aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Winamp')
-rw-r--r--Src/Winamp/ABOUT.cpp1531
-rw-r--r--Src/Winamp/ASXv2.cpp45
-rw-r--r--Src/Winamp/AccessibilityConfigGroup.cpp21
-rw-r--r--Src/Winamp/AccessibilityConfigGroup.h24
-rw-r--r--Src/Winamp/AdData.cpp13
-rw-r--r--Src/Winamp/AdData.h17
-rw-r--r--Src/Winamp/AlbumArtRetrieval.cpp693
-rw-r--r--Src/Winamp/AppRefCount.cpp52
-rw-r--r--Src/Winamp/AppRefCount.h35
-rw-r--r--Src/Winamp/ApplicationCOM.cpp321
-rw-r--r--Src/Winamp/ApplicationCOM.h23
-rw-r--r--Src/Winamp/BookmarksCOM.cpp134
-rw-r--r--Src/Winamp/BookmarksCOM.h21
-rw-r--r--Src/Winamp/BoolAttribute.cpp87
-rw-r--r--Src/Winamp/Browser.cpp368
-rw-r--r--Src/Winamp/Browser.h42
-rw-r--r--Src/Winamp/BrowserCOM.cpp101
-rw-r--r--Src/Winamp/BrowserCOM.h21
-rw-r--r--Src/Winamp/BurnManager.cpp67
-rw-r--r--Src/Winamp/BurnManager.h6
-rw-r--r--Src/Winamp/CommonReader.h10
-rw-r--r--Src/Winamp/Config.cpp1251
-rw-r--r--Src/Winamp/CurrentSongCOM.cpp317
-rw-r--r--Src/Winamp/CurrentSongCOM.h31
-rw-r--r--Src/Winamp/DOCK.cpp233
-rw-r--r--Src/Winamp/DSP.H80
-rw-r--r--Src/Winamp/DSP.cpp85
-rw-r--r--Src/Winamp/DataStoreCOM.cpp130
-rw-r--r--Src/Winamp/DataStoreCOM.h20
-rw-r--r--Src/Winamp/Dde.cpp327
-rw-r--r--Src/Winamp/DecodeFile.cpp202
-rw-r--r--Src/Winamp/DecodeFile.h21
-rw-r--r--Src/Winamp/DeveloperConfigGroup.cpp57
-rw-r--r--Src/Winamp/DeveloperConfigGroup.h22
-rw-r--r--Src/Winamp/EQConfigGroup.cpp33
-rw-r--r--Src/Winamp/EQConfigGroup.h24
-rw-r--r--Src/Winamp/Eq.cpp1025
-rw-r--r--Src/Winamp/Equi.cpp421
-rw-r--r--Src/Winamp/ExplorerFindFile.cpp163
-rw-r--r--Src/Winamp/ExplorerFindFile.h27
-rw-r--r--Src/Winamp/ExtendedInfo.cpp363
-rw-r--r--Src/Winamp/ExtendedReader.cpp87
-rw-r--r--Src/Winamp/ExtendedReader.h37
-rw-r--r--Src/Winamp/ExternalCOM.cpp520
-rw-r--r--Src/Winamp/ExternalCOM.h89
-rw-r--r--Src/Winamp/FFT.H10
-rw-r--r--Src/Winamp/FFT.cpp30
-rw-r--r--Src/Winamp/FRONTEND.H449
-rw-r--r--Src/Winamp/FeedBase.cpp62
-rw-r--r--Src/Winamp/FeedBase.h33
-rw-r--r--Src/Winamp/FileInfo.cpp2534
-rw-r--r--Src/Winamp/FloatAttribute.cpp30
-rw-r--r--Src/Winamp/GEN.H86
-rw-r--r--Src/Winamp/GammaFilter.cpp226
-rw-r--r--Src/Winamp/GammaFilter.h30
-rw-r--r--Src/Winamp/GammaManagerAPI.cpp361
-rw-r--r--Src/Winamp/GammaManagerAPI.h145
-rw-r--r--Src/Winamp/HTML.cpp139
-rw-r--r--Src/Winamp/HTTPRetrieveFile.cpp305
-rw-r--r--Src/Winamp/Http.cpp795
-rw-r--r--Src/Winamp/IN2.H191
-rw-r--r--Src/Winamp/IVideoD3DOSD.cpp966
-rw-r--r--Src/Winamp/IVideoD3DOSD.h158
-rw-r--r--Src/Winamp/IWasabiDispatchable.h13
-rw-r--r--Src/Winamp/In.cpp1293
-rw-r--r--Src/Winamp/InW.cpp52
-rw-r--r--Src/Winamp/InflateObject.cpp72
-rw-r--r--Src/Winamp/InflateObject.h28
-rw-r--r--Src/Winamp/IntAttribute.cpp24
-rw-r--r--Src/Winamp/InternetConfigGroup.cpp56
-rw-r--r--Src/Winamp/InternetConfigGroup.h22
-rw-r--r--Src/Winamp/JSAPI.h36
-rw-r--r--Src/Winamp/JSAPI2_Application.cpp197
-rw-r--r--Src/Winamp/JSAPI2_Application.h32
-rw-r--r--Src/Winamp/JSAPI2_AsyncDownloader.cpp732
-rw-r--r--Src/Winamp/JSAPI2_AsyncDownloader.h47
-rw-r--r--Src/Winamp/JSAPI2_Bookmarks.cpp122
-rw-r--r--Src/Winamp/JSAPI2_Bookmarks.h27
-rw-r--r--Src/Winamp/JSAPI2_CallbackManager.cpp567
-rw-r--r--Src/Winamp/JSAPI2_CallbackManager.h93
-rw-r--r--Src/Winamp/JSAPI2_Creator.cpp240
-rw-r--r--Src/Winamp/JSAPI2_Creator.h31
-rw-r--r--Src/Winamp/JSAPI2_Downloader.h26
-rw-r--r--Src/Winamp/JSAPI2_DownloaderAPI.cpp159
-rw-r--r--Src/Winamp/JSAPI2_ExternalObject.cpp307
-rw-r--r--Src/Winamp/JSAPI2_ExternalObject.h63
-rw-r--r--Src/Winamp/JSAPI2_MediaCore.cpp285
-rw-r--r--Src/Winamp/JSAPI2_MediaCore.h48
-rw-r--r--Src/Winamp/JSAPI2_PlayerAPI.cpp384
-rw-r--r--Src/Winamp/JSAPI2_PlayerAPI.h37
-rw-r--r--Src/Winamp/JSAPI2_Security.cpp255
-rw-r--r--Src/Winamp/JSAPI2_Security.h43
-rw-r--r--Src/Winamp/JSAPI2_SecurityAPI.cpp132
-rw-r--r--Src/Winamp/JSAPI2_SecurityAPI.h28
-rw-r--r--Src/Winamp/JSAPI2_SecurityPrompt.cpp718
-rw-r--r--Src/Winamp/JSAPI2_SkinAPI.cpp217
-rw-r--r--Src/Winamp/JSAPI2_SkinAPI.h35
-rw-r--r--Src/Winamp/JSAPI2_TransportAPI.cpp532
-rw-r--r--Src/Winamp/JSAPI2_TransportAPI.h57
-rw-r--r--Src/Winamp/JSAPI2_api_security.h117
-rw-r--r--Src/Winamp/JSAPI2_svc_apicreator.h51
-rw-r--r--Src/Winamp/JSAPI_CallbackParameters.cpp384
-rw-r--r--Src/Winamp/JSAPI_CallbackParameters.h87
-rw-r--r--Src/Winamp/JSAPI_DispatchTable.cpp22
-rw-r--r--Src/Winamp/JSAPI_DispatchTable.h17
-rw-r--r--Src/Winamp/JSAPI_Info.cpp2
-rw-r--r--Src/Winamp/JSAPI_Info.h101
-rw-r--r--Src/Winamp/JSAPI_ObjectArray.cpp257
-rw-r--r--Src/Winamp/JSAPI_ObjectArray.h43
-rw-r--r--Src/Winamp/Jump.cpp315
-rw-r--r--Src/Winamp/LazyServiceFactory.cpp128
-rw-r--r--Src/Winamp/LazyServiceFactory.h30
-rw-r--r--Src/Winamp/M3u.cpp73
-rw-r--r--Src/Winamp/Main.h1179
-rw-r--r--Src/Winamp/MediaCoreCOM.cpp398
-rw-r--r--Src/Winamp/MediaCoreCOM.h34
-rw-r--r--Src/Winamp/MemoryManager.cpp69
-rw-r--r--Src/Winamp/MemoryManager.h23
-rw-r--r--Src/Winamp/MergePlaylist.cpp247
-rw-r--r--Src/Winamp/MergePlaylist.h70
-rw-r--r--Src/Winamp/Metadata.cpp117
-rw-r--r--Src/Winamp/Metadata.h33
-rw-r--r--Src/Winamp/MoreItems.cpp134
-rw-r--r--Src/Winamp/MoreItems.h27
-rw-r--r--Src/Winamp/OUT.H132
-rw-r--r--Src/Winamp/OpenFileDialog.cpp467
-rw-r--r--Src/Winamp/Options.cpp611
-rw-r--r--Src/Winamp/Options.h105
-rw-r--r--Src/Winamp/Out.cpp119
-rw-r--r--Src/Winamp/OutputPluginAudioStream.cpp270
-rw-r--r--Src/Winamp/OutputPluginAudioStream.h24
-rw-r--r--Src/Winamp/PaletteManager.cpp458
-rw-r--r--Src/Winamp/PaletteManager.h100
-rw-r--r--Src/Winamp/ParamList.cpp124
-rw-r--r--Src/Winamp/ParamList.h42
-rw-r--r--Src/Winamp/PathsINI.cpp64
-rw-r--r--Src/Winamp/Peui.cpp791
-rw-r--r--Src/Winamp/Play.cpp322
-rw-r--r--Src/Winamp/PlayList.cpp2126
-rw-r--r--Src/Winamp/PlayQueue.cpp108
-rw-r--r--Src/Winamp/PlaybackConfigGroup.cpp48
-rw-r--r--Src/Winamp/PlaybackConfigGroup.h24
-rw-r--r--Src/Winamp/Playlist.h12
-rw-r--r--Src/Winamp/Pledit.cpp1723
-rw-r--r--Src/Winamp/Pls.cpp170
-rw-r--r--Src/Winamp/Resampler.cpp172
-rw-r--r--Src/Winamp/Resampler.h23
-rw-r--r--Src/Winamp/ResamplingReader.cpp89
-rw-r--r--Src/Winamp/ResamplingReader.h38
-rw-r--r--Src/Winamp/SA.cpp314
-rw-r--r--Src/Winamp/SABuffer.cpp139
-rw-r--r--Src/Winamp/SABuffer.h24
-rw-r--r--Src/Winamp/SHELL.CPP85
-rw-r--r--Src/Winamp/SPLASH.cpp56
-rw-r--r--Src/Winamp/SYSTRAY.cpp124
-rw-r--r--Src/Winamp/SecurityCOM.cpp100
-rw-r--r--Src/Winamp/SecurityCOM.h22
-rw-r--r--Src/Winamp/ServiceFactory.cpp25
-rw-r--r--Src/Winamp/ServiceManager.cpp285
-rw-r--r--Src/Winamp/ServiceManager.h47
-rw-r--r--Src/Winamp/Set.cpp1287
-rw-r--r--Src/Winamp/Singleton.h138
-rw-r--r--Src/Winamp/SkinBitmapElement.cpp28
-rw-r--r--Src/Winamp/SkinBitmapElement.h85
-rw-r--r--Src/Winamp/SkinCOM.cpp323
-rw-r--r--Src/Winamp/SkinCOM.h28
-rw-r--r--Src/Winamp/SkinColorElement.cpp20
-rw-r--r--Src/Winamp/SkinColorElement.h65
-rw-r--r--Src/Winamp/SkinCursorElement.cpp104
-rw-r--r--Src/Winamp/SkinCursorElement.h65
-rw-r--r--Src/Winamp/SkinElementAlias.cpp8
-rw-r--r--Src/Winamp/SkinElementAlias.h65
-rw-r--r--Src/Winamp/SkinUtils.cpp32
-rw-r--r--Src/Winamp/Skins.cpp943
-rw-r--r--Src/Winamp/SysCallbacks.cpp201
-rw-r--r--Src/Winamp/SysCallbacks.h35
-rw-r--r--Src/Winamp/TIMING.H24
-rw-r--r--Src/Winamp/TIMING.cpp77
-rw-r--r--Src/Winamp/TagProvider.cpp47
-rw-r--r--Src/Winamp/TagProvider.h28
-rw-r--r--Src/Winamp/TempFileCOM.cpp126
-rw-r--r--Src/Winamp/TempFileCOM.h21
-rw-r--r--Src/Winamp/Ui.cpp1290
-rw-r--r--Src/Winamp/UnsignedAttribute.cpp23
-rw-r--r--Src/Winamp/UpdateWindow.cpp214
-rw-r--r--Src/Winamp/VIS.H96
-rw-r--r--Src/Winamp/VIS.cpp839
-rw-r--r--Src/Winamp/VersionCheck.cpp313
-rw-r--r--Src/Winamp/VideoAspectAdjuster.h12
-rw-r--r--Src/Winamp/VideoConfigGroup.cpp41
-rw-r--r--Src/Winamp/VideoConfigGroup.h23
-rw-r--r--Src/Winamp/VideoFeedFactory.h35
-rw-r--r--Src/Winamp/VideoOSD.cpp537
-rw-r--r--Src/Winamp/VideoOSD.h53
-rw-r--r--Src/Winamp/VideoOutput.cpp1040
-rw-r--r--Src/Winamp/VideoOutput.h97
-rw-r--r--Src/Winamp/VideoOutputChild.cpp2
-rw-r--r--Src/Winamp/VideoOutputChild.h35
-rw-r--r--Src/Winamp/VideoOutputChildDDraw.cpp66
-rw-r--r--Src/Winamp/VideoOutputChildDDraw.h22
-rw-r--r--Src/Winamp/VideoPreferences.cpp2
-rw-r--r--Src/Winamp/W5S.cpp226
-rw-r--r--Src/Winamp/W5S.h2
-rw-r--r--Src/Winamp/WADrawDC.cpp33
-rw-r--r--Src/Winamp/WADrawDC.h14
-rw-r--r--Src/Winamp/WINAMP.sln122
-rw-r--r--Src/Winamp/Wasabi.cpp292
-rw-r--r--Src/Winamp/Wasabi.h7
-rw-r--r--Src/Winamp/WavEncoder.cpp375
-rw-r--r--Src/Winamp/WavEncoder.h48
-rw-r--r--Src/Winamp/Winamp.rc2807
-rw-r--r--Src/Winamp/WinampAttributes.cpp66
-rw-r--r--Src/Winamp/WinampAttributes.h49
-rw-r--r--Src/Winamp/WinampPlaylist.cpp228
-rw-r--r--Src/Winamp/WinampPlaylist.h43
-rw-r--r--Src/Winamp/XMLString.cpp51
-rw-r--r--Src/Winamp/XMLString.h29
-rw-r--r--Src/Winamp/api.h72
-rw-r--r--Src/Winamp/api_audiostream.h7
-rw-r--r--Src/Winamp/api_decodefile.h2
-rw-r--r--Src/Winamp/api_inflate.h96
-rw-r--r--Src/Winamp/api_random.h1
-rw-r--r--Src/Winamp/api_stats.h74
-rw-r--r--Src/Winamp/api_urlmanager.h27
-rw-r--r--Src/Winamp/api_videopreferences.cpp2
-rw-r--r--Src/Winamp/api_videopreferences.h28
-rw-r--r--Src/Winamp/api_winamp.h57
-rw-r--r--Src/Winamp/application.cpp941
-rw-r--r--Src/Winamp/application.h127
-rw-r--r--Src/Winamp/asx.cpp63
-rw-r--r--Src/Winamp/asx.h4
-rw-r--r--Src/Winamp/attributes.h94
-rw-r--r--Src/Winamp/b4s.cpp8
-rw-r--r--Src/Winamp/b4s.h6
-rw-r--r--Src/Winamp/benskiQ/Biquad.cpp204
-rw-r--r--Src/Winamp/benskiQ/Biquad.h29
-rw-r--r--Src/Winamp/benskiQ/EqBand.cpp81
-rw-r--r--Src/Winamp/benskiQ/EqBand.h23
-rw-r--r--Src/Winamp/benskiQ/benskiQ.cpp231
-rw-r--r--Src/Winamp/bm.cpp129
-rw-r--r--Src/Winamp/bookmark.cpp25
-rw-r--r--Src/Winamp/buildType.h13
-rw-r--r--Src/Winamp/burn.cpp220
-rw-r--r--Src/Winamp/burn.h16
-rw-r--r--Src/Winamp/classic_vis.cpp342
-rw-r--r--Src/Winamp/cmdline.cpp1120
-rw-r--r--Src/Winamp/commandLink.cpp698
-rw-r--r--Src/Winamp/commandLink.h106
-rw-r--r--Src/Winamp/compatibility.manifest20
-rw-r--r--Src/Winamp/config.h188
-rw-r--r--Src/Winamp/contnr.h123
-rw-r--r--Src/Winamp/conversions.cpp114
-rw-r--r--Src/Winamp/convert.cpp781
-rw-r--r--Src/Winamp/creddlg.c503
-rw-r--r--Src/Winamp/creddlg.h78
-rw-r--r--Src/Winamp/credits.cpp350
-rw-r--r--Src/Winamp/creditsrend.c935
-rw-r--r--Src/Winamp/demo.mp3bin0 -> 37251 bytes
-rw-r--r--Src/Winamp/directdraw.h6
-rw-r--r--Src/Winamp/dispatchCallback.cpp525
-rw-r--r--Src/Winamp/dispatchCallback.h150
-rw-r--r--Src/Winamp/dpi.cpp106
-rw-r--r--Src/Winamp/dpi.h46
-rw-r--r--Src/Winamp/draw.cpp699
-rw-r--r--Src/Winamp/draw.h60
-rw-r--r--Src/Winamp/draw_embed.cpp243
-rw-r--r--Src/Winamp/draw_eq.cpp329
-rw-r--r--Src/Winamp/draw_main.cpp696
-rw-r--r--Src/Winamp/draw_mb.cpp10
-rw-r--r--Src/Winamp/draw_pe.cpp822
-rw-r--r--Src/Winamp/draw_sa.cpp517
-rw-r--r--Src/Winamp/draw_vw.cpp231
-rw-r--r--Src/Winamp/dwm.cpp386
-rw-r--r--Src/Winamp/embwnd.cpp937
-rw-r--r--Src/Winamp/eq10dsp.cpp277
-rw-r--r--Src/Winamp/eq10dsp.h175
-rw-r--r--Src/Winamp/feeds.cpp60
-rw-r--r--Src/Winamp/feeds.h24
-rw-r--r--Src/Winamp/fullscreen.cpp159
-rw-r--r--Src/Winamp/gen.cpp213
-rw-r--r--Src/Winamp/handler.cpp90
-rw-r--r--Src/Winamp/handler.h22
-rw-r--r--Src/Winamp/install.cpp184
-rw-r--r--Src/Winamp/ipc.cpp1633
-rw-r--r--Src/Winamp/ipc_pe.h171
-rw-r--r--Src/Winamp/jnetcom.cpp528
-rw-r--r--Src/Winamp/jnetcom.h77
-rw-r--r--Src/Winamp/lang.cpp1136
-rw-r--r--Src/Winamp/language.h54
-rw-r--r--Src/Winamp/linklist.cpp94
-rw-r--r--Src/Winamp/main.cpp1892
-rw-r--r--Src/Winamp/main.hpp4
-rw-r--r--Src/Winamp/main_buttons.cpp241
-rw-r--r--Src/Winamp/main_close.cpp111
-rw-r--r--Src/Winamp/main_command.cpp916
-rw-r--r--Src/Winamp/main_display.cpp122
-rw-r--r--Src/Winamp/main_init.cpp322
-rw-r--r--Src/Winamp/main_mouse.cpp280
-rw-r--r--Src/Winamp/main_nonclient.cpp40
-rw-r--r--Src/Winamp/main_timer.cpp133
-rw-r--r--Src/Winamp/main_wndproc.cpp253
-rw-r--r--Src/Winamp/manifest.xml54
-rw-r--r--Src/Winamp/manifest64.xml53
-rw-r--r--Src/Winamp/manifest_debug.xml8
-rw-r--r--Src/Winamp/manifest_x64.rc63
-rw-r--r--Src/Winamp/manifest_x86.rc70
-rw-r--r--Src/Winamp/mb.cpp1
-rw-r--r--Src/Winamp/mbui.cpp1
-rw-r--r--Src/Winamp/menuv5.cpp653
-rw-r--r--Src/Winamp/menuv5.h24
-rw-r--r--Src/Winamp/metrics.cpp228
-rw-r--r--Src/Winamp/ole.cpp431
-rw-r--r--Src/Winamp/options_bookmarks.cpp386
-rw-r--r--Src/Winamp/options_classic.cpp291
-rw-r--r--Src/Winamp/options_dsp.cpp494
-rw-r--r--Src/Winamp/options_filetypes.cpp460
-rw-r--r--Src/Winamp/options_gen.cpp308
-rw-r--r--Src/Winamp/options_general.cpp283
-rw-r--r--Src/Winamp/options_in.cpp308
-rw-r--r--Src/Winamp/options_lang.cpp703
-rw-r--r--Src/Winamp/options_output.cpp328
-rw-r--r--Src/Winamp/options_playback.cpp325
-rw-r--r--Src/Winamp/options_playlist.cpp268
-rw-r--r--Src/Winamp/options_plugins.cpp203
-rw-r--r--Src/Winamp/options_skin.cpp683
-rw-r--r--Src/Winamp/options_stationinfo.cpp46
-rw-r--r--Src/Winamp/options_title.cpp157
-rw-r--r--Src/Winamp/options_video.cpp195
-rw-r--r--Src/Winamp/options_vis.cpp434
-rw-r--r--Src/Winamp/paths.cpp164
-rw-r--r--Src/Winamp/plush/CAM.C52
-rw-r--r--Src/Winamp/plush/CLIP.C255
-rw-r--r--Src/Winamp/plush/LIGHT.C46
-rw-r--r--Src/Winamp/plush/MAKE.C480
-rw-r--r--Src/Winamp/plush/MAT.C453
-rw-r--r--Src/Winamp/plush/MATH.C67
-rw-r--r--Src/Winamp/plush/OBJ.C179
-rw-r--r--Src/Winamp/plush/PF_PTEX.C459
-rw-r--r--Src/Winamp/plush/PF_SOLID.C271
-rw-r--r--Src/Winamp/plush/PF_TEX.C584
-rw-r--r--Src/Winamp/plush/PF_TRANS.C263
-rw-r--r--Src/Winamp/plush/PLUSH.C286
-rw-r--r--Src/Winamp/plush/PLUSH.H720
-rw-r--r--Src/Winamp/plush/PL_CONF.H45
-rw-r--r--Src/Winamp/plush/PL_DEFS.H62
-rw-r--r--Src/Winamp/plush/PL_TYPES.H162
-rw-r--r--Src/Winamp/plush/PUTFACE.H54
-rw-r--r--Src/Winamp/plush/READ_3DS.C244
-rw-r--r--Src/Winamp/plush/READ_COB.C182
-rw-r--r--Src/Winamp/plush/READ_JAW.C69
-rw-r--r--Src/Winamp/plush/READ_PCX.C162
-rw-r--r--Src/Winamp/plush/RENDER.C301
-rw-r--r--Src/Winamp/plush/SPLINE.C49
-rw-r--r--Src/Winamp/plush/TEXT.C123
-rw-r--r--Src/Winamp/precomp.cpp2
-rw-r--r--Src/Winamp/precomp.h14
-rw-r--r--Src/Winamp/rand.cpp226
-rw-r--r--Src/Winamp/random.h30
-rw-r--r--Src/Winamp/readme.txt35
-rw-r--r--Src/Winamp/registry.cpp251
-rw-r--r--Src/Winamp/resource.h1526
-rw-r--r--Src/Winamp/resource.hm4
-rw-r--r--Src/Winamp/resource/.gitattributes1
-rw-r--r--Src/Winamp/resource/BALANCE.BMPbin0 -> 16336 bytes
-rw-r--r--Src/Winamp/resource/CBUTTONS.BMPbin0 -> 3720 bytes
-rw-r--r--Src/Winamp/resource/CUR00001.CURbin0 -> 766 bytes
-rw-r--r--Src/Winamp/resource/DANGER.CURbin0 -> 766 bytes
-rw-r--r--Src/Winamp/resource/DANGER1.CURbin0 -> 766 bytes
-rw-r--r--Src/Winamp/resource/Eqmain.bmpbin0 -> 346554 bytes
-rw-r--r--Src/Winamp/resource/Eqmain_ISO.bmpbin0 -> 346554 bytes
-rw-r--r--Src/Winamp/resource/ICON1.ICObin0 -> 4710 bytes
-rw-r--r--Src/Winamp/resource/ICON10.ICObin0 -> 2238 bytes
-rw-r--r--Src/Winamp/resource/ICON11.ICObin0 -> 2998 bytes
-rw-r--r--Src/Winamp/resource/ICON12.ICObin0 -> 2238 bytes
-rw-r--r--Src/Winamp/resource/ICON13.ICObin0 -> 2998 bytes
-rw-r--r--Src/Winamp/resource/ICON2.ICObin0 -> 25214 bytes
-rw-r--r--Src/Winamp/resource/ICON3.ICObin0 -> 4710 bytes
-rw-r--r--Src/Winamp/resource/ICON6.ICObin0 -> 3638 bytes
-rw-r--r--Src/Winamp/resource/ICON7.ICObin0 -> 3774 bytes
-rw-r--r--Src/Winamp/resource/ICON8.ICObin0 -> 4710 bytes
-rw-r--r--Src/Winamp/resource/ICON9.ICObin0 -> 2238 bytes
-rw-r--r--Src/Winamp/resource/ICONS.GIFbin0 -> 5936 bytes
-rw-r--r--Src/Winamp/resource/LRSCROLL.CURbin0 -> 766 bytes
-rw-r--r--Src/Winamp/resource/MAIN.BMPbin0 -> 26680 bytes
-rw-r--r--Src/Winamp/resource/MONOSTER.BMPbin0 -> 2564 bytes
-rw-r--r--Src/Winamp/resource/MOVE.CURbin0 -> 766 bytes
-rw-r--r--Src/Winamp/resource/Mb.bmpbin0 -> 29160 bytes
-rw-r--r--Src/Winamp/resource/OSD-Sprite-Controls.pngbin0 -> 15302 bytes
-rw-r--r--Src/Winamp/resource/PLAYPAUS.BMPbin0 -> 376 bytes
-rw-r--r--Src/Winamp/resource/POSBAR.BMPbin0 -> 3184 bytes
-rw-r--r--Src/Winamp/resource/Pledit.bmpbin0 -> 53160 bytes
-rw-r--r--Src/Winamp/resource/RESIZE.CURbin0 -> 766 bytes
-rw-r--r--Src/Winamp/resource/SHUFREP.BMPbin0 -> 4444 bytes
-rw-r--r--Src/Winamp/resource/SPEC.BMPbin0 -> 1690 bytes
-rw-r--r--Src/Winamp/resource/TBICON1.icobin0 -> 1150 bytes
-rw-r--r--Src/Winamp/resource/TBICON2.icobin0 -> 1150 bytes
-rw-r--r--Src/Winamp/resource/TBICON3.icobin0 -> 1150 bytes
-rw-r--r--Src/Winamp/resource/TBICON4.icobin0 -> 1150 bytes
-rw-r--r--Src/Winamp/resource/TBICON5.icobin0 -> 1150 bytes
-rw-r--r--Src/Winamp/resource/TIPS.TXT140
-rw-r--r--Src/Winamp/resource/WinampIcon.icobin0 -> 61226 bytes
-rw-r--r--Src/Winamp/resource/ZIPICON.ICObin0 -> 766 bytes
-rw-r--r--Src/Winamp/resource/atf.htm1097
-rw-r--r--Src/Winamp/resource/bitmap1.bmpbin0 -> 372 bytes
-rw-r--r--Src/Winamp/resource/bitmap2.bmpbin0 -> 372 bytes
-rw-r--r--Src/Winamp/resource/cmdline.txt79
-rw-r--r--Src/Winamp/resource/djegg.bmpbin0 -> 4474 bytes
-rw-r--r--Src/Winamp/resource/eq_ex.bmpbin0 -> 23652 bytes
-rw-r--r--Src/Winamp/resource/gen.bmpbin0 -> 63710 bytes
-rw-r--r--Src/Winamp/resource/genex.bmpbin0 -> 29456 bytes
-rw-r--r--Src/Winamp/resource/icon5.icobin0 -> 4710 bytes
-rw-r--r--Src/Winamp/resource/numbers.bmpbin0 -> 2030 bytes
-rw-r--r--Src/Winamp/resource/splash2.bmpbin0 -> 76678 bytes
-rw-r--r--Src/Winamp/resource/team.bmpbin0 -> 14390 bytes
-rw-r--r--Src/Winamp/resource/text.bmpbin0 -> 6820 bytes
-rw-r--r--Src/Winamp/resource/titlebar-font.pngbin0 -> 6867 bytes
-rw-r--r--Src/Winamp/resource/titlebar.bmpbin0 -> 31008 bytes
-rw-r--r--Src/Winamp/resource/uninstallwa.icobin0 -> 1078 bytes
-rw-r--r--Src/Winamp/resource/video.bmpbin0 -> 29164 bytes
-rw-r--r--Src/Winamp/resource/video_logo.bmpbin0 -> 7480 bytes
-rw-r--r--Src/Winamp/resource/volume.bmpbin0 -> 30524 bytes
-rw-r--r--Src/Winamp/setup/checkbox.bmpbin0 -> 886 bytes
-rw-r--r--Src/Winamp/setup/headerstrip.bmpbin0 -> 206 bytes
-rw-r--r--Src/Winamp/setup/httpgrab.cpp183
-rw-r--r--Src/Winamp/setup/httpgrab.h13
-rw-r--r--Src/Winamp/setup/ifc_setupjob.h42
-rw-r--r--Src/Winamp/setup/ifc_setuppage.h62
-rw-r--r--Src/Winamp/setup/langutil.cpp43
-rw-r--r--Src/Winamp/setup/langutil.h18
-rw-r--r--Src/Winamp/setup/loadimage.cpp235
-rw-r--r--Src/Winamp/setup/loadimage.h12
-rw-r--r--Src/Winamp/setup/navitemstrip.bmpbin0 -> 182 bytes
-rw-r--r--Src/Winamp/setup/navstrip.bmpbin0 -> 1278 bytes
-rw-r--r--Src/Winamp/setup/png.rc72
-rw-r--r--Src/Winamp/setup/postsetup.cpp68
-rw-r--r--Src/Winamp/setup/postsetup.h10
-rw-r--r--Src/Winamp/setup/preview_classic.pngbin0 -> 16177 bytes
-rw-r--r--Src/Winamp/setup/preview_no.pngbin0 -> 3941 bytes
-rw-r--r--Src/Winamp/setup/resource.h16
-rw-r--r--Src/Winamp/setup/setup.cpp1131
-rw-r--r--Src/Winamp/setup/setup.h66
-rw-r--r--Src/Winamp/setup/setup.rc446
-rw-r--r--Src/Winamp/setup/setup_api.h24
-rw-r--r--Src/Winamp/setup/setup_resource.h139
-rw-r--r--Src/Winamp/setup/setupcommon.h31
-rw-r--r--Src/Winamp/setup/setupfactory.cpp249
-rw-r--r--Src/Winamp/setup/setupfactory.h19
-rw-r--r--Src/Winamp/setup/sjob_register.cpp84
-rw-r--r--Src/Winamp/setup/sjob_register.h28
-rw-r--r--Src/Winamp/setup/skininfo.cpp330
-rw-r--r--Src/Winamp/setup/skininfo.h38
-rw-r--r--Src/Winamp/setup/smokingllama.pngbin0 -> 1581 bytes
-rw-r--r--Src/Winamp/setup/spage_assoc.cpp1069
-rw-r--r--Src/Winamp/setup/spage_assoc.h57
-rw-r--r--Src/Winamp/setup/spage_connect.cpp313
-rw-r--r--Src/Winamp/setup/spage_connect.h45
-rw-r--r--Src/Winamp/setup/spage_feedback.cpp392
-rw-r--r--Src/Winamp/setup/spage_feedback.h45
-rw-r--r--Src/Winamp/setup/spage_lang.cpp293
-rw-r--r--Src/Winamp/setup/spage_lang.h42
-rw-r--r--Src/Winamp/setup/spage_skin.cpp646
-rw-r--r--Src/Winamp/setup/spage_skin.h52
-rw-r--r--Src/Winamp/setup/svc_setup.h123
-rw-r--r--Src/Winamp/setup/wa_classic_preview.pngbin0 -> 16177 bytes
-rw-r--r--Src/Winamp/skinWindow.cpp1311
-rw-r--r--Src/Winamp/skinWindow.h12
-rw-r--r--Src/Winamp/skinWindowIPC.h23
-rw-r--r--Src/Winamp/stats.cpp185
-rw-r--r--Src/Winamp/stats.h29
-rw-r--r--Src/Winamp/strutil.cpp486
-rw-r--r--Src/Winamp/strutil.h51
-rw-r--r--Src/Winamp/tagz.cpp343
-rw-r--r--Src/Winamp/tagz.h15
-rw-r--r--Src/Winamp/updateService.cpp232
-rw-r--r--Src/Winamp/updateService.h48
-rw-r--r--Src/Winamp/updateServicePopup.cpp112
-rw-r--r--Src/Winamp/urlmanager.cpp36
-rw-r--r--Src/Winamp/urlmanager.h28
-rw-r--r--Src/Winamp/util.cpp660
-rw-r--r--Src/Winamp/verchk.cpp285
-rw-r--r--Src/Winamp/version.rc242
-rw-r--r--Src/Winamp/vid_d3d.cpp740
-rw-r--r--Src/Winamp/vid_d3d.h51
-rw-r--r--Src/Winamp/vid_ddraw.cpp980
-rw-r--r--Src/Winamp/vid_ddraw.h56
-rw-r--r--Src/Winamp/vid_gdi+.cpp359
-rw-r--r--Src/Winamp/vid_gdi+.h44
-rw-r--r--Src/Winamp/vid_none.cpp4
-rw-r--r--Src/Winamp/vid_none.h21
-rw-r--r--Src/Winamp/vid_overlay.cpp843
-rw-r--r--Src/Winamp/vid_overlay.h56
-rw-r--r--Src/Winamp/vid_subs.cpp222
-rw-r--r--Src/Winamp/vid_subs.h75
-rw-r--r--Src/Winamp/video.cpp858
-rw-r--r--Src/Winamp/video.h28
-rw-r--r--Src/Winamp/video_ipc.cpp111
-rw-r--r--Src/Winamp/videoui.cpp203
-rw-r--r--Src/Winamp/vu.cpp238
-rw-r--r--Src/Winamp/wa_dlg.h458
-rw-r--r--Src/Winamp/wa_ipc.h3172
-rw-r--r--Src/Winamp/wasabicfg.h3
-rw-r--r--Src/Winamp/whatsnew-5.0.txt38
-rw-r--r--Src/Winamp/whatsnew.txt2002
-rw-r--r--Src/Winamp/winamp.exe.manifest20
-rw-r--r--Src/Winamp/winampApi.cpp83
-rw-r--r--Src/Winamp/winampApi.h42
-rw-r--r--Src/Winamp/winampv6.vcxproj1052
-rw-r--r--Src/Winamp/winampv6.vcxproj.filters1497
-rw-r--r--Src/Winamp/wintheme.cpp93
-rw-r--r--Src/Winamp/wintheme.h59
-rw-r--r--Src/Winamp/wpl.cpp8
-rw-r--r--Src/Winamp/wpl.h4
-rw-r--r--Src/Winamp/wpz.cpp10
513 files changed, 112251 insertions, 0 deletions
diff --git a/Src/Winamp/ABOUT.cpp b/Src/Winamp/ABOUT.cpp
new file mode 100644
index 00000000..9916fafc
--- /dev/null
+++ b/Src/Winamp/ABOUT.cpp
@@ -0,0 +1,1531 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author:
+** Created:
+**/
+
+#include "Main.h"
+#include "language.h"
+#include <math.h>
+#include "../nu/threadname.h"
+#include "resource.h"
+#include <tataki/export.h>
+#include "api.h"
+#include "../nu/threadpool/TimerHandle.hpp"
+#include "../nu/AutoWide.h"
+
+int img_w[2] = {400, 100}, img_h[2] = {189, 34};
+int about_lastpage;
+HWND about_hwnd;
+#define M_PI 3.14159265358979323846
+
+static BOOL CALLBACK tipsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static BOOL CALLBACK whatsnewProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static BOOL CALLBACK about1Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static BOOL CALLBACK creditProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static BOOL CALLBACK translationProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static LRESULT WINAPI aboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+
+static unsigned const char sq_table[]=
+{0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, 64, 65,
+67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90, 91, 93, 94,
+96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113,
+114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153,
+154, 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164,
+165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175,
+176, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185,
+185, 186, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 193, 194,
+195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 203,
+204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, 212,
+212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220,
+221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228,
+229, 229, 230, 230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236,
+236, 237, 237, 238, 238, 239, 240, 240, 241, 241, 242, 242, 243, 243,
+244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250,
+251, 251, 252, 252, 253, 253, 254, 254, 255};
+
+static __inline unsigned long isqrt(unsigned long n)
+{
+ if (n >= 0x10000)
+ if (n >= 0x1000000)
+ if (n >= 0x10000000)
+ if (n >= 0x40000000) return(sq_table[n >> 24] << 8);
+ else return(sq_table[n >> 22] << 7);
+ else
+ if (n >= 0x4000000) return(sq_table[n >> 20] << 6);
+ else return(sq_table[n >> 18] << 5);
+ else
+ if (n >= 0x100000)
+ if (n >= 0x400000) return(sq_table[n >> 16] << 4);
+ else return(sq_table[n >> 14] << 3);
+ else
+ if (n >= 0x40000) return(sq_table[n >> 12] << 2);
+ else return(sq_table[n >> 10] << 1);
+ else
+ if (n >= 0x100)
+ if (n >= 0x1000)
+ if (n >= 0x4000) return(sq_table[n >> 8]);
+ else return(sq_table[n >> 6] >> 1);
+ else
+ if (n >= 0x400) return(sq_table[n >> 4] >> 2);
+ else return(sq_table[n >> 2] >> 3);
+ else
+ if (n >= 0x10)
+ if (n >= 0x40) return(sq_table[n] >> 4);
+ else return(sq_table[n << 2] << 5);
+ else
+ if (n >= 0x4) return(sq_table[n >> 4] << 6);
+ else return(sq_table[n >> 6] << 7);
+}
+
+void about_dialog(void)
+{
+ if (about_hwnd)
+ {
+ SetForegroundWindow(about_hwnd);
+ return;
+ }
+
+ about_hwnd=(HWND)LPCreateDialogW(IDD_NEWABOUT, hMainWindow, aboutProc);
+
+ // show about window and restore last position as applicable
+ POINT pt = {about_rect.left, about_rect.top};
+ if (!windowOffScreen(about_hwnd, pt))
+ SetWindowPos(about_hwnd, HWND_TOP, about_rect.left, about_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+ else
+ ShowWindow(about_hwnd, SW_SHOW);
+}
+
+static LRESULT WINAPI aboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static HWND cur_wnd;
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ int t=about_lastpage;
+ about_lastpage=-1;
+ // make sure not to show the localised page if not under a language pack
+ if (t==4 && config_langpack[0]) SendMessageW(hwndDlg, WM_COMMAND, IDC_BUTTON2, 0);
+ else if (t==3) SendMessageW(hwndDlg, WM_COMMAND, IDC_BUTTON6, 0);
+ else if (t==2) SendMessageW(hwndDlg, WM_COMMAND, IDC_BUTTON5, 0);
+ else if (t==1) SendMessageW(hwndDlg, WM_COMMAND, IDC_BUTTON4, 0);
+ else
+ {
+ if (t==4) t = 0;
+ SendMessageW(hwndDlg, WM_COMMAND, IDC_BUTTON3, 0);
+ }
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ case IDC_BUTTON3:
+ case IDC_BUTTON4:
+ case IDC_BUTTON5:
+ case IDC_BUTTON6:
+ case IDC_BUTTON2:
+ {
+ int id=-1;
+ int t = 0;
+ void *proc = 0;
+ if (LOWORD(wParam)==IDC_BUTTON3) t=0;
+ if (LOWORD(wParam)==IDC_BUTTON4) t=1;
+ if (LOWORD(wParam)==IDC_BUTTON5) t=2;
+ if (LOWORD(wParam)==IDC_BUTTON6) t=3;
+ if (LOWORD(wParam)==IDC_BUTTON2) t=4;
+ if (t == about_lastpage) return 0;
+ about_lastpage=t;
+ switch (t)
+ {
+ case 0: id=IDD_NEWABOUT1; proc=about1Proc; break;
+ case 1: id=IDD_NEWABOUT2; proc=creditProc; break;
+ case 2: id=IDD_NEWABOUT3; proc=tipsProc; break;
+ case 3: id=IDD_NEWABOUT4; proc=whatsnewProc; break;
+ case 4: id=IDD_ABOUT_TRANSLATION; proc=translationProc; break;
+ }
+
+ if (IsWindow(cur_wnd))
+ {
+ DestroyWindow(cur_wnd);
+ cur_wnd=0;
+ }
+
+ if (id != -1)
+ {
+ cur_wnd = CreateDialogW(language_pack_instance, MAKEINTRESOURCEW(id), hwndDlg, (DLGPROC)proc);
+ // handles cases where there's no localised info page in a language pack / under en-us
+ if(!IsWindow(cur_wnd)) cur_wnd = LPCreateDialogW(id, hwndDlg, (DLGPROC)proc);
+
+ {
+ RECT r;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RECT),&r);
+ ScreenToClient(hwndDlg,(LPPOINT)&r);
+ SetWindowPos(cur_wnd,0,r.left,r.top,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
+ }
+ ShowWindow(cur_wnd,SW_SHOWNA);
+ {
+ RECT r,r2;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON3),&r);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON6),&r2);
+ r.right=r2.right;
+ ScreenToClient(hwndDlg,(LPPOINT)&r);
+ ScreenToClient(hwndDlg,((LPPOINT)&r)+1);
+ InvalidateRect(hwndDlg,&r,FALSE);
+ }
+ }
+ }
+ return FALSE;
+ }
+ break;
+
+ case WM_DESTROY:
+ GetWindowRect(hwndDlg, &about_rect);
+ if (IsWindow(cur_wnd)) DestroyWindow(cur_wnd);
+ cur_wnd=0;
+ about_hwnd=NULL;
+ break;
+ }
+
+ if (uMsg == WM_DRAWITEM)
+ {
+ DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
+ if (di->CtlType == ODT_BUTTON)
+ {
+ wchar_t wt[123] = {0};
+ int sel=0;
+ RECT r;
+ GetDlgItemTextW(hwndDlg,wParam,wt,123);
+
+ if (di->CtlID==IDC_BUTTON3 && about_lastpage==0) sel=1;
+ else if (di->CtlID==IDC_BUTTON4 && about_lastpage==1) sel=1;
+ else if (di->CtlID==IDC_BUTTON5 && about_lastpage==2) sel=1;
+ else if (di->CtlID==IDC_BUTTON6 && about_lastpage==3) sel=1;
+ else if (di->CtlID==IDC_BUTTON2 && about_lastpage==4) sel=1;
+
+ if (di->CtlID != IDC_BUTTON6)
+ {
+ MoveToEx(di->hDC,di->rcItem.right-1,di->rcItem.top,NULL);
+ LineTo(di->hDC,di->rcItem.right-1,di->rcItem.bottom);
+ }
+
+ // draw text
+ if (!sel && (di->itemState & (ODS_SELECTED)))
+ SetTextColor(di->hDC,RGB(0,40,255));
+ r=di->rcItem;
+ DrawTextW(di->hDC,wt,-1,&r,DT_VCENTER|DT_SINGLELINE|DT_CENTER);
+ if (sel)
+ {
+ r=di->rcItem;
+ r.left+=2;
+ SetBkMode(di->hDC,TRANSPARENT);
+ DrawTextW(di->hDC,wt,-1,&r,DT_VCENTER|DT_SINGLELINE|DT_CENTER);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Window Proc for the 'keyboard shorcuts' tab of about screen */
+static BOOL CALLBACK tipsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static HGLOBAL hResource=0;
+ static DWORD hResourceSize=0;
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ char *b = NULL, *p = 0, *op = 0;
+ DWORD size = 0;
+ if (!hResource)
+ {
+ hResource = langManager->LoadResourceFromFileW(language_pack_instance, hMainInstance,TEXT("TEXT"), TEXT("TIPSTEXT"),&size);
+ hResourceSize = size;
+ }
+ p = (char*)hResource;
+ if (p && (op = strstr(p, "!!End"))) // if there's "!!End" in the resource, than copy everything before it
+ {
+ b = (char*)GlobalAlloc(GPTR, op-p+1);
+ memcpy(b, p, op-p);
+ b[op-p] = 0;
+ } else {
+ b = (char*)GlobalAlloc(GPTR, hResourceSize+1);
+ memcpy(b, p, hResourceSize);
+ b[hResourceSize] = 0;
+ }
+
+ SetDlgItemTextA(hwndDlg, IDC_TIPS, (b ? b : p)); // send it to the text control to display
+ if (b) GlobalFree(b);
+ }
+ break;
+
+ case WM_COMMAND:
+ if(LOWORD(wParam) == IDCANCEL)
+ {
+ DestroyWindow(about_hwnd);
+ }
+ break;
+ }
+
+ if (FALSE != IsDirectMouseWheelMessage(uMsg))
+ {
+ HWND textWindow;
+ RECT windowRect;
+ textWindow = GetDlgItem(hwndDlg, IDC_TIPS);
+ if (NULL != textWindow &&
+ FALSE != GetClientRect(textWindow, &windowRect))
+ {
+ POINT pt;
+ POINTSTOPOINT(pt, lParam);
+
+ MapWindowPoints(HWND_DESKTOP, textWindow, &pt, 1);
+ if (FALSE != PtInRect(&windowRect, pt))
+ {
+ SendMessageW(textWindow, WM_MOUSEWHEEL, wParam, lParam);
+ SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
+ }
+ return TRUE;
+ }
+ }
+ return 0;
+}
+
+WNDPROC whatedproc = 0;
+static LRESULT CALLBACK whatseditproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if(uMsg == WM_KEYDOWN)
+ {
+ if(wParam == 'F' && (GetAsyncKeyState(VK_CONTROL)&0x8000) && !(GetAsyncKeyState(VK_SHIFT)&0x8000))
+ {
+ if(IsWindowEnabled(GetDlgItem(GetParent(hwndDlg), IDC_ABOUT_SEARCH)))
+ {
+ SendMessageW(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(IDC_ABOUT_SEARCH,0), 0);
+ }
+ }
+ }
+ return CallWindowProcW(whatedproc,hwndDlg,uMsg,wParam,lParam);
+}
+
+#define WHATSNEW_BUFFER_SIZE 262144
+static wchar_t* ver_buf;
+
+void GetWhatsNewFromFile(FILE *fp)
+{
+ bool utf8=false, utf16=false;
+ unsigned char BOM[3] = {0, 0, 0};
+ if (fread(BOM, 3, 1, fp) == 1 && BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
+ utf8 = true;
+ else
+ {
+ fseek(fp, 0, SEEK_SET);
+ if (fread(BOM, 2, 1, fp) == 1 && BOM[0] == 0xFF && BOM[1] == 0xFE)
+ utf16=true;
+ else
+ fseek(fp, 0, SEEK_SET);
+ }
+
+ if (utf16)
+ {
+ wchar_t buffer[WHATSNEW_BUFFER_SIZE]={0}, *p=buffer;
+ for (;;)
+ {
+ fgetws(p,1024,fp);
+ if (feof(fp)) break;
+ if (p[wcslen(p)-1]==L'\n')
+ p[wcslen(p)-1]=0;
+ StringCchCatW(p,WHATSNEW_BUFFER_SIZE,L"\r\n");
+ p=p+wcslen(p);
+ if (p-buffer > WHATSNEW_BUFFER_SIZE) break;
+ }
+
+ ver_buf = wcsdup(buffer);
+ }
+ else
+ {
+ char buffer[WHATSNEW_BUFFER_SIZE]={0},*p=buffer;
+ for (;;)
+ {
+ fgets(p,1024,fp);
+ if (feof(fp)) break;
+ if (p[lstrlenA(p)-1]=='\n')
+ p[lstrlenA(p)-1]=0;
+ StringCchCatA(p,WHATSNEW_BUFFER_SIZE,"\r\n");
+ p=p+lstrlenA(p);
+ if (p-buffer > WHATSNEW_BUFFER_SIZE) break;
+ }
+
+ if (utf8)
+ {
+ ver_buf = AutoWideDup(buffer, CP_UTF8);
+ }
+ else
+ {
+ ver_buf = AutoWideDup(buffer);
+ }
+ }
+}
+
+static std::map<int,wchar_t*> versions;
+/* Window Proc for the 'version history' tab of about screen */
+static BOOL CALLBACK whatsnewProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static UINT fm_msg;
+ static FINDREPLACEW find;
+ static wchar_t fromstring[256];
+ static HWND finder;
+
+ if(uMsg == fm_msg)
+ {
+ LPFINDREPLACEW lpFindReplace = (LPFINDREPLACEW) lParam;
+ if(lpFindReplace->Flags & FR_FINDNEXT)
+ {
+ int len = GetWindowTextLengthW(GetDlgItem(hwndDlg,IDC_TIPS))+1,
+ flen = lstrlenW(lpFindReplace->lpstrFindWhat), start = 0, end = 0;
+ wchar_t *buffer = (wchar_t*)calloc((len+1),sizeof(wchar_t)),
+ *search = (wchar_t*)calloc((flen+2),sizeof(wchar_t)),
+ *result = 0;
+
+ lstrcpynW(search,lpFindReplace->lpstrFindWhat,flen+1);
+ SendDlgItemMessageW(hwndDlg,IDC_TIPS,EM_GETSEL,(WPARAM)&start,(LPARAM)&end);
+
+ GetDlgItemTextW(hwndDlg,IDC_TIPS,buffer,len);
+
+ // handles the match case option
+ if(!(lpFindReplace->Flags & FR_MATCHCASE))
+ {
+ CharUpperBuffW(buffer, len);
+ CharUpperBuffW(search, flen+1);
+ }
+
+ if((result = wcsstr(buffer+end,search)))
+ {
+ SendDlgItemMessage(hwndDlg,IDC_TIPS,EM_SETSEL,result-buffer,(result-buffer)+flen);
+ SendDlgItemMessage(hwndDlg,IDC_TIPS,EM_SCROLLCARET,0,0);
+ }
+ else
+ {
+ MessageBoxW(finder,getStringW(IDS_NO_MATCHES_FOUND,NULL,0),L"Winamp",MB_ICONINFORMATION);
+ }
+
+ free(buffer);
+ free(search);
+ }
+ }
+
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ {
+ wchar_t fn[MAX_PATH] = {0};
+ FILE *fp = NULL;
+ int last_add = 0;
+
+ whatedproc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwndDlg,IDC_TIPS),GWLP_WNDPROC,(LONG_PTR)whatseditproc);
+
+ SendDlgItemMessage(hwndDlg, IDC_TIPS, EM_SETLIMITTEXT, 0, 0);
+
+ // attempt to pull a localised whatsnew.txt
+ // before reverting to the english default
+ if (lang_directory[0])
+ {
+ lstrcpynW(fn,lang_directory,MAX_PATH);
+ }
+ else
+ {
+ GetModuleFileNameW(NULL,fn,MAX_PATH);
+ PathRemoveFileSpecW(fn);
+ }
+ PathAppendW(fn, L"whatsnew.txt");
+
+ // we don't set the buffer position so that it all works on the fallback code
+ // and make sure there's a selection no matter what happens with other things
+ SendDlgItemMessageW(hwndDlg,IDC_VER_COMBO,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_SHOW_ALL_HISTORY,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_VER_COMBO,CB_SETCURSEL,0,0);
+
+ versions.clear();
+ fp = _wfopen(fn,L"rb");
+
+ // if there isn't a localised whatsnew.txt then revert to the old ways
+ if(!fp)
+ {
+ GetModuleFileNameW(NULL,fn,MAX_PATH);
+ PathRemoveFileSpecW(fn);
+ PathAppendW(fn,L"whatsnew.txt");
+ fp = _wfopen(fn,L"rb");
+ }
+
+ if (fp)
+ {
+ GetWhatsNewFromFile(fp);
+ fclose(fp);
+ wchar_t* p = ver_buf;
+ while(p && *p)
+ {
+ // populate the version combobox
+ if(!wcsncmp(p,L"Winamp 5.",9))
+ {
+ wchar_t* pp = p, ver[64] = {0};
+ while(pp && *pp && *pp != L'\r') pp = CharNextW(pp);
+ // need to make sure that we've actually found a valid part otherwise
+ // just skip over things and don't fill in the combobox (attempted exploit)
+ if(pp && *pp && *pp == L'\r'){
+ pp = CharNextW(pp);
+ // make sure that we keep within the buffer size as some people have
+ // tried to make a buffer overflow vulnerability with this on XP SP3
+ lstrcpynW(ver,p,(pp-p<64?pp-p:64));
+ wchar_t* v = ver, *vn = 0, *vne = 0;
+ while(v && *v && *v != L'\t') v = CharNextW(v);
+ if(v && *v == L'\t'){
+ vn = vne = CharNextW(v);
+ *v = 0;
+ if(vn && *vn == L'[') vn = CharNextW(vn);
+ while(vne && *vne && *vne != L']') vne = CharNextW(vne);
+ if(vne && *vne == L']') *vne = 0;
+ }
+ last_add = SendDlgItemMessageW(hwndDlg,IDC_VER_COMBO,CB_ADDSTRING,0,(LPARAM)ver);
+ SendDlgItemMessageW(hwndDlg,IDC_VER_COMBO,CB_SETITEMDATA,last_add,(LPARAM)p);
+ versions[last_add] = wcsdup(vn);
+ }
+ }
+ p = CharNextW(p);
+ }
+
+ // reset the selection to the last view and force an update to that
+ // would be better to do it straight away on load but this ensures all synchs up
+ SendDlgItemMessage(hwndDlg,IDC_VER_COMBO,CB_SETCURSEL,_r_i("whtsnewlp",1),0);
+ SendMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_VER_COMBO,CBN_SELCHANGE),(LPARAM)GetDlgItem(hwndDlg,IDC_VER_COMBO));
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VER_COMBO),0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ABOUT_SEARCH),0);
+ SetDlgItemTextW(hwndDlg,IDC_TIPS,getStringW(IDS_WHATSNEW_FAIL,ver_buf,WHATSNEW_BUFFER_SIZE));
+ }
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ if(LOWORD(wParam) == IDC_VER_COMBO && HIWORD(wParam) == CBN_SELCHANGE)
+ {
+ int cur = SendMessageW((HWND)lParam,CB_GETCURSEL,0,0);
+ wchar_t* position = (wchar_t*)SendMessageW((HWND)lParam,CB_GETITEMDATA,cur,0);
+ if(cur != CB_ERR && position){
+ wchar_t* p = position, *out_buf = (wchar_t*)calloc(WHATSNEW_BUFFER_SIZE,sizeof(wchar_t)), *out = out_buf;
+ while(p && *p)
+ {
+ if(*p == L'\t')
+ {
+ if(*CharNextW(p) == L'[')
+ {
+ wchar_t* pb = p;
+ while(pb && *pb && *pb != L']')
+ {
+ pb = CharNextW(pb);
+ }
+ if(pb && *pb == L']') p = CharNextW(pb);
+ }
+ }
+
+ // look for 2 empty lines to indicate end of version block
+ if(*p == L'\r')
+ {
+ wchar_t* n = CharNextW(p);
+ if(n && *n == L'\n')
+ {
+ n = CharNextW(n);
+ if(n && *n == L'\r')
+ {
+ break;
+ }
+ }
+ }
+ *out = *p;
+ p = CharNextW(p);
+ out = CharNextW(out);
+ }
+ *out = 0;
+
+ wchar_t released[128] = {0};
+ if(cur == 1 || cur > 1 && versions[cur] != 0)
+ StringCchPrintfW(released,128,getStringW(IDS_RELEASED,NULL,0), (cur == 1 ? AutoWide(__DATE__) : versions[cur]));
+ else
+ released[0] = 0;
+ SendMessageW(GetDlgItem(hwndDlg,IDC_RELEASED),WM_SETTEXT,0,(LPARAM)released);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_TIPS),WM_SETTEXT,0,(LPARAM)out_buf);
+ free(out_buf);
+ }
+ else{
+ SendMessageW(GetDlgItem(hwndDlg,IDC_RELEASED),WM_SETTEXT,0,(LPARAM)L"");
+ SendMessageW(GetDlgItem(hwndDlg,IDC_TIPS),WM_SETTEXT,0,(LPARAM)ver_buf);
+ }
+ }
+ else if(LOWORD(wParam) == IDC_ABOUT_SEARCH)
+ {
+ if(!IsWindow(finder))
+ {
+ if(!fm_msg) fm_msg = RegisterWindowMessageW(FINDMSGSTRINGW);
+
+ find.lStructSize = sizeof(find);
+ find.hwndOwner = hwndDlg;
+ find.Flags = FR_DOWN|FR_HIDEWHOLEWORD|FR_HIDEUPDOWN;
+ find.lpstrFindWhat = fromstring;
+ find.wFindWhatLen = ARRAYSIZE(fromstring);
+ finder = FindTextW(&find);
+ ShowWindow(finder,SW_SHOW);
+ }
+ else
+ {
+ SetActiveWindow(finder);
+ }
+ }
+
+ else if(LOWORD(wParam) == IDCANCEL)
+ {
+ DestroyWindow(about_hwnd);
+ }
+ break;
+
+ case WM_DESTROY:
+ free(ver_buf);
+ ver_buf = 0;
+
+ //for (int i=0; i!=versions.size(); i++)
+ // free(versions[i]);
+ for (auto& version : versions)
+ {
+ if (version.second)
+ {
+ free(version.second);
+ }
+ }
+
+ versions.clear();
+ _w_i("whtsnewlp",SendDlgItemMessage(hwndDlg,IDC_VER_COMBO,CB_GETCURSEL,0,0));
+ if(IsWindow(finder)) DestroyWindow(finder);
+ break;
+ }
+
+ if (FALSE != IsDirectMouseWheelMessage(uMsg))
+ {
+ HWND textWindow;
+ RECT windowRect;
+ textWindow = GetDlgItem(hwndDlg, IDC_TIPS);
+ if (NULL != textWindow &&
+ FALSE != GetClientRect(textWindow, &windowRect))
+ {
+ POINT pt;
+ POINTSTOPOINT(pt, lParam);
+
+ MapWindowPoints(HWND_DESKTOP, textWindow, &pt, 1);
+ if (FALSE != PtInRect(&windowRect, pt))
+ {
+ SendMessageW(textWindow, WM_MOUSEWHEEL, wParam, lParam);
+ SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
+ }
+ return TRUE;
+ }
+ }
+ return 0;
+}
+
+static volatile int aboutThread_kill, aboutThread_mode;
+static HPALETTE m_haboutpal;
+
+/* This does the 'zooming' effect on the image in the 'winamp' tab of the about screen */
+class AboutContext
+{
+public:
+ bool Init(HWND _hwndDlg);
+ bool Tick();
+ void Quit();
+
+private:
+ int mode;
+ static int m_wt,m_wait;
+ static int a;
+ HDC m_hdc;
+ HBITMAP m_hbm,m_oldhbm;
+
+ int m_pitch,m_height;
+ char *m_source,*m_dib;
+ int m_wmul[200];
+ RECT r;
+ HBITMAP m_imgbm, m_imgoldbm;
+ HDC m_imgdc;
+
+ struct
+ {
+ BITMAPINFO bmi;
+ RGBQUAD more_bmiColors[256];
+ LPVOID data;
+ } m_bitmap;
+ int c,use_palette;
+ HWND hwndDlg;
+};
+
+int AboutContext::m_wt = 0;
+int AboutContext::m_wait = 0;
+int AboutContext::a = 0;
+bool AboutContext::Init(HWND _hwndDlg)
+{
+ hwndDlg = _hwndDlg;
+ mode=(GetAsyncKeyState(VK_SHIFT)&0x8000);
+ GetClientRect(GetDlgItem(hwndDlg,IDC_ABOUTIMG),&r);
+ HDC hdc=GetWindowDC(hwndDlg);
+ if (!hdc)
+ return false;
+ use_palette = (GetDeviceCaps(hdc,RASTERCAPS)&RC_PALETTE)?1:0;
+ m_hdc = CreateCompatibleDC(NULL);
+ m_imgdc = CreateCompatibleDC(NULL);
+ ReleaseDC(hwndDlg,hdc);
+
+ if (!m_imgdc)
+ return false;
+
+ m_imgbm= (HBITMAP)LoadImage(hMainInstance,MAKEINTRESOURCE((!aboutThread_mode ? IDB_SPLASH : IDB_PLATE)),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
+ m_imgoldbm=(HBITMAP)SelectObject(m_imgdc,m_imgbm);
+ m_source=(char *)GlobalAlloc(GPTR,img_w[aboutThread_mode]*img_h[aboutThread_mode]);
+
+ if (m_imgbm && m_source)
+ {
+ memset(&m_bitmap, 0, sizeof(m_bitmap));
+ m_bitmap.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ m_bitmap.bmi.bmiHeader.biPlanes = 1;
+ m_bitmap.bmi.bmiHeader.biBitCount = 8;
+ m_bitmap.bmi.bmiHeader.biCompression = BI_RGB;
+ m_bitmap.bmi.bmiHeader.biSizeImage = 0;
+ m_bitmap.bmi.bmiHeader.biClrUsed = 128;
+ m_bitmap.bmi.bmiHeader.biClrImportant = 128;
+ m_bitmap.bmi.bmiHeader.biWidth = img_w[aboutThread_mode];
+ m_bitmap.bmi.bmiHeader.biHeight = -img_h[aboutThread_mode];
+ m_bitmap.bmi.bmiHeader.biSizeImage = img_w[aboutThread_mode]*img_h[aboutThread_mode];
+
+ GetDIBits(m_imgdc,m_imgbm,0,img_h[aboutThread_mode],m_source,(BITMAPINFO *)&m_bitmap,DIB_RGB_COLORS);
+ GetDIBColorTable(m_imgdc,0,256,m_bitmap.bmi.bmiColors);
+
+ SelectObject(m_imgdc, m_imgoldbm);
+ DeleteDC(m_imgdc);
+ DeleteObject(m_imgbm);
+ }
+ else
+ {
+ DeleteDC(m_imgdc);
+ if (m_imgbm) DeleteObject(m_imgbm);
+ if (m_source) GlobalFree(m_source);
+ return false;
+ }
+
+ if (use_palette)
+ {
+ struct
+ {
+ LOGPALETTE logpal;
+ PALETTEENTRY palentries[255];
+ } palette;
+ palette.logpal.palVersion = 0x300;
+ palette.logpal.palNumEntries = 128;
+
+ for (c = 0; c < 128; c ++)
+ {
+ palette.logpal.palPalEntry[c].peRed = m_bitmap.bmi.bmiColors[c].rgbRed;
+ palette.logpal.palPalEntry[c].peGreen = m_bitmap.bmi.bmiColors[c].rgbGreen;
+ palette.logpal.palPalEntry[c].peBlue = m_bitmap.bmi.bmiColors[c].rgbBlue;
+ palette.logpal.palPalEntry[c].peFlags = 0;
+ }
+ m_haboutpal = CreatePalette((LOGPALETTE *)&palette.logpal);
+ }
+
+ m_pitch=((r.right-r.left+3)&~3);
+ m_height=r.bottom-r.top;
+ m_bitmap.bmi.bmiHeader.biSizeImage = 0;
+ m_bitmap.bmi.bmiHeader.biClrUsed = 0;
+ m_bitmap.bmi.bmiHeader.biClrImportant = 0;
+ m_bitmap.bmi.bmiHeader.biWidth = m_pitch;
+ m_bitmap.bmi.bmiHeader.biHeight = -m_height;
+ m_bitmap.bmi.bmiHeader.biSizeImage = m_pitch*m_height;
+ m_hbm = CreateDIBSection(m_hdc,&m_bitmap.bmi,DIB_RGB_COLORS, &m_bitmap.data, NULL, 0);
+
+ if (!m_hbm)
+ {
+ if (m_imgbm) DeleteObject(m_imgbm);
+ if (m_source) GlobalFree(m_source);
+ return 0;
+ }
+ m_oldhbm = (HBITMAP) SelectObject(m_hdc, m_hbm);
+ m_dib=(char*)m_bitmap.data;
+ {
+ for (int x = 0; x < img_h[aboutThread_mode]; x ++)
+ m_wmul[x]=x*img_w[aboutThread_mode];
+ }
+
+ return true;
+}
+
+
+bool AboutContext::Tick()
+{
+ if (aboutThread_kill)
+ return false;
+
+ int tab[512] = {0};
+ // Sleep(50);
+ {
+ int offs;
+ int x;
+ double max_d=sqrt((double)((m_pitch*m_pitch+m_height*m_height))/4.0f);
+ //int imax_d2=(int)(255.0/max_d*256.0);
+ int imax_d=(int)max_d;
+ double dpos;
+
+ int thiswt=m_wt;
+ if (thiswt > 63) thiswt = 126-thiswt;
+
+ dpos=1.0+sin(thiswt*M_PI/32.0);
+
+ if (dpos < 1.0) dpos=0.5+dpos/2.0;
+ if (thiswt < 32) offs=thiswt*24;
+ else offs=(64-thiswt)*24;
+ if (imax_d > 512) return false;
+
+ for (x = 0; x < imax_d; x ++)
+ {
+ tab[x]=(int) (pow(sin(x/(max_d-1)),dpos)*1.7*256.0*max_d/(x+1)) - offs;
+ if (tab[x]<0)tab[x]=-tab[x];
+ }
+
+ if (m_wt == 0)
+ {
+ if (m_wait++>=40)
+ {
+ m_wt++;
+ }
+ }
+ else
+ {
+ m_wait=0;
+ m_wt++;
+ }
+ m_wt&=127;
+ }
+
+ {
+ int xsc=((!aboutThread_mode ? img_w[0]*180 : img_w[1]*360))/m_pitch;
+ int ysc=((!aboutThread_mode ? img_h[0]*200 : img_h[1]*500))/m_height;
+ int w2=m_pitch/2;
+ int h2=m_height/2;
+ char *out=m_dib;
+ int y;
+ if (m_wt)
+ {
+ a=!a;
+ // weird interlace shit
+ if (a && mode)
+ {
+ out+=m_pitch;
+ }
+ for (y = -h2+(mode?a:0); y < h2; y ++)
+ {
+ int x2=w2*w2+w2+y*y+256;
+ int dx2=-2*w2;
+ int yysc=y*ysc;
+ int xxsc=-w2*xsc;
+ int x=m_pitch;
+ while (x--)
+ {
+ int qd=tab[isqrt(x2)];
+ int ow,oh;
+ x2+=dx2;
+ dx2+=2;
+ ow = img_w[aboutThread_mode]/2 + (qd*xxsc)/65536;
+ xxsc+=xsc;
+ oh = img_h[aboutThread_mode]/2 + (qd*yysc)/65536;
+
+ if (ow < 0) ow=0;
+ else if (ow >= img_w[aboutThread_mode]) ow=img_w[aboutThread_mode]-1;
+ if (oh < 0) oh=0;
+ else if (oh >= img_h[aboutThread_mode]) oh=img_h[aboutThread_mode]-1;
+
+ *out++=m_source[ow+m_wmul[oh]];
+ }
+
+ // weird interlace shit
+ if (mode)
+ {
+ y++;
+ out+=m_pitch;
+ }
+ }
+ }
+ else // copy, with optional rescale
+ {
+ int x;
+ int skipw=0;
+ int skiph=0;
+
+ int dxp,dyp,xp,yp;
+
+ skiph=(m_height-img_h[aboutThread_mode])/2;
+ skipw=(m_pitch-img_w[aboutThread_mode])/2;
+
+ if (skipw <0) skipw=0;
+ if (skiph <0) skiph=0;
+
+ dxp=(img_w[aboutThread_mode]<<16)/(m_pitch-skipw*2);
+ dyp=(img_h[aboutThread_mode]<<16)/(m_height-skiph*2);
+ yp=0;
+ for (y = 0; y < m_height; y ++)
+ {
+ if (y < skiph || y >= m_height - skiph)
+ {
+ memset(out,0,m_pitch);
+ out+=m_pitch;
+ }
+ else
+ {
+ char *in=m_source+(yp>>16)*img_w[aboutThread_mode];
+ xp=0;
+ for (x = 0; x < m_pitch; x ++)
+ {
+ if (x < skipw || x >=m_pitch-skipw)
+ {
+ *out++=0;
+ }
+ else
+ {
+ *out++=in[xp>>16];
+ xp+=dxp;
+ }
+ }
+ yp+=dyp;
+ }
+ }
+ }
+ }
+
+ {
+ HWND hwnd=GetDlgItem(hwndDlg,IDC_ABOUTIMG);
+ if (hwnd)
+ {
+ HDC h=GetDC(hwnd);
+ if (h)
+ {
+ if (m_haboutpal)
+ {
+ SelectPalette(h,m_haboutpal,FALSE);
+ RealizePalette(h);
+ }
+ BitBlt(h,0,0,m_pitch,m_height,m_hdc,0,0,SRCCOPY);
+ ReleaseDC(hwnd,h);
+ }
+ }
+ }
+
+ return true;
+}
+
+void AboutContext::Quit()
+{
+ if (m_hbm)
+ {
+ if (m_hdc) SelectObject(m_hdc, m_oldhbm);
+ DeleteObject(m_hbm);
+ m_hbm = NULL;
+ m_oldhbm=NULL;
+ }
+ if (m_haboutpal)
+ {
+ DeleteObject(m_haboutpal);
+ m_haboutpal = NULL;
+ }
+ if (m_hdc)
+ {
+ DeleteDC(m_hdc);
+ m_hdc=NULL;
+ }
+ if (m_source)
+ {
+ GlobalFree((HGLOBAL)m_source);
+ m_source=NULL;
+ }
+}
+
+static int AboutTickThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
+{
+ AboutContext *context = (AboutContext *)user_data;
+ TimerHandle t(handle);
+ if (context->Tick())
+ {
+ t.Wait(50);
+ return 0;
+ }
+ else
+ {
+ context->Quit();
+ delete context;
+ HANDLE event = (HANDLE)id;
+ SetEvent(event);
+ WASABI_API_THREADPOOL->RemoveHandle(0, handle);
+ t.Close();
+ return 0;
+ }
+}
+
+static int AboutThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
+{
+ AboutContext *context = new AboutContext;
+ if (context->Init((HWND)user_data))
+ {
+ TimerHandle t;
+ WASABI_API_THREADPOOL->AddHandle(0, t, AboutTickThreadPoolFunc, context, id, 0);
+ t.Wait(50);
+ }
+ else
+ {
+ delete context;
+ HANDLE event = (HANDLE)id;
+ SetEvent(event);
+ }
+ return 0;
+}
+/* Window Proc for the 'winamp' tab of the about screen */
+static INT_PTR CALLBACK about1EggProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+#if 0
+ static char ascii[]="\n\n ______ ____ ___/\\ _/\\_ _____ dro _____ <3 ______ /\\____ _______\n\
+ \\_ \\/ \\/ \\_\\__/_\\ \\___ _\\ _ \\___ _\\ \\/ \\__\\ _ \\_\n\
+ / / / / / \\/ |/ \\/ / / / / |/ /\n\
+ / / / / / / / / / / / / ____/\n\
+ \\______/\\________\\____/\\____/\\_____\\____/\\_____\\____\\____/\\____/\\____/\n\
+ _________________________________________________________________ _________\n\
+ (_________________________________________________________________\\\\\\_WINAMP_)\n\n\n\
+ supplied by deadbeef\n\n\
+ cracked by rOn\n\n\
+ 32kb cool intro by lone";
+
+ int i=0;
+ FILE *fh;
+ fh=fopen("c:\\blah.c","wt");
+ for(i=0;ascii[i];i++)
+ {
+ ascii[i]^=0x65;
+ fprintf(fh,"0x%x,",ascii[i]);
+ if((i&31)==31) fprintf(fh,"\n");
+ }
+ fclose(fh);
+#else
+ static char ascii[]={
+ 0x6f,0x6f,0x6f,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x45,0x45,0x3a,0x3a,0x3a,0x4a,0x39,0x45,0x45,0x3a,0x4a,0x39,0x3a,0x45,
+ 0x3a,0x3a,0x3a,0x3a,0x3a,0x45,0x45,0x1,0x17,0xa,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x3a,0x45,0x45,0x45,0x59,0x56,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x45,0x45,
+ 0x4a,0x39,0x3a,0x3a,0x3a,0x3a,0x45,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x6f,0x45,0x45,0x39,0x3a,0x45,0x45,0x45,0x45,0x39,0x4a,0x45,0x45,0x45,0x45,0x39,
+ 0x4a,0x45,0x45,0x45,0x45,0x45,0x39,0x3a,0x39,0x3a,0x3a,0x4a,0x3a,0x39,0x45,0x45,0x45,0x45,0x39,0x3a,0x3a,0x3a,0x45,0x45,0x3a,0x39,0x45,0x45,0x3a,0x45,0x39,0x3a,
+ 0x3a,0x3a,0x45,0x45,0x3a,0x39,0x45,0x45,0x45,0x45,0x45,0x39,0x4a,0x45,0x45,0x45,0x45,0x45,0x45,0x39,0x3a,0x3a,0x39,0x45,0x45,0x3a,0x45,0x45,0x45,0x39,0x3a,0x6f,
+ 0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,
+ 0x45,0x45,0x45,0x45,0x45,0x39,0x4a,0x45,0x45,0x45,0x19,0x4a,0x45,0x45,0x45,0x45,0x45,0x39,0x4a,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x4a,0x45,0x45,0x4a,0x45,0x45,
+ 0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x19,0x4a,0x45,0x45,0x45,0x45,0x4a,0x6f,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x4a,0x45,0x45,0x4a,0x45,0x45,0x45,
+ 0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,
+ 0x4a,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x4a,0x45,0x45,0x45,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x4a,0x6f,0x45,0x45,0x39,
+ 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x4a,0x39,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x39,0x3a,0x3a,0x3a,0x3a,0x4a,0x39,0x3a,0x3a,0x3a,0x3a,0x4a,0x39,0x3a,0x3a,0x3a,
+ 0x3a,0x3a,0x39,0x3a,0x3a,0x3a,0x3a,0x4a,0x39,0x3a,0x3a,0x3a,0x3a,0x3a,0x39,0x3a,0x3a,0x3a,0x3a,0x39,0x3a,0x3a,0x3a,0x3a,0x4a,0x39,0x3a,0x3a,0x3a,0x3a,0x4a,0x39,
+ 0x3a,0x3a,0x3a,0x3a,0x4a,0x6f,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,
+ 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,
+ 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x45,0x45,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x6f,0x45,0x4d,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,
+ 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,
+ 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x39,0x39,0x39,0x3a,0x32,0x2c,0x2b,0x24,
+ 0x28,0x35,0x3a,0x4c,0x6f,0x6f,0x6f,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,
+ 0x45,0x45,0x45,0x16,0x10,0x15,0x15,0x9,0xc,0x0,0x1,0x45,0x7,0x1c,0x45,0x1,0x0,0x4,0x1,0x7,0x0,0x0,0x3,0x6f,0x6f,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,
+ 0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x6,0x17,0x4,0x6,0xe,0x0,0x1,0x45,0x7,0x1c,0x45,
+ 0x17,0x2a,0xb,0x6f,0x6f,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,
+ 0x56,0x57,0xe,0x7,0x45,0x6,0xa,0xa,0x9,0x45,0xc,0xb,0x11,0x17,0xa,0x45,0x7,0x1c,0x45,0x9,0xa,0xb,0x0,
+ };
+ static int dexored=0;
+ if(!dexored)
+ {
+ int i=0;
+ for(i=0;i<sizeof(ascii);i++) ascii[i]^=0x65;
+ dexored=1;
+ }
+#endif
+ SetDlgItemTextA(hwndDlg,IDC_ASCII,ascii);
+ }
+ return 1;
+ case WM_LBUTTONDBLCLK:
+ {
+ EndDialog(hwndDlg,0);
+ ShowWindow(GetDlgItem(GetParent(hwndDlg),IDC_ABOUTIMG),SW_NORMAL);
+ }
+ break;
+ }
+ return 0;
+}
+
+/* Window proc for the about screen (i.e. this one handles the tab changes */
+static BOOL CALLBACK about1Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static HANDLE hThread;
+ static HWND egg_wnd;
+ if (uMsg == WM_INITDIALOG)
+ {
+ if (!hThread)
+ {
+ aboutThread_kill=0;
+ aboutThread_mode=0;
+ hThread = CreateEvent(NULL, TRUE, FALSE, NULL);
+ WASABI_API_THREADPOOL->RunFunction(0, AboutThreadPoolFunc, (void *)hwndDlg, (intptr_t)hThread, 0);
+ }
+ {
+ wchar_t buf[2048] = {0}, buf2[2048] = {0}, buf3[256] = {0},
+ *t1 = 0, *t2 = 0, *t3 = 0;
+ GetDlgItemTextW(hwndDlg,IDC_ABOUTTEXT,buf,ARRAYSIZE(buf));
+ StringCchPrintfW(buf2,2048,buf,(buf3[0] ? buf3 : (t1 = AutoWideDup(app_version_string))),
+ (t2 = AutoWideDup(APP_VERSION_PLATFORM)), (t3 = AutoWideDup(app_date)));
+ SetDlgItemTextW(hwndDlg, IDC_ABOUTTEXT, buf2);
+ link_startsubclass(hwndDlg, IDC_WINAMPLINK);
+ if (t1) free(t1);
+ if (t2) free(t2);
+ if (t3) free(t3);
+ }
+ return TRUE;
+ }
+ if (uMsg == WM_QUERYNEWPALETTE)
+ {
+ if (m_haboutpal)
+ {
+ HDC hdc = GetWindowDC(hwndDlg);
+ SelectPalette(hdc,m_haboutpal,FALSE);
+ RealizePalette(hdc);
+ InvalidateRect(hwndDlg,NULL,FALSE);
+ ReleaseDC(hwndDlg,hdc);
+ return 1;
+ }
+ return 0;
+ }
+ if (uMsg == WM_PALETTECHANGED)
+ {
+ if (m_haboutpal)
+ {
+ HDC hdc = GetWindowDC(hwndDlg);
+ SelectPalette(hdc,m_haboutpal,FALSE);
+ RealizePalette(hdc);
+ UpdateColors(hdc);
+ ReleaseDC(hwndDlg,hdc);
+ return 1;
+ }
+ return 0;
+ }
+ if (uMsg == WM_DESTROY)
+ {
+ if (hThread)
+ {
+ aboutThread_kill=1;
+ WaitForSingleObject(hThread,INFINITE);
+ CloseHandle(hThread);
+ hThread=NULL;
+ }
+ }
+ if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_WINAMPLINK:
+ {
+ wchar_t homepage[1024] = {0};
+ if (config_langpack[0])
+ {
+ getStringW(IDS_LOCALIZED_HOMEPAGE, homepage, 1024);
+ }
+ if (homepage[0])
+ myOpenURL(hwndDlg, homepage);
+ else
+ myOpenURL(hwndDlg,L"http://www.winamp.com/");
+ }
+ return 0;
+ }
+ }
+ if (uMsg == WM_LBUTTONDBLCLK)
+ {
+ if ((GetAsyncKeyState(VK_SHIFT)&0x8000) && !(GetAsyncKeyState(VK_CONTROL)&0x8000))
+ {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ABOUTIMG),SW_HIDE);
+ if (!IsWindow(egg_wnd))
+ {
+ egg_wnd = LPCreateDialogW(IDD_NEWABOUT1EGG,hwndDlg,about1EggProc);
+ }
+ ShowWindow(egg_wnd, SW_SHOW);
+ }
+ else
+ {
+ if ((GetAsyncKeyState(VK_CONTROL)&0x8000) && !(GetAsyncKeyState(VK_SHIFT)&0x8000))
+ {
+ if (hThread)
+ {
+ aboutThread_kill=1;
+ WaitForSingleObject(hThread,INFINITE);
+ CloseHandle(hThread);
+ hThread=NULL;
+ aboutThread_kill=0;
+ aboutThread_mode=!aboutThread_mode;
+ hThread = CreateEvent(NULL, TRUE, FALSE, NULL);
+ WASABI_API_THREADPOOL->RunFunction(0, AboutThreadPoolFunc, (void *)hwndDlg, (intptr_t)hThread, 0);
+ }
+ }
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ABOUTIMG),SW_SHOW);
+ }
+ }
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ return 0;
+}
+
+static volatile int creditThread_kill;
+static HPALETTE m_hcreditspal;
+
+/* this thread handles the 3d credits rendering (this one does some busywork and housecleaning, actual rendering done in creditsrend.c) */
+class CreditsContext
+{
+public:
+ bool Init(HWND _hwndDlg);
+ bool Tick(int &wait_time);
+ void Quit();
+
+private:
+ HDC m_hdc;
+ HBITMAP m_hbm,m_oldhbm;
+ int m_pitch,m_height;
+ char *m_dib;
+char pal[768];
+ struct
+ {
+ BITMAPINFO bmi;
+ RGBQUAD more_bmiColors[255];
+ } m_bitmap;
+ int c,use_palette;
+ HWND hwndDlg;
+};
+
+bool CreditsContext::Init(HWND _hwndDlg)
+{
+ hwndDlg = _hwndDlg;
+ Tataki::Init(WASABI_API_SVC);
+ m_hcreditspal = 0;
+ m_hdc = 0;
+ m_hbm = 0;
+
+ RECT r={0,};
+ memset(&m_bitmap, 0, sizeof(m_bitmap));
+
+ GetWindowRect(hwndDlg,&r);
+ r.right=r.right-r.left;
+ r.bottom=r.bottom-r.top;
+ HDC hdc=GetWindowDC(hwndDlg);
+ if (!hdc)
+ return false;
+ use_palette = (GetDeviceCaps(hdc,RASTERCAPS)&RC_PALETTE)?1:0;
+ m_hdc = CreateCompatibleDC(NULL);
+ ReleaseDC(hwndDlg,hdc);
+
+ m_pitch=((r.right+3)&~3);
+ m_height=r.bottom;
+ if (m_pitch < 4) m_pitch=4;
+ if (m_height < 4) m_height=4;
+ // if (m_pitch > GetSystemMetrics(SM_CXSCREEN)) m_pitch=GetSystemMetrics(SM_CXSCREEN);
+ // if (m_height > GetSystemMetrics(SM_CYSCREEN)) m_height=GetSystemMetrics(SM_CYSCREEN);
+ render_init(m_pitch,m_height,pal);
+
+ {
+ struct
+ {
+ LOGPALETTE logpal;
+ PALETTEENTRY palentries[255];
+ } palette;
+ palette.logpal.palVersion = 0x300;
+ palette.logpal.palNumEntries = 220;
+ for (c = 0; c < 256; c ++)
+ {
+ palette.logpal.palPalEntry[c].peRed = pal[c*3];
+ palette.logpal.palPalEntry[c].peGreen = pal[c*3+1];
+ palette.logpal.palPalEntry[c].peBlue = pal[c*3+2];
+ palette.logpal.palPalEntry[c].peFlags = PC_NOCOLLAPSE;
+ m_bitmap.bmi.bmiColors[c].rgbRed=pal[c*3];
+ m_bitmap.bmi.bmiColors[c].rgbGreen=pal[c*3+1];
+ m_bitmap.bmi.bmiColors[c].rgbBlue=pal[c*3+2];
+ m_bitmap.bmi.bmiColors[c].rgbReserved=0;
+ }
+ if (use_palette)
+ m_hcreditspal = CreatePalette((LOGPALETTE *)&palette.logpal);
+ }
+
+
+ m_bitmap.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ m_bitmap.bmi.bmiHeader.biPlanes = 1;
+ m_bitmap.bmi.bmiHeader.biBitCount = 8;
+ m_bitmap.bmi.bmiHeader.biCompression = BI_RGB;
+ m_bitmap.bmi.bmiHeader.biSizeImage = 0;
+ m_bitmap.bmi.bmiHeader.biClrImportant = 0;
+ m_bitmap.bmi.bmiHeader.biClrUsed = 256;
+ m_bitmap.bmi.bmiHeader.biWidth = m_pitch;
+ m_bitmap.bmi.bmiHeader.biHeight = -m_height;
+ m_bitmap.bmi.bmiHeader.biSizeImage = m_pitch*m_height;
+ m_hbm = CreateDIBSection(m_hdc,&m_bitmap.bmi,DIB_RGB_COLORS, (void**)&m_dib, NULL, 0);
+ m_oldhbm = (HBITMAP) SelectObject(m_hdc, m_hbm);
+ return (m_hbm && m_dib);
+}
+
+void CreditsContext::Quit()
+{
+ if (m_hbm)
+ {
+ if (m_hdc) SelectObject(m_hdc, m_oldhbm);
+ DeleteObject(m_hbm);
+ m_hbm = NULL;
+ m_oldhbm=NULL;
+ }
+ if (m_hcreditspal)
+ {
+ DeleteObject(m_hcreditspal);
+ m_hcreditspal = NULL;
+ }
+ if (m_hdc)
+ {
+ DeleteDC(m_hdc);
+ m_hdc=NULL;
+ }
+ render_quit();
+ Tataki::Quit();
+}
+
+bool CreditsContext::Tick(int &wait_time)
+{
+ if (creditThread_kill)
+ return false;
+
+ unsigned int thist=GetTickCount();
+ render_render((unsigned char*)m_dib, m_hdc);
+ {
+ HDC h=GetDC(hwndDlg);
+ if (h)
+ {
+ if (m_hcreditspal)
+ {
+ SelectPalette(h,m_hcreditspal,FALSE);
+ RealizePalette(h);
+ }
+ BitBlt(h,0,0,m_pitch,m_height,m_hdc,0,0,SRCCOPY);
+ ReleaseDC(hwndDlg,h);
+ }
+ }
+ thist=GetTickCount()-thist;
+ if (thist > 28) thist=28;
+ wait_time = 30-thist;
+ return true;
+}
+
+static int CreditsTickThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
+{
+ CreditsContext *context = (CreditsContext *)user_data;
+ TimerHandle t(handle);
+ int wait_time=30;
+ if (context->Tick(wait_time))
+ {
+ t.Wait(wait_time);
+ return 0;
+ }
+ else
+ {
+ context->Quit();
+ delete context;
+ HANDLE event = (HANDLE)id;
+ SetEvent(event);
+ WASABI_API_THREADPOOL->RemoveHandle(0, handle);
+ t.Close();
+ return 0;
+ }
+}
+
+static int CreditThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
+{
+ CreditsContext *context = new CreditsContext;
+ if (context->Init((HWND)user_data))
+ {
+ TimerHandle t;
+ WASABI_API_THREADPOOL->AddHandle(0, t, CreditsTickThreadPoolFunc, context, id, api_threadpool::FLAG_LONG_EXECUTION);
+ t.Wait(30);
+ }
+ else
+ {
+ delete context;
+ HANDLE event = (HANDLE)id;
+ SetEvent(event);
+ }
+ return 0;
+}
+
+/* Window Proc for the 'credits' tab of the about screen */
+static BOOL CALLBACK creditProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static int g_fullscreen=0;
+ static RECT rsave;
+ static HWND hOldParent;
+ static int oldstyle;
+ static HANDLE hThread;
+ if (uMsg == WM_LBUTTONDBLCLK)
+ {
+ render_togglecredits();
+ return 0;
+ }
+ if (uMsg == WM_KEYDOWN && g_fullscreen)
+ {
+ if (wParam == VK_ESCAPE)
+ {
+ PostMessageW(hwndDlg,WM_LBUTTONDOWN,0,0);
+ }
+ else PostMessageW(hMainWindow,uMsg,wParam,lParam);
+ }
+ if ((uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK) && g_fullscreen)
+ {
+ if (hThread)
+ {
+ creditThread_kill=1;
+ WaitForSingleObject(hThread,INFINITE);
+ CloseHandle(hThread);
+ hThread = 0;
+ if (g_fullscreen)
+ {
+ RECT r=rsave;
+ ScreenToClient(hOldParent,(LPPOINT)&r);
+ ScreenToClient(hOldParent,(LPPOINT)&r+1);
+ SetWindowLong(hwndDlg,GWL_STYLE,oldstyle);
+ SetParent(hwndDlg,hOldParent);
+ SetWindowPos(hwndDlg,0,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER);
+ }
+ }
+ g_fullscreen=0;
+ creditThread_kill=0;
+ hThread = CreateEvent(NULL, TRUE, FALSE, NULL);
+ WASABI_API_THREADPOOL->RunFunction(0, CreditThreadPoolFunc, (void *)hwndDlg, (intptr_t)hThread, api_threadpool::FLAG_LONG_EXECUTION);
+ }
+ else if (uMsg == WM_RBUTTONDBLCLK && !g_fullscreen)
+ {
+ RECT r;
+ if (hThread)
+ {
+ creditThread_kill=1;
+ WaitForSingleObject(hThread,INFINITE);
+ CloseHandle(hThread);
+ hThread = 0;
+ }
+ g_fullscreen=1;
+ GetWindowRect(hwndDlg,&rsave);
+ oldstyle=GetWindowLongW(hwndDlg,GWL_STYLE);
+ hOldParent=SetParent(hwndDlg,NULL);
+
+ SetWindowLong(hwndDlg,GWL_STYLE,WS_POPUP|WS_VISIBLE);
+
+ getViewport(&r,hwndDlg,1,NULL);
+
+ SetWindowPos(hwndDlg, HWND_TOPMOST, r.left, r.top, r.right, r.bottom, SWP_DRAWFRAME);
+ creditThread_kill=0;
+ hThread = CreateEvent(NULL, TRUE, FALSE, NULL);
+ WASABI_API_THREADPOOL->RunFunction(0, CreditThreadPoolFunc, (void *)hwndDlg, (intptr_t)hThread, api_threadpool::FLAG_LONG_EXECUTION);
+ // go fullscreen
+ }
+ if (uMsg == WM_INITDIALOG)
+ {
+ if (!hThread)
+ {
+ g_fullscreen=0;
+ creditThread_kill=0;
+ hThread = CreateEvent(NULL, TRUE, FALSE, NULL);
+ WASABI_API_THREADPOOL->RunFunction(0, CreditThreadPoolFunc, (void *)hwndDlg, (intptr_t)hThread, api_threadpool::FLAG_LONG_EXECUTION);
+ }
+ return TRUE;
+ }
+ if (uMsg == WM_QUERYNEWPALETTE)
+ {
+ if (m_hcreditspal)
+ {
+ HDC hdc = GetWindowDC(hwndDlg);
+ SelectPalette(hdc,m_hcreditspal,FALSE);
+ RealizePalette(hdc);
+ InvalidateRect(hwndDlg,NULL,FALSE);
+ ReleaseDC(hwndDlg,hdc);
+ return 1;
+ }
+ return 0;
+ }
+ if (uMsg == WM_PALETTECHANGED)
+ {
+ if (m_hcreditspal)
+ {
+ HDC hdc = GetWindowDC(hwndDlg);
+ SelectPalette(hdc,m_hcreditspal,FALSE);
+ RealizePalette(hdc);
+ UpdateColors(hdc);
+ ReleaseDC(hwndDlg,hdc);
+ return 1;
+ }
+ return 0;
+ }
+ if (uMsg == WM_DESTROY)
+ {
+ if (hThread)
+ {
+ creditThread_kill=1;
+ WaitForSingleObject(hThread,INFINITE);
+ CloseHandle(hThread);
+ hThread=NULL;
+ }
+ }
+ return 0;
+}
+
+static BOOL CALLBACK translationProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ // only attempt set it to show a hand cursor if it's an ownerdraw button
+ if(GetWindowLongPtrW(GetDlgItem(hwndDlg, IDC_AUTHOR_HOMEPAGE), GWL_STYLE) & BS_OWNERDRAW)
+ {
+ link_startsubclass(hwndDlg, IDC_AUTHOR_HOMEPAGE);
+ }
+ if(GetWindowLongPtrW(GetDlgItem(hwndDlg, IDC_AUTHOR_HOMEPAGE2), GWL_STYLE) & BS_OWNERDRAW)
+ {
+ link_startsubclass(hwndDlg, IDC_AUTHOR_HOMEPAGE2);
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ if(LOWORD(wParam) == IDCANCEL)
+ {
+ DestroyWindow(about_hwnd);
+ }
+ else if (LOWORD(wParam) == IDC_AUTHOR_HOMEPAGE)
+ {
+ wchar_t homepage[1024] = {0};
+ getStringW(IDS_AUTHOR_HOMEPAGE, homepage, 1024);
+ myOpenURL(hwndDlg, homepage);
+ }
+ else if (LOWORD(wParam) == IDC_AUTHOR_HOMEPAGE2)
+ {
+ wchar_t homepage[1024] = {0};
+ getStringW(IDS_AUTHOR_HOMEPAGE2, homepage, 1024);
+ myOpenURL(hwndDlg, homepage);
+ }
+ break;
+ }
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ return 0;
+}
diff --git a/Src/Winamp/ASXv2.cpp b/Src/Winamp/ASXv2.cpp
new file mode 100644
index 00000000..e509d85a
--- /dev/null
+++ b/Src/Winamp/ASXv2.cpp
@@ -0,0 +1,45 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+
+void loadasxv2fn(const wchar_t *filename, int whattodo)
+{
+ if (PlayList_getlength())
+ {
+ if (whattodo < 1)
+ PlayList_delete();
+ }
+
+ int i=1;
+ wchar_t ref[FILENAME_SIZE];
+ wchar_t key[100];
+ while (1)
+ {
+ StringCchPrintfW(key, 100, L"Ref%d", i++);
+ GetPrivateProfileStringW(L"Reference", key, L"?", ref, FILENAME_SIZE, filename);
+ if (!lstrcmpiW(ref, L"?"))
+ break;
+ else
+ {
+ if (!_wcsnicmp(ref, L"http://", 7))
+ {
+ wchar_t *end = scanstr_backW(ref, L"/.", 0);
+ if (!end || *end == L'/')
+ {
+ if (wcschr(ref, L'?'))
+ StringCchCatW(ref, FILENAME_SIZE, L"&=.wma");
+ else
+ StringCchCatW(ref, FILENAME_SIZE, L"?.wma");
+ }
+ }
+
+ PlayList_append(ref);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/AccessibilityConfigGroup.cpp b/Src/Winamp/AccessibilityConfigGroup.cpp
new file mode 100644
index 00000000..e915cd0c
--- /dev/null
+++ b/Src/Winamp/AccessibilityConfigGroup.cpp
@@ -0,0 +1,21 @@
+#include "main.h"
+#include "AccessibilityConfigGroup.h"
+#include "WinampAttributes.h"
+
+
+ifc_configitem *AccessibilityConfigGroup::GetItem(const wchar_t *name)
+{
+ if (!wcscmp(name, L"modalbeep"))
+ return &config_accessibility_modalbeep;
+ else if (!wcscmp(name, L"modalflash"))
+ return &config_accessibility_modalflash;
+ return 0;
+}
+
+
+#define CBCLASS AccessibilityConfigGroup
+START_DISPATCH;
+CB(IFC_CONFIGGROUP_GETITEM, GetItem)
+CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/AccessibilityConfigGroup.h b/Src/Winamp/AccessibilityConfigGroup.h
new file mode 100644
index 00000000..ce634ff5
--- /dev/null
+++ b/Src/Winamp/AccessibilityConfigGroup.h
@@ -0,0 +1,24 @@
+#ifndef NULLSOFT_WINAMP_ACCESSIBILITYCONFIGGROUP_H
+#define NULLSOFT_WINAMP_ACCESSIBILITYCONFIGGROUP_H
+
+//#include "main.h"
+#include "../Agave/Config/ifc_configgroup.h"
+
+// {0E2E7F4A-7C51-478f-8774-ABBCF6D5A857}
+static const GUID accessibilityConfigGroupGUID =
+{ 0xe2e7f4a, 0x7c51, 0x478f, { 0x87, 0x74, 0xab, 0xbc, 0xf6, 0xd5, 0xa8, 0x57 } };
+
+
+class AccessibilityConfigGroup : public ifc_configgroup
+{
+public:
+ ifc_configitem *GetItem(const wchar_t *name);
+ GUID GetGUID() { return accessibilityConfigGroupGUID; }
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern AccessibilityConfigGroup accessibilityConfigGroup;
+
+#endif //NULLSOFT_WINAMP_ACCESSIBILITYCONFIGGROUP_H \ No newline at end of file
diff --git a/Src/Winamp/AdData.cpp b/Src/Winamp/AdData.cpp
new file mode 100644
index 00000000..1603e52c
--- /dev/null
+++ b/Src/Winamp/AdData.cpp
@@ -0,0 +1,13 @@
+#include "main.h"
+#include "AdData.h"
+
+ad_data::ad_data()
+:strCurtain(0), cbCurtain(0)/*, strBrowser(0), cbBrowser(0)*/
+{
+}
+
+ad_data::~ad_data()
+{
+ delete[] strCurtain; cbCurtain=0;
+ /*delete[] strBrowser; cbBrowser=0;*/
+}
diff --git a/Src/Winamp/AdData.h b/Src/Winamp/AdData.h
new file mode 100644
index 00000000..2596fa48
--- /dev/null
+++ b/Src/Winamp/AdData.h
@@ -0,0 +1,17 @@
+#ifndef NULLSOFT_ADDATAH
+#define NULLSOFT_ADDATAH
+
+struct ad_data
+{
+ ad_data();
+ ~ad_data();
+ char *strCurtain;
+ int cbCurtain;
+ /*
+ char *strBrowser;
+ size_t cbBrowser;
+ */
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/AlbumArtRetrieval.cpp b/Src/Winamp/AlbumArtRetrieval.cpp
new file mode 100644
index 00000000..29338392
--- /dev/null
+++ b/Src/Winamp/AlbumArtRetrieval.cpp
@@ -0,0 +1,693 @@
+// disabled 30 May 2012 as per email from Tejas w.r.t. to Rovi deal ending
+#if 0
+#include "main.h"
+#include "../nu/AutoUrl.h"
+#include "../nu/AutoWide.h"
+#include "../nu/GrowBuf.h"
+#include "api.h"
+#include "../xml/obj_xml.h"
+#include "../xml/ifc_xmlreadercallback.h"
+#include "..\Components\wac_network\wac_network_http_receiver_api.h"
+#include <api/service/waservicefactory.h>
+#include <api/service/svcs/svc_imgload.h>
+#include "XMLString.h"
+#include <tataki/export.h>
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <strsafe.h>
+
+static INT_PTR CALLBACK artDownloader(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static INT_PTR CALLBACK scrollChildHostProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static INT_PTR CALLBACK scrollChildProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static INT_PTR CALLBACK imageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+
+#define HTTP_BUFFER_SIZE 32768
+
+#define WM_ADDCHILD WM_USER+0
+#define WM_SELECTED WM_USER+1
+#define WM_UPDATESTATUS WM_USER+2
+#define AddImageToList(hChild, param) SendMessageW(hChild,WM_ADDCHILD,0,(LPARAM)param)
+#define GetParam(hwndDlg) (ArtParser*)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA)
+#define GetParamC(hwndDlg) (ImgDownloader*)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA)
+#define UpdateStatus(hwndDlg) PostMessageW(hwndDlg,WM_UPDATESTATUS,0,0)
+
+class ImgDownloader
+{
+public:
+ ImgDownloader(const wchar_t *_desc, const char *_url) : done(false), http(0), started(false), error(false), imgbuf(0), imgbufsize(0), imgbufused(0)
+ {
+ desc = _wcsdup(_desc);
+ url = _strdup(_url);
+ }
+ ~ImgDownloader()
+ {
+ free(desc);
+ free(url);
+ free(imgbuf);
+ waServiceFactory *httpFactory = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
+ if(httpFactory && http)
+ httpFactory->releaseInterface(http);
+ }
+ bool run();
+
+ wchar_t *desc;
+ char *url;
+ bool done, error;
+ api_httpreceiver *http;
+
+ BYTE *imgbuf;
+ int imgbufsize;
+ int imgbufused;
+private:
+ bool started;
+};
+
+class ArtParser : public ifc_xmlreadercallback
+{
+public:
+ ArtParser(artFetchData * data);
+ ~ArtParser();
+
+ wchar_t curAlbumStr[512] = {0};
+ void ArtParser::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+ void ArtParser::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
+
+ int run();
+
+ artFetchData * data;
+
+ bool doneXML;
+ int curImage, numImages, failedImages;
+
+ bool error;
+ HWND hwndDlg;
+ obj_xml *parser;
+ waServiceFactory *parserFactory, *httpFactory;
+ api_httpreceiver *http;
+ std::vector<ImgDownloader*> imgDownload;
+
+protected:
+ #define CBCLASS ArtParser
+ START_DISPATCH_INLINE;
+ VCB(ONSTARTELEMENT, StartTag);
+ VCB(ONCHARDATA, TextHandler);
+ END_DISPATCH;
+ #undef CBCLASS
+};
+
+wchar_t tmp_album[512] = {0}, tmp_artist[512] = {0}, tmp_year[5] = {0};
+int RetrieveAlbumArt(artFetchData * data)
+{
+ if(!data || data->size < sizeof(artFetchData))
+ return 1;
+
+ int ret = 1;
+ Tataki::Init(serviceManager);
+ {
+ ArtParser param(data);
+ if(!param.error)
+ ret = LPDialogBoxParamW(IDD_ARTDOWNLOADER,data->parent,artDownloader,(LPARAM)&param);
+
+ while (ret == 2) // Keep in loop till user aborts custom search
+ {
+ // TODO: benski> maybe we should save the old values and restore at the end
+ data->album = tmp_album;
+ data->artist = tmp_artist;
+ data->year = _wtoi(tmp_year);
+ // Martin> we should also set the other values back to null
+ // benski> i'm not sure if we want to set these id fields to NULL
+ // but we'll go with it for now
+ data->amgAlbumId = NULL;
+ data->amgArtistId = NULL;
+ data->gracenoteFileId = NULL;
+ WASABI_API_MEMMGR->sysFree(data->imgData);
+ data->imgData = NULL;
+ data->imgDataLen = NULL;
+
+ ArtParser param(data);
+ ret = LPDialogBoxParamW(IDD_ARTDOWNLOADER,data->parent,artDownloader,(LPARAM)&param);
+ }
+ }
+ Tataki::Quit();
+ return ret;
+}
+
+#define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.21*/ + 1 /*Null*/)
+static void SetUserAgent(api_httpreceiver *http)
+{
+ char user_agent[USER_AGENT_SIZE] = {0};
+ StringCchCopyA(user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/"APP_VERSION); // as a nice side effect, this will cut off any extra digits after the first two. e.g. 5.111 becomes 5.11
+ http->addheader(user_agent);
+}
+
+class UrlBuilder : private GrowBuf
+{
+public:
+ UrlBuilder(const char * base) : first(1) { set(base); }
+ ~UrlBuilder(){}
+ void AddParam(const char * key, const wchar_t * value) { AddParamI(key,(char*)AutoUrl(value)); }
+ void AddParam(const char * key, int value) { char buf[16]; StringCchPrintfA(buf,16,"%d",value); AddParamI(key,buf); }
+ void Finish() { GrowBuf::add((void*)"",1); }
+ const char * Get() { return (const char*)get(); } // don't call this without first calling finish!
+private:
+ void AddParamI(const char * key, const char * value) { if(first){ first=0; add("?");} else add("&"); add(key); add("="); add(value); }
+ void add(const char * x) { GrowBuf::add((char*)x,strlen(x)); }
+ void set(const char * x) { GrowBuf::set((char*)x,strlen(x)); }
+ int first;
+};
+
+static wchar_t* format(const wchar_t *in, wchar_t *buf, int len)
+{
+ wchar_t *p = buf;
+ int inbracket = 0;
+ while(in && *in)
+ {
+ if(p >= buf + len - 1) break;
+ else if(*in == L'[' || *in == L'(' || *in == L'<') inbracket++;
+ else if(*in == L']' || *in == L')' || *in == L'>') inbracket--;
+ else if(!inbracket) *(p++) = *in;
+ in++;
+ }
+ *p=0;
+ return buf;
+}
+
+ArtParser::ArtParser(artFetchData * data) : data(data), error(false), parserFactory(0), parser(0), http(0), httpFactory(0), doneXML(false), curImage(0), numImages(0), failedImages(0)
+{
+ curAlbumStr[0]=0;
+
+ parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
+ if (parserFactory)
+ parser = (obj_xml *)parserFactory->getInterface();
+
+ if (parser)
+ {
+ parser->xmlreader_registerCallback(L"document\fartwork", this);
+ parser->xmlreader_registerCallback(L"response\fdata\fartwork", this);
+ parser->xmlreader_open();
+ }
+ else
+ {
+ error=true;
+ return;
+ }
+
+ // construct xml url
+ UrlBuilder url("http://client.winamp.com/metadata/artwork.php");
+
+ wchar_t temp[2048] = {0};
+
+ if(data->artist && data->artist[0] && _wcsicmp(data->artist, L"Various Artists") && _wcsicmp(data->artist, L"VA") && _wcsicmp(data->artist, L"OST"))
+ url.AddParam("artist",format(data->artist,temp,2048));
+
+ if(data->album && data->album[0])
+ url.AddParam("album",format(data->album,temp,2048));
+
+ if(data->year)
+ url.AddParam("recorddate",data->year);
+
+ if(data->amgAlbumId)
+ url.AddParam("amgalbumid",data->amgAlbumId);
+
+ if(data->amgArtistId)
+ url.AddParam("amgartistid",data->amgArtistId);
+
+ if(data->gracenoteFileId && data->gracenoteFileId[0])
+ url.AddParam("tagid",data->gracenoteFileId);
+
+ url.Finish();
+
+ httpFactory = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
+ if(httpFactory) http = (api_httpreceiver *)httpFactory->getInterface();
+
+ if(http)
+ {
+ http->AllowCompression();
+ http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, config_proxy);
+ SetUserAgent(http);
+ http->connect(url.Get());
+ }
+ else error = true;
+}
+
+ArtParser::~ArtParser()
+{
+ imgDownload.deleteAll();
+ if(parser)
+ {
+ parser->xmlreader_unregisterCallback(this);
+ parser->xmlreader_close();
+ if(parserFactory)
+ parserFactory->releaseInterface(parser);
+ }
+ parser = 0;
+ parserFactory = 0;
+ if(http && httpFactory)
+ httpFactory->releaseInterface(http);
+ http = 0;
+ httpFactory = 0;
+}
+
+void ArtParser::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ const wchar_t* artist = params->getItemValue(L"amgArtistDispName");
+ const wchar_t* album = params->getItemValue(L"amgDispName");
+ const wchar_t* year = params->getItemValue(L"recordDate");
+ StringCchPrintfW(curAlbumStr,512,L"%s - %s (%s)",artist?artist:L"",album?album:L"",year?year:L"");
+}
+
+void ArtParser::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str)
+{
+ numImages++;
+ imgDownload.push_back(new ImgDownloader(curAlbumStr,AutoChar(str)));
+ UpdateStatus(hwndDlg);
+}
+
+int ArtParser::run()
+{
+ int ret = http->run();
+ if (ret == -1) // connection failed
+ {
+ error=true;
+ UpdateStatus(hwndDlg);
+ return 0;
+ }
+
+ int replycode = http->getreplycode();
+ switch (replycode)
+ {
+ case 0:
+ case 100:
+ return 1;
+ case 200:
+ {
+ char downloadedData[HTTP_BUFFER_SIZE] = {0};
+ int xmlResult = API_XML_SUCCESS;
+ int downloadSize = http->get_bytes(downloadedData, HTTP_BUFFER_SIZE);
+ if(downloadSize)
+ xmlResult = parser->xmlreader_feed((void *)downloadedData, downloadSize);
+ else if(!downloadSize && ret == 1)
+ { // we're finished!
+ xmlResult = parser->xmlreader_feed(0,0);
+ doneXML=true;
+ UpdateStatus(hwndDlg);
+ return 0;
+ }
+ break;
+ }
+ default:
+ error=true;
+ UpdateStatus(hwndDlg);
+ return 0;
+ }
+ return 1;
+}
+
+bool ImgDownloader::run()
+{
+ if(!started)
+ {
+ started = true;
+ waServiceFactory *httpFactory = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
+ if(httpFactory) http = (api_httpreceiver *)httpFactory->getInterface();
+ if(http)
+ {
+ http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, config_proxy);
+ SetUserAgent(http);
+ http->connect(url);
+ }
+ imgbuf = (BYTE*)malloc(HTTP_BUFFER_SIZE);
+ imgbufsize = HTTP_BUFFER_SIZE;
+ }
+ if(!http || !imgbuf)
+ {
+ error=true;
+ return 0;
+ }
+ int ret = http->run();
+ if(ret == -1) //error
+ {
+ error=true;
+ return 0;
+ }
+
+ int replycode = http->getreplycode();
+ switch (replycode)
+ {
+ case 0:
+ case 100:
+ return 1;
+ case 200:
+ {
+ int downloadSize = http->get_bytes(imgbuf+imgbufused, imgbufsize - imgbufused);
+ imgbufused += downloadSize;
+ if(imgbufused + 4096 >= imgbufsize)
+ {
+ imgbufsize += HTTP_BUFFER_SIZE;
+ imgbuf = (BYTE*)realloc(imgbuf,imgbufsize);
+ }
+
+ if(!downloadSize && ret == 1)
+ done=true;
+ break;
+ }
+ default:
+ return 0;
+ }
+ return 1;
+
+}
+
+static INT_PTR CALLBACK artDownloader(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static HWND m_child;
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ m_child = LPCreateDialogW(IDD_ARTDOWNLOADER_SCROLLHOST,hwndDlg,(WNDPROC)scrollChildHostProc);
+ SetWindowLong(hwndDlg,GWLP_USERDATA,lParam);
+ ArtParser * parser = (ArtParser *)lParam;
+ parser->hwndDlg = hwndDlg;
+ SetTimer(hwndDlg,0,50,NULL);
+ SetTimer(hwndDlg,1,50,NULL);
+ UpdateStatus(hwndDlg);
+ if(parser->data->showCancelAll) ShowWindow(GetDlgItem(hwndDlg,IDC_CANCELALL),SW_SHOWNA);
+ wchar_t old[100]=L"";
+ GetWindowTextW(hwndDlg,old,100);
+ wchar_t buf[256]=L"";
+ if(parser->data->artist && parser->data->artist[0] && parser->data->album && parser->data->album[0])
+ StringCchPrintfW(buf,256,L"%s: %s - %s",old,parser->data->artist,parser->data->album);
+ else if(parser->data->album && parser->data->album[0])
+ StringCchPrintfW(buf,256,L"%s: %s",old,parser->data->album);
+ else if(parser->data->artist && parser->data->artist[0])
+ StringCchPrintfW(buf,256,L"%s: %s",old,parser->data->artist);
+
+ if(buf[0])
+ SetWindowTextW(hwndDlg,buf);
+
+ SetWindowTextW(GetDlgItem(hwndDlg,IDC_SEARCHREFINE_ARTIST), parser->data->artist);
+ SetWindowTextW(GetDlgItem(hwndDlg,IDC_SEARCHREFINE_ALBUM), parser->data->album);
+ wchar_t yearbuf[5]=L"";
+ _itow(parser->data->year,yearbuf,10);
+ SetWindowTextW(GetDlgItem(hwndDlg,IDC_SEARCHREFINE_YEAR), (parser->data->year?yearbuf:L""));
+ }
+ break;
+ case WM_SELECTED:
+ {
+ ArtParser * parser = GetParam(hwndDlg);
+ HWND selchild = (HWND)wParam;
+ ImgDownloader *d = (ImgDownloader *)lParam;
+ if(parser && d && d->imgbuf && d->imgbufused)
+ {
+ if (!AGAVE_API_AMGSUCKS || AGAVE_API_AMGSUCKS->WriteAlbumArt(d->imgbuf, d->imgbufused, &parser->data->imgData, &parser->data->imgDataLen) != 0)
+ {
+ void * img = WASABI_API_MEMMGR->sysMalloc(d->imgbufused);
+ memcpy(img,d->imgbuf,d->imgbufused);
+ parser->data->imgData = img;
+ parser->data->imgDataLen = d->imgbufused;
+ }
+ char * dot = strrchr(d->url,'.');
+ if(dot) lstrcpynW(parser->data->type,AutoWide(dot+1),10);
+ EndDialog(hwndDlg,0);
+ }
+ }
+ break;
+ case WM_UPDATESTATUS:
+ {
+ ArtParser * parser = GetParam(hwndDlg);
+ if(parser)
+ {
+ wchar_t s[100] = {0};
+ if(parser->error) getStringW(IDS_ART_SEARCH_FAILED,s,100);
+ else if(parser->doneXML) getStringW(IDS_ART_SEARCH_FINISHED,s,100);
+ else getStringW(IDS_ART_SEARCH_PROGRESS,s,100);
+ wchar_t buf[512] = {0};
+ StringCchPrintfW(buf,512,getStringW(IDS_ART_SEARCH_STATUS,0,0),s,parser->numImages,parser->curImage - parser->failedImages,parser->failedImages,parser->numImages - parser->curImage);
+ SetDlgItemTextW(hwndDlg,IDC_STATUS,buf);
+
+ }
+ }
+ break;
+ case WM_TIMER:
+ {
+ ArtParser * parser = GetParam(hwndDlg);
+ switch(wParam)
+ {
+ case 0:
+ if(parser && !parser->run())
+ KillTimer(hwndDlg,0);
+ break;
+ case 1:
+ if(parser && parser->imgDownload.size())
+ {
+ ImgDownloader *d = parser->imgDownload.at(0);
+ if(d->error)
+ {
+ parser->failedImages++;
+ parser->curImage++;
+ parser->imgDownload.eraseindex(0);
+ delete d;
+ UpdateStatus(hwndDlg);
+ }
+ else if(d->done)
+ {
+ parser->curImage++;
+ parser->imgDownload.eraseindex(0);
+ AddImageToList(m_child,d);
+ UpdateStatus(hwndDlg);
+ }
+ else d->run();
+ }
+ if(parser->error || parser->doneXML)
+ {
+ if(parser->curImage == parser->numImages)
+ {
+ KillTimer(hwndDlg,1);
+ if(!parser->numImages)
+ {
+ wchar_t title[100] = {0};
+ getStringW(IDS_ART_SEARCH_NOT_FOUND_TITLE,title,100);
+ MessageBoxW(hwndDlg,getStringW(IDS_ART_SEARCH_NOT_FOUND,0,0),title,0);
+ //EndDialog(hwndDlg,-1); //CUT, since we have now a custom search
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SEARCHAGAIN), true);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case WM_DESTROY:
+ {
+ SetWindowLong(hwndDlg,GWLP_USERDATA,0);
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hwndDlg,-1);
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ EndDialog(hwndDlg,-1);
+ break;
+ case IDC_CANCELALL:
+ EndDialog(hwndDlg,-2);
+ break;
+ case IDC_SEARCHAGAIN: // copy text field params to parser
+ ArtParser * parser = GetParam(hwndDlg);
+
+ // Let the first search process finish
+ if (!(parser->doneXML || parser->error))
+ {
+ //TODO change this string
+ MessageBoxW(hwndDlg, L"Please wait till the current retrieval is finished", L"", 0);
+ return 0;
+ }
+
+ GetDlgItemTextW(hwndDlg,IDC_SEARCHREFINE_ALBUM, tmp_album, 512);
+ GetDlgItemTextW(hwndDlg,IDC_SEARCHREFINE_ARTIST, tmp_artist, 512);
+ GetDlgItemTextW(hwndDlg,IDC_SEARCHREFINE_YEAR, tmp_year, 5);
+
+ // End Dialog w/ returning 2: indicates that teh users wants to start a custom search
+ EndDialog(hwndDlg,2);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+// from FileInfo.cpp
+extern HBITMAP getBitmap(ARGB32 * data, int dw, int dh, int targetW, int targetH, HWND parent);
+extern ARGB32 * decompressImage(const void *data, int datalen, int * dataW, int * dataH);
+
+HBITMAP loadImage(const void * data, int datalen, int w, int h, HWND parent, int *dw=0, int *dh=0)
+{
+ int dataW=0, dataH=0;
+ ARGB32* ret = decompressImage(data,datalen,&dataW,&dataH);
+
+ if(dw) *dw = dataW;
+ if(dh) *dh = dataH;
+ if(!ret) return 0;
+ HBITMAP r = getBitmap(ret, dataW, dataH, w, h, parent);
+ WASABI_API_MEMMGR->sysFree(ret);
+ return r;
+}
+
+#define GetDlgParent(hwndDlg) GetParent(GetParent(GetParent(hwndDlg)))
+static INT_PTR CALLBACK imageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SetWindowLong(hwndDlg,GWLP_USERDATA,lParam);
+ ImgDownloader *d = (ImgDownloader *)lParam;
+ int w=0,h=0;
+ HBITMAP bm = loadImage(d->imgbuf,d->imgbufused,140,140,hwndDlg,&w,&h);
+ SendDlgItemMessage(hwndDlg,IDC_IMAGE,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)bm);
+ wchar_t buf[1024] = {0};
+ StringCchPrintfW(buf,1024,L"%s: %dx%d (%d kB)",d->desc,w,h,(d->imgbufused/1024));
+ SetDlgItemTextW(hwndDlg,IDC_IMGTEXT,buf);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ ImgDownloader *d = GetParamC(hwndDlg);
+ SetWindowLong(hwndDlg,GWLP_USERDATA,0);
+ if(d) delete d;
+ HBITMAP bm = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_IMAGE,STM_SETIMAGE,IMAGE_BITMAP,0);
+ if(bm) DeleteObject(bm);
+ }
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam) != IDC_SELECT)
+ break;
+ // else run through
+ case WM_LBUTTONDBLCLK:
+ SendMessageW(GetDlgParent(hwndDlg),WM_SELECTED,(WPARAM)hwndDlg,(LPARAM)GetParamC(hwndDlg));
+ break;
+ }
+ return 0;
+}
+
+// scroll shit, nothing interesting is happening down here...
+
+static INT_PTR CALLBACK scrollChildHostProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ //static HWND m_child;
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ RECT r;
+ HWND hw = GetParent(hwndDlg);
+ GetWindowRect(GetDlgItem(hw,IDC_PLACEHOLDER),&r);
+ ScreenToClient(hw,(LPPOINT)&r);
+ ScreenToClient(hw,((LPPOINT)&r)+1);
+ SetWindowPos(hwndDlg,NULL,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER|SWP_NOACTIVATE);
+ LPCreateDialogW(IDD_ARTDOWNLOADER_SCROLLCHILD,hwndDlg,(WNDPROC)scrollChildProc);
+
+ SCROLLINFO si={sizeof(si),SIF_RANGE|SIF_PAGE,0};
+ si.nPage = (r.right - r.left);
+ SetScrollInfo(hwndDlg,SB_HORZ,&si,TRUE);
+ }
+ break;
+ case WM_ADDCHILD:
+ {
+ HWND m_child = GetWindow(hwndDlg,GW_CHILD);
+ HWND newChild = (HWND)SendMessageW(m_child,uMsg,wParam,lParam);
+ RECT r,r2;
+ GetClientRect(m_child,&r);
+ GetClientRect(hwndDlg,&r2);
+ SCROLLINFO si={sizeof(si),SIF_RANGE|SIF_PAGE,0};
+ si.nMin = 0;
+ si.nMax = (r.right - r.left);
+ si.nPage = (r2.right - r2.left);
+ if(si.nMax < 0) si.nMax = 0;
+ SetScrollInfo(hwndDlg,SB_HORZ,&si,TRUE);
+ return (INT_PTR)newChild;
+ }
+ break;
+ case WM_HSCROLL:
+ {
+ HWND m_child = GetWindow(hwndDlg,GW_CHILD);
+ int v=0;
+ RECT r;
+ RECT r2;
+ GetClientRect(hwndDlg,&r2);
+ GetClientRect(m_child,&r);
+ int action = LOWORD(wParam);
+
+ if (r2.right < r.right) {
+ if (action == SB_THUMBPOSITION || action == SB_THUMBTRACK) {
+ SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS};
+ GetScrollInfo(hwndDlg,SB_HORZ,&si);
+ v=si.nTrackPos;
+ }
+ else if (action == SB_TOP)
+ v=0;
+ else if (action == SB_BOTTOM)
+ v=r.right-r2.right;
+ else if (action == SB_PAGEDOWN || action == SB_LINEDOWN) {
+ SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS};
+ GetScrollInfo(hwndDlg,SB_HORZ,&si);
+ if(action == SB_LINEDOWN)
+ v=si.nPos + (r2.right)/10;
+ else
+ v=si.nPos + r2.right;
+ if (v > r.right-r2.right) v=r.right-r2.right;
+ }
+ else if (action == SB_PAGEUP || action == SB_LINEUP) {
+ SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS};
+ GetScrollInfo(hwndDlg,SB_HORZ,&si);
+ if(action == SB_LINEUP)
+ v=si.nPos - (r2.right)/10;
+ else
+ v=si.nPos - r2.right;
+ if (v < 0) v=0;
+ }
+ else return 0;
+
+ SetScrollPos(hwndDlg,SB_HORZ,v,!(action == SB_THUMBPOSITION || action == SB_THUMBTRACK));
+ SetWindowPos(m_child,NULL,0-v,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ else {
+ SetScrollPos(hwndDlg,SB_HORZ,0,!(action == SB_THUMBPOSITION || action == SB_THUMBTRACK));
+ SetWindowPos(m_child,NULL,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK scrollChildProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ RECT r;
+ GetClientRect(hwndDlg,&r);
+ SetWindowPos(hwndDlg,0,0,0,0,r.bottom,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ break;
+ case WM_ADDCHILD:
+ {
+ HWND newChild = LPCreateDialogParamW(IDD_ARTDOWNLOADER_IMAGE,hwndDlg,imageProc,lParam);
+ RECT r,r2;
+ GetClientRect(hwndDlg,&r);
+ GetClientRect(newChild,&r2);
+ SetWindowPos(hwndDlg,0,0,0,r.right + r2.right,r.bottom,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
+ SetWindowPos(newChild,0,r.right,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ ShowWindow(newChild,SW_SHOWNA);
+ return (INT_PTR)newChild;
+ }
+ break;
+ }
+ return 0;
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/AppRefCount.cpp b/Src/Winamp/AppRefCount.cpp
new file mode 100644
index 00000000..4d67f17f
--- /dev/null
+++ b/Src/Winamp/AppRefCount.cpp
@@ -0,0 +1,52 @@
+#include "AppRefCount.h"
+
+AppRefCount appRefCount;
+AppRefCount::AppRefCount()
+{
+ refCount = 1;
+ m_dwThread = 0;
+}
+
+STDMETHODIMP AppRefCount::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG AppRefCount::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+ULONG AppRefCount::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) PostThreadMessage(m_dwThread, WM_NULL, 0, 0);
+ return lRef;
+}
+
+int AppRefCount_CanQuit()
+{
+ return appRefCount.refCount == 0;
+}
+
+void *InitAppRefCounterObject(DWORD threadId)
+{
+ appRefCount.m_dwThread = threadId;
+ return (IUnknown *)&appRefCount;
+}
+
+void AppRefCount_Release()
+{
+ appRefCount.Release();
+} \ No newline at end of file
diff --git a/Src/Winamp/AppRefCount.h b/Src/Winamp/AppRefCount.h
new file mode 100644
index 00000000..8366d77c
--- /dev/null
+++ b/Src/Winamp/AppRefCount.h
@@ -0,0 +1,35 @@
+#pragma once
+#ifdef __cplusplus
+#include <unknwn.h>
+class ThreadRefCount : public IUnknown
+{
+public:
+ ThreadRefCount();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ LONG refCount;
+};
+
+class AppRefCount : public IUnknown
+{
+public:
+ AppRefCount();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ LONG refCount;
+ DWORD m_dwThread;
+};
+
+extern "C" {
+#endif
+ void *InitAppRefCounterObject(DWORD threadId);
+ void *GetAppRefCounterObject();
+ void AppRefCount_Release();
+ int AppRefCount_CanQuit();
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/ApplicationCOM.cpp b/Src/Winamp/ApplicationCOM.cpp
new file mode 100644
index 00000000..509db740
--- /dev/null
+++ b/Src/Winamp/ApplicationCOM.cpp
@@ -0,0 +1,321 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "ApplicationCOM.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+#include "api.h"
+#include "../Plugins/General/gen_ml/ml.h"
+#include <api/syscb/callbacks/browsercb.h>
+#include "../Agave/Language/api_language.h"
+HINSTANCE WASABI_API_LNG_HINST;
+HINSTANCE WASABI_API_ORIG_HINST;
+#include <shlwapi.h>
+#include "TempFileCOM.h"
+#include "resource.h"
+#include "JSAPI.h"
+
+#define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
+
+bool FilterUrl(const wchar_t *url)
+{
+ const wchar_t filterNowPlaying[] = L"http://client.winamp.com/nowplaying";
+ size_t urlLength, filterLength;
+ if (NULL == url)
+ return false;
+
+ urlLength = lstrlenW(url);
+ filterLength = ARRAYSIZE(filterNowPlaying) - 1;
+ if (urlLength >= filterLength &&
+ CSTR_EQUAL == CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE,
+ url, (int)filterLength, filterNowPlaying, (int)filterLength))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void myOpenURL(HWND hwnd, const wchar_t *loc)
+{
+ if (loc)
+ {
+ bool override=false;
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&override));
+ if (!override && false == FilterUrl(loc))
+ ShellExecuteW(hwnd, L"open", loc, NULL, NULL, SW_SHOWNORMAL);
+ }
+}
+
+void myOpenURLWithFallback(HWND hwnd, wchar_t *loc, wchar_t *fallbackLoc)
+{
+ bool override=false;
+ if (loc)
+ {
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&override));
+ }
+ if (!override && false == FilterUrl(loc) && fallbackLoc)
+ ShellExecuteW(hwnd, L"open", fallbackLoc, NULL, NULL, SW_SHOWNORMAL);
+}
+
+
+enum
+{
+ DISP_APPLICATION_IDLE = 777,
+ DISP_APPLICATION_GETLANGUAGE,
+ DISP_APPLICATION_ISWINAMPPRO,
+ DISP_APPLICATION_GETCOUNTRY,
+ DISP_APPLICATION_GETLOCALE,
+ DISP_APPLICATION_LAUNCHURL,
+ DISP_APPLICATION_VERSION,
+ DISP_APPLICATION_SPECIALBUILD,
+ DISP_APPLICATION_DOWNLOADMEDIA,
+ DISP_APPLICATION_CREATETEMPFILE,
+};
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT ApplicationCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("Idle", DISP_APPLICATION_IDLE)
+ CHECK_ID("GetLanguage", DISP_APPLICATION_GETLANGUAGE)
+ CHECK_ID("IsWinampPro", DISP_APPLICATION_ISWINAMPPRO)
+ CHECK_ID("GetCountry", DISP_APPLICATION_GETCOUNTRY)
+ CHECK_ID("GetLocale", DISP_APPLICATION_GETLOCALE)
+ CHECK_ID("LaunchURL", DISP_APPLICATION_LAUNCHURL)
+ CHECK_ID("Version", DISP_APPLICATION_VERSION)
+ CHECK_ID("GetSpecialBuildName", DISP_APPLICATION_SPECIALBUILD)
+ CHECK_ID("DownloadMedia", DISP_APPLICATION_DOWNLOADMEDIA)
+ CHECK_ID("CreateTempFile", DISP_APPLICATION_CREATETEMPFILE)
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT ApplicationCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT ApplicationCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+void GetLanguage(wchar_t *language, size_t size)
+{
+ StringCchCopyW(language, size, WASABI_API_LNG->GetLanguageIdentifier(LANG_LANG_CODE));
+}
+
+void GetCountry(wchar_t *language, size_t size)
+{
+ // language packs aren't country-specific enough to use them for country info, yet
+ int err = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME , language, (int)size);
+ if (err == 0) // win95 doesn't support this flag, so we'll check for an error
+ lstrcpynW(language, L"US", (int)size); // and default to english
+}
+
+void CALLBACK OpenURLAPC(ULONG_PTR param)
+{
+ wchar_t *url = (wchar_t *)param;
+ myOpenURL(NULL, url);
+ free(url);
+}
+
+void GetPathToStore(wchar_t path_to_store[MAX_PATH])
+{
+ if (FAILED(SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
+ {
+ if (FAILED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
+ {
+ // and if that all fails then do a reasonable default
+ GetPrivateProfileStringW(L"gen_ml_config", L"extractpath", L"C:\\My Music", path_to_store, MAX_PATH, ML_INI_FILE);
+ }
+ // if there's no valid My Music folder (typically win2k) then default to %my_documents%\my music
+ else
+ {
+ PathCombineW(path_to_store, path_to_store, L"My Music");
+ }
+ }
+}
+
+static void CALLBACK SendOpenUrl_Callback(HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult)
+{
+ if (NULL != dwData)
+ free((void*)dwData);
+}
+
+HRESULT ApplicationCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ case DISP_APPLICATION_CREATETEMPFILE:
+ {
+ IDispatch *tempFile =0;
+ if (pdispparams->cArgs == 1)
+ tempFile = new TempFileCOM(pdispparams->rgvarg[0].bstrVal);
+ else
+ tempFile = new TempFileCOM(0);
+
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_DISPATCH;
+ V_DISPATCH(pvarResult) = tempFile;
+ return S_OK;
+ }
+ case DISP_APPLICATION_DOWNLOADMEDIA:
+ {
+ const wchar_t *url = pdispparams->rgvarg[0].bstrVal;
+ if (url)
+ {
+ const wchar_t *destFileSpec=PathFindFileNameW(url);
+ wchar_t path_to_store[MAX_PATH] = {0};
+ GetPathToStore(path_to_store);
+ wchar_t destfile[MAX_PATH] = {0};
+ wchar_t dlgtitle[256] = {0};
+
+ CreateDirectoryW(path_to_store, NULL);
+
+ PathCombineW(destfile, path_to_store, destFileSpec);
+ httpRetrieveFileW(hMainWindow, AutoChar(url), destfile, getStringW(IDS_DOWNLOADING, dlgtitle,256));
+ LMDB_FILE_ADD_INFOW fi = {const_cast<wchar_t *>(destfile), -1, -1};
+ sendMlIpc(ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi);
+ sendMlIpc(ML_IPC_DB_SYNCDB, 0);
+ }
+ }
+ return S_OK;
+ case DISP_APPLICATION_IDLE:
+ //Idle();
+ return S_OK;
+ case DISP_APPLICATION_GETLANGUAGE:
+ {
+ wchar_t langName[8] = {0};
+ GetLanguage(langName, 8);
+
+ BSTR language = SysAllocString(langName);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = language;
+ return S_OK;
+ }
+ case DISP_APPLICATION_GETCOUNTRY:
+ {
+ wchar_t countryName[8] = {0};
+ GetCountry(countryName, 8);
+
+ BSTR country = SysAllocString(countryName);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = country;
+ return S_OK;
+ }
+ case DISP_APPLICATION_GETLOCALE:
+ {
+ wchar_t countryName[8] = {0};
+ GetCountry(countryName, 8);
+
+ wchar_t langName[8] = {0};
+ GetLanguage(langName, 8);
+
+ wchar_t language_country[16] = {0};
+ StringCchPrintfW(language_country, 16, L"%s-%s", langName, countryName);
+
+ BSTR languageAndCountryCode = SysAllocString(language_country);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = languageAndCountryCode;
+ return S_OK;
+ }
+ case DISP_APPLICATION_ISWINAMPPRO:
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ V_BOOL(pvarResult) = VARIANT_TRUE;
+ return S_OK;
+ }
+ case DISP_APPLICATION_LAUNCHURL:
+ if (pdispparams->cArgs == 1 || pdispparams->cArgs == 2)
+ {
+ if (JSAPI_PARAM_OPTIONAL(pdispparams, 2, boolVal, FALSE) == TRUE)
+ ShellExecuteW(NULL, L"open", JSAPI_PARAM(pdispparams, 1).bstrVal, NULL, L".", 0);
+ else
+ {
+ LPWSTR url = _wcsdup(JSAPI_PARAM(pdispparams, 1).bstrVal);
+ if ( 0 == SendMessageCallback(hMainWindow, WM_WA_IPC, (WPARAM)url, (LPARAM)IPC_OPEN_URL, SendOpenUrl_Callback, (ULONG_PTR)url) &&
+ 0 == QueueUserAPC(OpenURLAPC, hMainThread, (ULONG_PTR)url))
+ {
+ free(url);
+ }
+ }
+
+ return S_OK;
+ }
+ else
+ return DISP_E_BADPARAMCOUNT;
+ case DISP_APPLICATION_VERSION:
+ {
+ AutoWide versionW(APP_VERSION);
+ BSTR versionB = SysAllocString(versionW);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = versionB;
+ return S_OK;
+ }
+ case DISP_APPLICATION_SPECIALBUILD:
+ {
+ BSTR special = SysAllocString(SPECIAL_BUILD_NAME);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = special;
+ return S_OK;
+ }
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP ApplicationCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG ApplicationCOM::AddRef(void)
+{
+ return 0;
+}
+
+ULONG ApplicationCOM::Release(void)
+{
+ return 0;
+}
+
+void ApplicationCOM::Idle()
+{
+ WASABI_API_APP->app_messageLoopStep();
+} \ No newline at end of file
diff --git a/Src/Winamp/ApplicationCOM.h b/Src/Winamp/ApplicationCOM.h
new file mode 100644
index 00000000..88c8739e
--- /dev/null
+++ b/Src/Winamp/ApplicationCOM.h
@@ -0,0 +1,23 @@
+#ifndef NULLSOFT_APPLICATIONCOM_H
+#define NULLSOFT_APPLICATIONCOM_H
+
+#include <ocidl.h>
+
+class ApplicationCOM : public IDispatch
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ void Idle();
+
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/BookmarksCOM.cpp b/Src/Winamp/BookmarksCOM.cpp
new file mode 100644
index 00000000..10a2b3f2
--- /dev/null
+++ b/Src/Winamp/BookmarksCOM.cpp
@@ -0,0 +1,134 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "BookmarksCOM.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+#include "api.h"
+
+enum
+{
+ DISP_BOOKMARK_ADD = 777,
+ DISP_BOOKMARK_GETXML,
+};
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT BookmarksCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("Add", DISP_BOOKMARK_ADD)
+ CHECK_ID("GetXML", DISP_BOOKMARK_GETXML)
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT BookmarksCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT BookmarksCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+void Bookmark_WriteAsXML(const wchar_t *filename, int max);
+
+HRESULT BookmarksCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ case DISP_BOOKMARK_ADD:
+ switch (pdispparams->cArgs)
+ {
+ case 1:
+ {
+ Bookmark_additem(pdispparams->rgvarg[0].bstrVal,
+ pdispparams->rgvarg[0].bstrVal);
+ return S_OK;
+ }
+ case 2:
+ {
+ Bookmark_additem(pdispparams->rgvarg[1].bstrVal,
+ pdispparams->rgvarg[0].bstrVal);
+ return S_OK;
+ }
+ }
+ break;
+
+ case DISP_BOOKMARK_GETXML:
+ {
+ int max=0;
+ if (pdispparams->cArgs == 1)
+ {
+ max = _wtoi(pdispparams->rgvarg[0].bstrVal);
+ }
+ wchar_t tempPath[MAX_PATH] = {0};
+ GetTempPathW(MAX_PATH, tempPath);
+ wchar_t tempFile[MAX_PATH] = {0};
+ GetTempFileNameW(tempPath, L"bmx.b4s", 0, tempFile);
+ Bookmark_WriteAsXML(tempFile, max);
+
+ HANDLE plFile = CreateFileW(tempFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+ size_t flen = SetFilePointer(plFile, 0, NULL, FILE_END);
+ SetFilePointer(plFile, 0, NULL, FILE_BEGIN);
+
+ SAFEARRAY *bufferArray=SafeArrayCreateVector(VT_UI1, 0, (ULONG)flen);
+ void *data = 0;
+ SafeArrayAccessData(bufferArray, &data);
+ DWORD bytesRead = 0;
+ ReadFile(plFile, data, (DWORD)flen, &bytesRead, 0);
+ SafeArrayUnaccessData(bufferArray);
+ CloseHandle(plFile);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_ARRAY|VT_UI1;
+ V_ARRAY(pvarResult) = bufferArray;
+ DeleteFileW(tempFile);
+ }
+ return S_OK;
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP BookmarksCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG BookmarksCOM::AddRef(void)
+{
+ return 0;
+}
+
+ULONG BookmarksCOM::Release(void)
+{
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/BookmarksCOM.h b/Src/Winamp/BookmarksCOM.h
new file mode 100644
index 00000000..78bce1dc
--- /dev/null
+++ b/Src/Winamp/BookmarksCOM.h
@@ -0,0 +1,21 @@
+#ifndef NULLSOFT_BOOKMARKSCOM_H
+#define NULLSOFT_BOOKMARKSCOM_H
+
+#include <ocidl.h>
+
+class BookmarksCOM : public IDispatch
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/BoolAttribute.cpp b/Src/Winamp/BoolAttribute.cpp
new file mode 100644
index 00000000..7fbcc5df
--- /dev/null
+++ b/Src/Winamp/BoolAttribute.cpp
@@ -0,0 +1,87 @@
+#include "main.h"
+#include "attributes.h"
+
+_bool_base::_bool_base() : value(false) {}
+
+bool _bool_base::GetBool()
+{
+ return value;
+}
+
+void _bool_base::SetBool(bool boolValue)
+{
+ value = boolValue;
+}
+
+intptr_t _bool_base::GetInt()
+{
+ return value ? 1 : 0;
+}
+
+void _bool_base::SetInt(intptr_t intValue)
+{
+ value = !!intValue;
+}
+
+_bool_base::operator intptr_t()
+{
+ return GetInt();
+}
+
+intptr_t _bool_base::operator =(intptr_t intValue)
+{
+ value = !!intValue;
+ return GetInt();
+}
+
+bool _bool_base::operator =(bool boolValue)
+{
+ value = boolValue;
+ return GetBool();
+}
+
+
+_bool_base::operator bool()
+{
+ return value;
+}
+
+_bool_base::operator UINT()
+{
+ return value?1:0;
+}
+
+bool _bool_base::operator !()
+{
+ return !value;
+}
+
+/* --------------------- */
+
+_bool::_bool(bool defaultValue)
+{
+ value = defaultValue;
+}
+
+#define CBCLASS _bool
+START_DISPATCH;
+CB(IFC_CONFIGITEM_GETBOOL, GetBool)
+CB(IFC_CONFIGITEM_GETINT, GetInt)
+END_DISPATCH;
+#undef CBCLASS
+
+/* --------------------- */
+
+_mutable_bool::_mutable_bool(bool defaultValue)
+{
+ value = defaultValue;
+}
+
+#define CBCLASS _mutable_bool
+START_DISPATCH;
+CB(IFC_CONFIGITEM_GETBOOL, GetBool)
+CB(IFC_CONFIGITEM_GETINT, GetInt)
+VCB(IFC_CONFIGITEM_SETINT, SetInt)
+VCB(IFC_CONFIGITEM_SETBOOL, SetBool)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/Browser.cpp b/Src/Winamp/Browser.cpp
new file mode 100644
index 00000000..5808bae1
--- /dev/null
+++ b/Src/Winamp/Browser.cpp
@@ -0,0 +1,368 @@
+#include "Main.h"
+#include "Browser.h"
+#include "menuv5.h"
+#include "ExternalCOM.h"
+#include "wa_dlg.h"
+#include "resource.h"
+#include "../nu/ns_wc.h"
+
+Browser *browser = 0;
+static WNDPROC oldBrowserProc = 0;
+static DWORD browserThreadId=0;
+static HANDLE killBrowserEvent=0;
+static HANDLE browserThreadHandle=0;
+static BOOL fUnicode = FALSE;
+static LRESULT WINAPI BrowserSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_PAINT:
+ {
+ HDC out = GetDC(hwnd);
+ RECT r;
+ GetClientRect(hwnd, &r);
+ r.left = 11;
+ r.top = 20;
+ r.right -= 8;
+ r.bottom -= 14;
+
+ HBRUSH b = CreateSolidBrush(WADlg_getColor(WADLG_WNDBG));
+ FillRect(out, &r, b);
+ DeleteObject(b);
+ ValidateRect(hwnd, &r);
+ }
+ break;
+
+ case WM_USER + 0x100:
+ if (wParam == 1 && lParam)
+ {
+ config_si_wx = ((POINT *)lParam)->x;
+ config_si_wy = ((POINT *)lParam)->y;
+ }
+ break;
+
+ case WM_USER + 0x101:
+ if (wParam == 1 && lParam)
+ {
+ config_si_width = ((POINT *)lParam)->x;
+ config_si_height = ((POINT *)lParam)->y;
+ }
+ break;
+
+ case WM_USER + 0x102:
+ {
+ if (wParam == 1)
+ {
+ if (!config_minimized)
+ ShowWindow(browser->m_hwnd, SW_SHOW);
+ config_si_open = 1;
+ const char *url = PlayList_getbrowser(PlayList_getPosition());
+ if (url && *url)
+ browser->NavigateToName(url);
+ }
+ else
+ {
+ ShowWindow(browser->m_hwnd, SW_HIDE);
+ config_si_open = 0;
+ }
+ browser->SetMenuCheckMark();
+ }
+ break;
+
+ case WM_USER + 101:
+ {
+ ShowWindow(hwnd, SW_HIDE);
+ ShowWindow(browser->m_hwnd, SW_HIDE);
+ config_si_open = 0;
+ browser->SetMenuCheckMark();
+ return 0;
+ }
+ break;
+
+ case WM_DESTROY:
+ browser->m_hwnd = 0;
+ SetEvent(killBrowserEvent);
+ return 0;
+ }
+
+ if (oldBrowserProc) return (fUnicode) ? CallWindowProcW(oldBrowserProc, hwnd, msg, wParam, lParam) : CallWindowProcA(oldBrowserProc, hwnd, msg, wParam, lParam);
+ else return (fUnicode) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam);
+}
+// {25CE50EF-3EE2-4356-A638-6E495C44BFB8}
+static const GUID StationInfoGUID =
+{ 0x25ce50ef, 0x3ee2, 0x4356, { 0xa6, 0x38, 0x6e, 0x49, 0x5c, 0x44, 0xbf, 0xb8 } };
+
+Browser::Browser()
+: minimised(false), threadId(0), state(0)
+{
+}
+
+Browser::~Browser()
+{
+}
+
+HWND Browser::CreateHWND()
+{
+ if (!m_hwnd)
+ {
+ threadId = GetCurrentThreadId();
+
+ state.flags = EMBED_FLAGS_NOWINDOWMENU;
+ state.me = 0;
+ state.r.left = config_si_wx;
+ state.r.right = config_si_wx + config_si_width;
+ state.r.top = config_si_wy;
+ state.r.bottom = config_si_wy + config_si_height;
+
+ state.flags |= EMBED_FLAGS_GUID;
+ void *blah = state.extra_data+4;
+ memcpy(blah, &StationInfoGUID, sizeof(GUID));
+
+ HWND owner = (HWND)SendMessage(hMainWindow, WM_WA_IPC, (WPARAM)&state, IPC_GET_EMBEDIF);
+
+ m_hwnd = owner;
+ setLocation(11, 20, config_si_width - 19, config_si_height - 34);
+ fUnicode = IsWindowUnicode(owner);
+ oldBrowserProc = (WNDPROC) ((fUnicode) ? SetWindowLongPtrW(owner, GWLP_WNDPROC, (LONG_PTR)BrowserSubclassProc) :
+ SetWindowLongPtrA(owner, GWLP_WNDPROC, (LONG_PTR)BrowserSubclassProc));
+ wchar_t langBuf[1024];
+ SetWindowTextW(owner, getStringW(IDS_STATIONINFOCAPTION, langBuf, 1024));
+ }
+ EnableMenuItem(main_menu, WINAMP_BROWSER_ID, MF_BYCOMMAND | MF_ENABLED);
+
+ if (config_si_autoshow || (config_si_open/* && !visible*/))
+ {
+ if(g_showcode!=SW_SHOWMINIMIZED && !config_minimized)
+ ShowWindow(m_hwnd, SW_SHOW);
+ else
+ browser->minimised = 1;
+ config_si_open = 1;
+ browser->SetMenuCheckMark();
+ }
+
+ return m_hwnd;
+}
+
+// ---------------------------------------------------------------
+void Browser::NavigateToName(LPCTSTR pszUrl)
+{
+ if (!config_si_open)
+ return ;
+ if (!m_pweb) return ;
+ DWORD dwChars = lstrlen (pszUrl) + 1;
+ LPWSTR pwszUrl = (LPWSTR)LocalAlloc (LPTR, dwChars * sizeof (WCHAR));
+ long moptions = navNoReadFromCache | navNoWriteToCache | navNoHistory;
+ VARIANT options;
+ memset( (void*)&options, 0, sizeof(VARIANT));
+ V_VT(&options) = VT_I4;
+ V_I4(&options) = moptions;
+ if (pwszUrl)
+ {
+ MultiByteToWideCharSZ(CP_ACP, 0, pszUrl, -1, pwszUrl, dwChars);
+ m_pweb->Navigate (pwszUrl, &options , 0, 0, 0);
+ LocalFree (pwszUrl);
+ }
+}
+
+#define VIDEO_GENFF_SIZEREQUEST (WM_USER+2048)
+void Browser::Resized(unsigned long width, unsigned long height)
+{
+ if (!config_si_autosize)
+ return ;
+ setLocation(11, 20, width, height);
+ config_si_width = width + 19;
+ config_si_height = height + 34;
+ if (GetParent(m_hwnd))
+ SendMessage(GetParent(m_hwnd), VIDEO_GENFF_SIZEREQUEST, width, height);
+ else
+ SetWindowPos(m_hwnd, 0, 0, 0, width + 19, height + 34, SWP_NOMOVE | SWP_ASYNCWINDOWPOS);
+
+ InvalidateRect(m_hwnd, NULL, TRUE);
+}
+
+HRESULT Browser::GetExternal(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
+{
+ *ppDispatch = (IDispatch *) & externalCOM;
+ return S_OK;
+}
+
+void Browser::ToggleVisible(int showing)
+{
+ if ((!config_si_open && !showing) || (showing && minimised))
+ {
+ if(minimised) minimised = 0;
+ CreateHWND();
+ if (m_hwnd)
+ PostMessage(m_hwnd, WM_USER + 0x102, 1, 0);
+ }
+ else if(!showing)
+ {
+ if(minimised) minimised = 0;
+ if (m_hwnd)
+ PostMessage(m_hwnd, WM_USER + 0x102, 0, 0);
+ }
+}
+
+void Browser::OnNavigateComplete()
+{
+ setVisible(TRUE);
+ RECT r;
+ GetClientRect(m_hwnd, &r);
+ setLocation(11, 20, r.right - 19, r.bottom - 34);
+}
+
+void Browser::SetMenuCheckMark()
+{
+ MENUITEMINFO i = {sizeof(i), MIIM_STATE , MFT_STRING, config_si_open ? MFS_CHECKED : MFS_UNCHECKED, WINAMP_BROWSER_ID};
+ SetMenuItemInfo(main_menu, WINAMP_BROWSER_ID, FALSE, &i);
+}
+
+/* ---- APCs ---- */
+VOID CALLBACK ToggleVisibleAPC(ULONG_PTR param)
+{
+ browser->ToggleVisible(param);
+}
+
+VOID CALLBACK SetVisibleAPC(ULONG_PTR param)
+{
+ BOOL visible = (BOOL)param;
+ browser->setVisible(visible);
+}
+
+VOID CALLBACK NavigateAPC(ULONG_PTR param)
+{
+ char *url = (char *)param;
+ browser->NavigateToName(url);
+ free(url);
+}
+
+VOID CALLBACK CreateHWNDAPC(ULONG_PTR param)
+{
+ browser->CreateHWND();
+}
+
+HANDLE browserEvent=0;
+/* ---- ---- */
+static DWORD CALLBACK BrowserThread(LPVOID param)
+{
+ if (!browser)
+ browser = new Browser;
+ killBrowserEvent = CreateEvent(0, TRUE, FALSE, 0);
+ SetEvent(browserEvent);
+
+ while (1)
+ {
+ DWORD dwStatus = MsgWaitForMultipleObjectsEx(1, &killBrowserEvent,
+ INFINITE, QS_ALLINPUT,
+ MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+ if (dwStatus == WAIT_OBJECT_0)
+ {
+ browser->remove();
+ browser->close();
+ browser->Release();
+ CloseHandle(killBrowserEvent);
+ return 0;
+ }
+ else if (dwStatus == WAIT_OBJECT_0 + 1)
+ {
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT)
+ {
+ browser->remove();
+ browser->close();
+ browser->Release();
+ CloseHandle(killBrowserEvent);
+ return 0;
+ }
+ if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN ||
+ msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP)
+ {
+ if (!browser->translateKey(&msg))
+ {
+ PostMessage(hMainWindow, msg.message, msg.wParam, msg.lParam);
+ }
+ }
+ else
+ {
+ if (!browser->translateKey(&msg))
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static void CreateBrowser()
+{
+ if (!browser)
+ {
+ browserEvent = CreateEvent(0, TRUE, FALSE, 0);
+ browserThreadHandle = CreateThread(0, 0, BrowserThread, 0, 0, &browserThreadId);
+ WaitForSingleObject(browserEvent, INFINITE);
+ }
+}
+
+static void CallAPC(PAPCFUNC func, ULONG_PTR param)
+{
+ if (browserThreadHandle)
+ {
+ DWORD curThreadId = GetCurrentThreadId();
+ if (curThreadId == browserThreadId)
+ func(param);
+ else
+ {
+ QueueUserAPC(func, browserThreadHandle, param);
+ }
+ }
+}
+
+void Browser_toggleVisible(int showing)
+{
+ CreateBrowser();
+ CallAPC(ToggleVisibleAPC, showing);
+}
+
+void CloseBrowser()
+{
+ if (!browser || !browser->m_hwnd)
+ return ;
+ if (config_si_autohide)
+ PostMessage(browser->m_hwnd, WM_USER + 0x102, 0, 0);
+ else
+ CallAPC(SetVisibleAPC, FALSE);
+}
+
+void LaunchBrowser(const char *url)
+{
+ OpenBrowser();
+ CallAPC(NavigateAPC, (ULONG_PTR)_strdup(url));
+}
+
+void OpenBrowser()
+{
+ CreateBrowser();
+ CallAPC(CreateHWNDAPC, 0);
+}
+
+void Browser_init()
+{
+ MENUITEMINFO i = {sizeof(i), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING, MFS_UNCHECKED, WINAMP_BROWSER_ID};
+ i.dwTypeData = getString(IDS_STATIONINFO_MENU,NULL,0);;
+ InsertMenuItem(main_menu, 10 + g_mm_optionsbase_adj, TRUE, &i);
+ g_mm_optionsbase_adj++;
+}
+
+void Browser_kill()
+{
+ if (browserThreadHandle)
+ {
+ SetEvent(killBrowserEvent); // just in case, so we don't hang here
+ WaitForSingleObject(browserThreadHandle, INFINITE);
+ CloseHandle(browserThreadHandle);
+ browserThreadHandle=0;
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/Browser.h b/Src/Winamp/Browser.h
new file mode 100644
index 00000000..47848859
--- /dev/null
+++ b/Src/Winamp/Browser.h
@@ -0,0 +1,42 @@
+#ifndef NULLSOFT_BROWSERH
+#define NULLSOFT_BROWSERH
+
+#include "../nu/HTMLContainer.h"
+#include "wa_ipc.h"
+
+class Browser : public HTMLContainer
+{
+public:
+ Browser();
+ ~Browser();
+ static WNDCLASS *wc;
+ static HRESULT CALLBACK WindowProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void NavigateToName(LPCTSTR pszUrl);
+ void Resized(unsigned long width, unsigned long height);
+ STDMETHOD (GetExternal)(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch);
+ void ToggleVisible(int showing);
+ embedWindowState state;
+ bool minimised;
+ void SetMenuCheckMark();
+ virtual void OnNavigateComplete();
+ HWND CreateHWND();
+ DWORD threadId;
+};
+
+class UpdateBrowser : public HTMLContainer
+{
+public:
+ HWND CreateHWND();
+ static WNDCLASS *wc;
+ static HRESULT CALLBACK WindowProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void NavigateToName(LPCTSTR pszUrl);
+ void Resized(unsigned long width, unsigned long height);
+ STDMETHOD (GetExternal)(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch);
+ embedWindowState state;
+ virtual void OnNavigateComplete();
+
+};
+
+HRESULT UpdateWindow_Show(LPCSTR pszUrl);
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/BrowserCOM.cpp b/Src/Winamp/BrowserCOM.cpp
new file mode 100644
index 00000000..c6764ec3
--- /dev/null
+++ b/Src/Winamp/BrowserCOM.cpp
@@ -0,0 +1,101 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "BrowserCOM.h"
+#include "Browser.h"
+#include "../nu/AutoChar.h"
+
+//extern Browser *browser;
+extern UpdateBrowser *updateBrowser;
+enum
+{
+ DISP_BROWSER_SETSIZE = 777,
+ DISP_BROWSER_SETTITLE,
+ DISP_BROWSER_SETUPDATESIZE,
+ DISP_BROWSER_HIDDEN,
+};
+
+#define CHECK_ID(str, id) if (wcscmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; }
+HRESULT BrowserCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ //CHECK_ID("SetSize", DISP_BROWSER_SETSIZE)
+ CHECK_ID("SetUpdateSize", DISP_BROWSER_SETUPDATESIZE)
+ //CHECK_ID("SetTitle", DISP_BROWSER_SETTITLE)
+ //CHECK_ID("hidden", DISP_BROWSER_HIDDEN)
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT BrowserCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT BrowserCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+
+HRESULT BrowserCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+
+ case DISP_BROWSER_SETUPDATESIZE:
+ if (pdispparams->cArgs == 2 && updateBrowser)
+ {
+ updateBrowser->Resized(pdispparams->rgvarg[1].lVal, pdispparams->rgvarg[0].lVal);
+ return S_OK;
+ }
+ break;
+
+
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP BrowserCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+
+ULONG BrowserCOM::AddRef(void)
+{
+ return 0;
+}
+
+ULONG BrowserCOM::Release(void)
+{
+ return 0;
+}
diff --git a/Src/Winamp/BrowserCOM.h b/Src/Winamp/BrowserCOM.h
new file mode 100644
index 00000000..19b9d5dc
--- /dev/null
+++ b/Src/Winamp/BrowserCOM.h
@@ -0,0 +1,21 @@
+#ifndef NULLSOFT_BROWSERCOMH
+#define NULLSOFT_BROWSERCOMH
+
+#include <ocidl.h>
+
+class BrowserCOM : public IDispatch
+{
+public:
+
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/BurnManager.cpp b/Src/Winamp/BurnManager.cpp
new file mode 100644
index 00000000..fa0adaa7
--- /dev/null
+++ b/Src/Winamp/BurnManager.cpp
@@ -0,0 +1,67 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "../Agave/DecodeFile/ifc_audiostream.h"
+#include "../Agave/DecodeFile/api_decodefile.h"
+
+#include "./BurnManager.h"
+
+BurnManager::BurnManager(void) : decodeFile(NULL), context(NULL)
+{
+}
+
+BurnManager::~BurnManager()
+{
+}
+
+void BurnManager::SetDecodeAPI(api_decodefile *decoderAPI)
+{
+ decodeFile = decoderAPI;
+}
+
+api_decodefile *BurnManager::GetDecodeAPI(void)
+{
+ return decodeFile;
+}
+void BurnManager::SetFiles(size_t numFiles, const wchar_t **filenames, BurnManagerCallback *callback)
+{
+ WRESULT *results = new WRESULT[numFiles];
+ memset(results, 0, numFiles * sizeof(WRESULT));
+ callback->OnLicenseCallback(numFiles, results);
+ delete [] results;
+}
+
+ifc_audiostream* BurnManager::CreateDecoder(const wchar_t *filename)
+{
+ AudioParameters parameters;
+ parameters.bitsPerSample = 16;
+ parameters.channels = 2;
+ parameters.sampleRate = 44100;
+
+ ifc_audiostream *decoder = decodeFile->OpenAudio(filename, &parameters);
+ if (decoder && (parameters.bitsPerSample != 16 || parameters.channels != 2 || parameters.sampleRate != 44100))
+ {
+ parameters.errorCode = API_DECODEFILE_BAD_RESAMPLE;
+ decodeFile->CloseAudio(decoder);
+ decoder=0;
+ }
+ return decoder;
+}
+
+void BurnManager::CloseDecoder(ifc_audiostream *decoder)
+{
+ decodeFile->CloseAudio(decoder);
+}
+
+void BurnManager::CancelBurn()
+{
+}
+
+void BurnManager::BurnFinished()
+{
+}
+
diff --git a/Src/Winamp/BurnManager.h b/Src/Winamp/BurnManager.h
new file mode 100644
index 00000000..5808a925
--- /dev/null
+++ b/Src/Winamp/BurnManager.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "../Agave/DecodeFile/ifc_audiostream.h"
+#include "../Agave/DecodeFile/api_decodefile.h"
+
+#include "../burnlib/manager.h" \ No newline at end of file
diff --git a/Src/Winamp/CommonReader.h b/Src/Winamp/CommonReader.h
new file mode 100644
index 00000000..f1982267
--- /dev/null
+++ b/Src/Winamp/CommonReader.h
@@ -0,0 +1,10 @@
+#ifndef NULLSOFT_WINAMP_COMMONREADER_H
+#define NULLSOFT_WINAMP_COMMONREADER_H
+
+class CommonReader : public ifc_audiostream
+{
+public:
+ virtual ~CommonReader() {}
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Config.cpp b/Src/Winamp/Config.cpp
new file mode 100644
index 00000000..1a5199ad
--- /dev/null
+++ b/Src/Winamp/Config.cpp
@@ -0,0 +1,1251 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author:
+** Created:
+**/
+
+#ifndef CONFIG_IMPL
+#define CONFIG_IMPL
+#endif
+#include "Main.h"
+#include "config.h"
+#include "WinampAttributes.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+#include "../nu/AutoLock.h"
+#include "../nu/AutoCharFn.h"
+#include "../Elevator/FileTypeRegistrar.h"
+#include "main.hpp"
+#include <shobjidl.h>
+
+#if (_MSC_VER < 1500)
+typedef struct tagBIND_OPTS3 : tagBIND_OPTS2
+{
+ HWND hwnd;
+} BIND_OPTS3, * LPBIND_OPTS3;
+#endif
+static HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, void ** ppv)
+{
+ BIND_OPTS3 bo;
+ WCHAR wszCLSID[50] = {0};
+ WCHAR wszMonikerName[300] = {0};
+
+ StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0]));
+ HRESULT hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
+ if (FAILED(hr))
+ return hr;
+ memset(&bo, 0, sizeof(bo));
+ bo.cbStruct = sizeof(bo);
+ bo.hwnd = hwnd;
+ bo.dwClassContext = CLSCTX_LOCAL_SERVER;
+ return CoGetObject(wszMonikerName, &bo, riid, ppv);
+}
+
+static bool NeedElevation()
+{
+ return !IsUserAnAdmin();
+}
+
+static Nullsoft::Utility::LockGuard registrarGuard;
+static const GUID ftr_guid =
+ { 0x3B29AB5C, 0x52CB, 0x4a36, { 0x93,0x14,0xE3,0xFE,0xE0,0xBA,0x74,0x68 } };
+static IFileTypeRegistrar *masterRegistrar;
+static FileTypeRegistrar builtIn;
+bool usingBuiltIn = false;
+int GetRegistrar(IFileTypeRegistrar **registrar, BOOL use_fallback)
+{
+ Nullsoft::Utility::AutoLock autolock(registrarGuard);
+ // attempt to re-get an elevated object as needed
+ // i.e. if user selects no but wants to try again
+ // then we need to try going elevated again
+ if (!masterRegistrar || usingBuiltIn)
+ {
+#if 1 // benski> on Vista, we need this object to run out-of-process so it can be elevated to Administrator
+ // without elevating Winamp itself - see http://msdn2.microsoft.com/en-us/ms679687.aspx
+ OSVERSIONINFO version = {0};
+ version.dwOSVersionInfoSize = sizeof(version);
+ if (!GetVersionEx(&version)) ZeroMemory(&version, sizeof(OSVERSIONINFO));
+ if (version.dwMajorVersion >= 6 && NeedElevation()) // Vista
+ {
+ IFileTypeRegistrar *registrar = 0;
+ HRESULT hr = CoCreateInstanceAsAdmin(0, ftr_guid, __uuidof(IFileTypeRegistrar), (void**)&registrar);
+ if (SUCCEEDED(hr) && registrar)
+ {
+ if (masterRegistrar) masterRegistrar->Release();
+ masterRegistrar = registrar;
+ usingBuiltIn = false;
+ }
+ else
+ {
+ if (!use_fallback)
+ {
+ if (registrar) registrar->Release();
+ if (masterRegistrar) masterRegistrar->Release();
+ registrar = masterRegistrar = 0;
+ usingBuiltIn = false;
+ return 1;
+ }
+ }
+ }
+#if 0
+ else /* benski> on earlier OS's just for testing purposes, we'll get rid of this totally once the COM stuff is worked out */
+ {
+ CoCreateInstance(ftr_guid, NULL, CLSCTX_LOCAL_SERVER, __uuidof(IFileTypeRegistrar), (void**)&masterRegistrar);
+ }
+#endif
+#endif
+ }
+
+ if (!masterRegistrar) /* wasn't registered? we'll use our internal version (but it won't work well on Vista+) */
+ {
+ masterRegistrar = &builtIn;
+ usingBuiltIn = true;
+ }
+
+ if (masterRegistrar)
+ {
+ *registrar = masterRegistrar;
+ masterRegistrar->AddRef();
+ return 0;
+ }
+ return 1;
+}
+
+void RemoveRegistrar()
+{
+ Nullsoft::Utility::AutoLock autolock(registrarGuard);
+ if (masterRegistrar) masterRegistrar->Release();
+ masterRegistrar = 0;
+ usingBuiltIn = false;
+}
+
+int _r_i(char *name, int def)
+{
+ return GetPrivateProfileIntA(app_name, name, def, INI_FILEA);
+}
+
+#define RI(x) (( config_##x ) = _r_i(#x,( config_##x )))
+#define RI_NP(x) (( x ) = _r_i(#x,( x )))
+#define RB(x) (( config_##x ) = !!_r_i(#x,( config_##x )))
+void _w_i(char *name, intptr_t d)
+{
+ char str[120] = {0};
+ StringCchPrintfA(str, 120, "%d", d);
+ WritePrivateProfileStringA(app_name, name, str, INI_FILEA);
+}
+#define WI(x) _w_i(#x,( config_##x ))
+#define WI_NP(x) _w_i(#x,( x ))
+
+void _r_s(char *name, char *data, int mlen)
+{
+ char utf8_data[2048] = {0};
+ wchar_t utf16_data[2048] = {0};
+ char buf[2048] = {0};
+ StringCchCopyA(buf, 2048, data);
+ GetPrivateProfileStringA(app_name, name, buf, utf8_data, 2048, INI_FILEA);
+ MultiByteToWideCharSZ(CP_UTF8, 0, utf8_data, -1, utf16_data, 2048);
+ WideCharToMultiByteSZ(CP_ACP, 0, utf16_data, -1, data, mlen, 0, 0);
+}
+#define RS(x) (_r_s(#x,config_##x,sizeof(config_##x)))
+#define RS_NP(x) (_r_s(#x,x,sizeof(x)))
+
+void _r_sW(const char *name, wchar_t *data, int mlen)
+{
+ char utf8_data[2048] = {0};
+ char default_data[2048] = {0};
+ WideCharToMultiByteSZ(config_utf8?CP_UTF8:CP_ACP, 0, data, -1, default_data, 2048,0,0);
+ GetPrivateProfileStringA(app_name, name, default_data, utf8_data, 2048, INI_FILEA);
+ MultiByteToWideCharSZ(config_utf8?CP_UTF8:CP_ACP, 0, utf8_data, -1, data, mlen);
+}
+#define RSW(x) (_r_sW(#x,config_##x,sizeof(config_##x)/sizeof(wchar_t)))
+#define RSW_NP(x) (_r_sW(#x,x,sizeof(x)/sizeof(wchar_t)))
+
+void _w_s(char *name, char *data)
+{
+ WritePrivateProfileStringA(app_name, name, AutoChar(AutoWide(data), CP_UTF8), INI_FILEA);
+}
+#define WS(x) (_w_s(#x,config_##x))
+#define WS_NP(x) (_w_s(#x,x))
+
+void _w_sW(const char *name, const wchar_t *data)
+{
+ WritePrivateProfileStringA(app_name, name, AutoChar(data, CP_UTF8), INI_FILEA); // TODO: don't want autowide here
+}
+#define WSW(x) (_w_sW(#x,config_##x))
+#define WSW_NP(x) (_w_sW(#x,x))
+
+
+void config_write(int i)
+{
+ config_pilp = PlayList_getPosition();
+ //GetCurrentDirectoryW(MAX_PATH, config_cwd);
+ if (i && plneedsave)
+ {
+ // changed 5.64 to only save if there was a change as this can save a
+ // decent amount of time on closing with a large unmodified playlist.
+ savem3ufn(M3U_FILE, 0, 1);
+ savem3ufn(OLD_M3U_FILE, 0, 1);
+ }
+
+ config_utf8=1;
+ WI(utf8);
+
+ if (i != 1) // write mostly unused stuff, like proxy, plugin names, etc
+ {
+ WS(defext);
+ WSW(titlefmt);
+ WI(proxy80);
+ WS(proxy);
+ WSW(visplugin_name);
+ WSW(dspplugin_name);
+ WI(check_ft_startup);
+ WI(updated_ft_startup);
+ WI(visplugin_num);
+ WI(pe_fontsize);
+ WI(pe_direction);
+ WI(visplugin_priority);
+ WI(visplugin_autoexec);
+ WI(dspplugin_num);
+ WI(sticon);
+ WI(splash);
+ WI(taskbar);
+ WI(dropaotfs);
+ WI(nomwheel);
+ WI(ascb_new);
+ WI(ttips);
+ WI(riol);
+ WI(minst);
+ WI(whichicon);
+ WI(whichicon2);
+ WI(addtolist);
+ WI(snap);
+ WI(snaplen);
+ WI(parent);
+ WI(hilite);
+ WI(disvis);
+ WI(rofiob);
+ WI(shownumsinpl);
+ WI(keeponscreen);
+ WI(eqdsize);
+ WI(usecursors);
+ WI(fixtitles);
+ WI(priority);
+ WI(shuffle_morph_rate);
+ WI(useexttitles);
+ WI(bifont);
+ WI(bifont_alt);
+ WI(dotitlenum);
+ WI(dotasknum);
+ WI(plscrollsize);
+ WI(plmw2xscroll);
+ WI(inet_mode);
+ WI(ospb);
+ WI(embedwnd_freesize);
+ WI(no_visseh);
+ }
+ WI(newverchk);
+ WI(newverchk2);
+ WI(newverchk3);
+ WI(newverchk_rc);
+ WI(user_consent_join_channels);
+ // write everything else
+ {
+ int config_prefs_last_page = prefs_last_page | (about_lastpage << 8);
+ WI(prefs_last_page);
+ prefs_last_page &= 255;
+
+ _w_i("prefs_wx", prefs_rect.left);
+ _w_i("prefs_wy", prefs_rect.top);
+
+ _w_i("alt3_wx", alt3_rect.left);
+ _w_i("alt3_wy", alt3_rect.top);
+
+ _w_i("editinfo_wx", editinfo_rect.left);
+ _w_i("editinfo_wy", editinfo_rect.top);
+
+ _w_i("ctrle_wx", ctrle_rect.left);
+ _w_i("ctrle_wy", ctrle_rect.top);
+
+ _w_i("about_wx", about_rect.left);
+ _w_i("about_wy", about_rect.top);
+
+ _w_i("loc_wx", loc_rect.left);
+ _w_i("loc_wy", loc_rect.top);
+
+ _w_i("time_wx", time_rect.left);
+ _w_i("time_wy", time_rect.top);
+
+ _w_i("load_wx", load_rect.left);
+ _w_i("load_wy", load_rect.top);
+ }
+ WI(autoload_eq);
+ WI(playlist_recyclebin);
+ WI(use_eq);
+ WI(eq_ws);
+ WI(wx);
+ WI(wy);
+ WI(minimized);
+ WI(aot);
+ WI(shuffle);
+ WI(repeat);
+ WI(volume);
+ WI(pan);
+ WI(easymove);
+ WI(dsize);
+ WI(timeleftmode);
+ WI(autoscrollname);
+ WI(sa);
+ WI(safire);
+ WI(saref);
+ WI(safalloff);
+ WI(sa_peaks);
+ WI(sa_peak_falloff);
+ WI(eq_wx);
+ WI(eq_wy);
+ WI(eq_open);
+ WI(mw_open);
+ WI(pe_wx);
+ WI(pe_wy);
+ WI(pe_open);
+ WI(pe_width);
+ WI(pe_height);
+ WI(pe_height_ws);
+
+ WI(eq_limiter);
+ WI(eq_type);
+ WI(eq_frequencies);
+
+ /*
+ WI(si_wx);
+ WI(si_wy);
+ WI(si_width);
+ WI(si_height);
+ WI(si_autoshow);
+ WI(si_autosize);
+ WI(si_autohide);
+ WI(si_open);
+ */
+
+ WI(video_wx);
+ WI(video_wy);
+ WI(video_open);
+ WI(video_width);
+ WI(video_height);
+ WI(video_ratio1);
+ WI(video_ratio2);
+ WI(video_useratio);
+ WI(windowshade);
+ WI(preamp);
+ WI(pilp);
+ WI(randskin);
+ WSW(cwd);
+ WSW(skin);
+ WS(outname);
+ WI(pladv);
+ {
+ char config_eq_data[256] = {0};
+ StringCchPrintfA(config_eq_data, 256, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ eq_tab[0], eq_tab[1], eq_tab[2], eq_tab[3], eq_tab[4],
+ eq_tab[5], eq_tab[6], eq_tab[7], eq_tab[8], eq_tab[9]);
+ WS(eq_data);
+ }
+ WI(video_vsync2);
+ WI(video_aspectadj);
+ WI(video_overlays);
+ WI(video_gdiplus);
+ WI(video_ddraw);
+ WI(video_updsize);
+ WI(video_autoopen);
+ WI(video_autoclose);
+ WI(video_noss);
+ WI(video_logo);
+ WI(video_osd);
+ WI(video_yv12);
+ WI(video_stopclose);
+ WI(video_auto_fs);
+
+ WI(playback_thread_priority);
+ WI(audio_bits);
+ WI(audio_mono);
+ WI(audio_surround);
+ WI(audio_dither);
+ WI(replaygain);
+ WI(replaygain_mode);
+ WI(replaygain_source);
+ WI(replaygain_preferred_only);
+ _w_i("replaygain_non_rg_gain", (intptr_t)(config_replaygain_non_rg_gain.GetFloat()*1000.0f));
+ _w_i("replaygain_preamp", (intptr_t)(config_replaygain_preamp.GetFloat()*1000.0f));
+
+ // WI(video_contrast);
+ // WI(video_brightness);
+ WI(video_fliprgb);
+ WI(video_remove_fs_on_stop);
+ WI(wav_do_header);
+ WI(wav_convert);
+ WS(wav_ext);
+ _w_sW("playlist_custom_font", playlist_custom_fontW);
+ WI(custom_plfont);
+ WI(no_registry);
+ WI(last_classic_skin_page);
+ WI(last_playback_page);
+ WI(last_fileinfo_page);
+ WSW(artwork_filter);
+ WI(zeropadplnum);
+ WI(wlz_menu);
+ WI(accessibility_modalbeep);
+ WI(accessibility_modalflash);
+
+ WI(noml_ratings_prompt);
+ WI(noml_ratings);
+ WI(uid_ft);
+}
+
+void config_read(int i)
+{
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ // regmimetype(L"interface/x-winamp-skin", programname, L".wsz", 0); // hack cause wa3 is gheeeeeey
+
+ RI(utf8);
+ RI(eq_ws);
+ RI(updated_ft_startup);
+ // fiddle things so if running an existing install then we force restore file assoc off
+ // when we're running on Vista / Win7+ to resolve complaints from users on those OSes.
+ // vista
+ if(config_updated_ft_startup)
+ {
+ RI(check_ft_startup);
+ }
+ else
+ {
+ OSVERSIONINFO version = {0};
+ version.dwOSVersionInfoSize = sizeof(version);
+ if (!GetVersionEx(&version)) ZeroMemory(&version, sizeof(OSVERSIONINFO));
+ if (version.dwMajorVersion >= 6) // Vista
+ {
+ config_updated_ft_startup = 0;
+ }
+ else
+ {
+ RI(check_ft_startup);
+ }
+ }
+ config_updated_ft_startup = 1;
+
+ RS(browserbrand);
+ RI(inet_mode);
+ RI(pe_fontsize);
+ RI(pe_direction);
+ RI(ospb);
+ RI(visplugin_num);
+ RI(visplugin_priority);
+ RI(visplugin_autoexec);
+ RI(dspplugin_num);
+ RI(sticon);
+ RI(splash);
+ RI(taskbar);
+ RI(dropaotfs);
+ RI(nomwheel);
+ RI(ascb_new);
+ RI(ttips);
+ RI(keeponscreen);
+ RI(riol);
+ RI(whichicon);
+ RI(whichicon2);
+ RI(addtolist);
+ RI(snap);
+ RI(snaplen);
+ RI(parent);
+ RI(hilite);
+ RI(disvis);
+ RI(minst);
+ RI(eqdsize);
+ RI(pladv);
+ RI(bifont);
+ RI(bifont_alt);
+ RI(autoload_eq);
+ RI(playlist_recyclebin);
+ RI(use_eq);
+ RI(wx);
+ RI(wy);
+ RI(minimized);
+ RI(aot);
+ RI(shuffle);
+ RI(repeat);
+ RI(volume);
+ RI(pan);
+ RI(easymove);
+ RI(dsize);
+ RI(timeleftmode);
+ RI(autoscrollname);
+ RI(sa);
+ RI(safire);
+ RI(saref);
+ RI(safalloff);
+ RI(sa_peaks);
+ RI(sa_peak_falloff);
+ RI(eq_wx);
+ RI(eq_wy);
+ RI(eq_open);
+ RI(mw_open);
+ RI(pe_wx);
+ RI(pe_wy);
+ RI(pe_open);
+ RI(pe_width);
+ RI(pe_height);
+ RI(pe_height_ws);
+
+ RB(eq_limiter);
+ RI(eq_type);
+ RI(eq_frequencies);
+ /*
+ RI(si_wx);
+ RI(si_wy);
+ RI(si_height);
+ RI(si_width);
+ RI(si_autoshow);
+ RI(si_autosize);
+ RI(si_autohide);
+ RI(si_open);
+ */
+
+ RI(video_wx);
+ RI(video_wy);
+ RI(video_open);
+ RI(video_width);
+ RI(video_height);
+ RI(video_ratio1);
+ RI(video_ratio2);
+ RI(video_useratio);
+ RI(windowshade);
+ RI(preamp);
+ RI(pilp);
+ RI(randskin);
+ if (!*config_cwd) // don't read if the user has overridden it through paths.ini
+ RSW(cwd);
+ RSW(skin);
+
+ RI_NP(prefs_last_page);
+ about_lastpage = prefs_last_page >> 8;
+ prefs_last_page &= 255;
+
+ prefs_rect.left = _r_i("prefs_wx", -1);
+ prefs_rect.top = _r_i("prefs_wy", -1);
+
+ alt3_rect.left = _r_i("alt3_wx", -1);
+ alt3_rect.top = _r_i("alt3_wy", -1);
+
+ editinfo_rect.left = _r_i("editinfo_wx", -1);
+ editinfo_rect.top = _r_i("editinfo_wy", -1);
+
+ ctrle_rect.left = _r_i("ctrle_wx", -1);
+ ctrle_rect.top = _r_i("ctrle_wy", -1);
+
+ about_rect.left = _r_i("about_wx", -1);
+ about_rect.top = _r_i("about_wy", -1);
+
+ loc_rect.left = _r_i("loc_wx", -1);
+ loc_rect.top = _r_i("loc_wy", -1);
+
+ time_rect.left = _r_i("time_wx", -1);
+ time_rect.top = _r_i("time_wy", -1);
+
+ load_rect.left = _r_i("load_wx", -1);
+ load_rect.top = _r_i("load_wy", -1);
+
+ RI(rofiob);
+ RI(shownumsinpl);
+ RS(outname);
+ RI(usecursors);
+ RI(fixtitles);
+ RI(priority);
+
+ if (!_r_i("fixpriority", 0))
+ {
+ if (config_priority > 1)
+ {
+ config_priority++;
+ WI(priority);
+ }
+ _w_i("fixpriority", 1);
+ }
+
+ RI(shuffle_morph_rate);
+ RI(useexttitles);
+ RI(newverchk);
+ RI(newverchk2);
+ RI(newverchk3);
+ RI(newverchk_rc);
+ RI(user_consent_join_channels);
+ RI(embedwnd_freesize);
+ RB(video_vsync2);
+ RI(video_aspectadj);
+ RB(video_overlays);
+ RB(video_gdiplus);
+ RB(video_ddraw);
+ RI(video_updsize);
+ RB(video_autoopen);
+ RB(video_autoclose);
+ RI(video_noss);
+ RI(video_logo);
+ RI(video_osd);
+ RB(video_yv12);
+ RI(video_stopclose);
+ RB(video_auto_fs);//RI(video_auto_fs); plague> changed to RB
+ RI(dotitlenum);
+ RI(dotasknum);
+ RI(plscrollsize);
+ RI(plmw2xscroll);
+ RI(playback_thread_priority);
+ RI(audio_bits);
+ RB(audio_mono);
+ RB(audio_surround);
+ RB(audio_dither);
+ RB(replaygain);
+ RI(replaygain_mode);
+ RI(replaygain_source);
+ RB(replaygain_preferred_only);
+ int gain10 = _r_i("replaygain_non_rg_gain", (int)(config_replaygain_non_rg_gain.GetFloat()*1000.0f));
+ config_replaygain_non_rg_gain = (float)((float)gain10/1000.0f);
+ gain10 = _r_i("replaygain_preamp", (int)(config_replaygain_preamp.GetFloat()*1000.0f));
+ config_replaygain_preamp = (float)((float)gain10/1000.0f);
+
+ RI(last_classic_skin_page);
+ RI(last_playback_page);
+ RI(last_fileinfo_page);
+ RI(upd_mode);
+ RSW(artwork_filter);
+
+ RI(noml_ratings_prompt);
+ RI(noml_ratings);
+
+ RI(jtf_check);
+ RI(block_img);
+
+ // RI(video_contrast);
+ // RI(video_brightness);
+ RI(video_fliprgb);
+ RI(video_remove_fs_on_stop);
+ RI(wav_do_header);
+ RI(wav_convert);
+ RS(wav_ext);
+ RI(no_visseh);
+ _r_sW("playlist_custom_font", playlist_custom_fontW, sizeof(playlist_custom_fontW)/sizeof(*playlist_custom_fontW));
+ if (!*playlist_custom_fontW) StringCbCopyW(playlist_custom_fontW, sizeof(playlist_custom_fontW), DEFAULT_FONT);
+ WideCharToMultiByteSZ(CP_ACP, 0, playlist_custom_fontW, -1, playlist_custom_font, 128, 0, 0);
+ RI(custom_plfont);
+ RI(no_registry);
+ RB(proxy80);
+ RS(proxy);
+ RS(defext);
+ RSW(titlefmt);
+ RSW(visplugin_name);
+ RSW(dspplugin_name);
+ RI(zeropadplnum);
+ RI(wlz_menu);
+ RB(accessibility_modalbeep);
+ RB(accessibility_modalflash);
+
+ {
+ char eq_data[256] = {0, };
+ int x;
+ char *p = eq_data;
+ RS_NP(eq_data);
+ for (x = 0; x < 10; x ++)
+ {
+ int b = 0, s = 0;
+ while (p && *p >= '0' && *p <= '9')
+ {
+ s = 1;b = b * 10 + *p++ -'0';
+ }
+ if (!s) break;
+ p++;
+ eq_tab[x] = min(63, max(b, 0));
+ }
+ }
+
+ //SetCurrentDirectoryW(config_cwd);
+
+ config_utf8=1;
+ WI(utf8);
+
+
+ if (!i)
+ {
+ if (!PathFileExistsW(M3U_FILE))
+ {
+ LoadPlaylistByExtension(OLD_M3U_FILE, L".m3u", 1, 1);
+ savem3ufn(M3U_FILE, 0, 1);
+ }
+ else
+ LoadPlaylistByExtension(M3U_FILE, L".m3u8", 1, 1);
+ PlayList_setposition(config_pilp);
+ }
+}
+
+
+int config_isregistered(wchar_t *ext)
+{
+ wchar_t b[256] = {0};
+ DWORD rval = 0, s = sizeof(b);
+
+ if (config_no_registry) return 0;
+
+ if (!ext[0]) return 0;
+ StringCchPrintfW(b, 256, L".%s", ext);
+
+ OSVERSIONINFO version = {0};
+ version.dwOSVersionInfoSize = sizeof(version);
+ if (!GetVersionEx(&version)) ZeroMemory(&version, sizeof(OSVERSIONINFO));
+
+ if (IsWin8()) // Windows 8
+ {
+ // QueryAppIsDefault(..) was deprecated in Windows 8 so this is an alternative
+ // which seems to work though how long it will keep working is currently unknown
+ IApplicationAssociationRegistration* pAAR = 0;
+ HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
+ NULL, CLSCTX_INPROC,
+ __uuidof(IApplicationAssociationRegistration),
+ (void**)&pAAR);
+ if (SUCCEEDED(hr) && pAAR)
+ {
+ LPWSTR app = 0;
+ /*hr = */pAAR->QueryCurrentDefault(b,
+ AT_FILEEXTENSION,
+ AL_EFFECTIVE,
+ &app);
+ pAAR->Release();
+
+ if (IsPlaylistExtension(ext))
+ {
+ if(!lstrcmpiW(WINAMP_PLAYLISTW, app)){ rval = 1; }
+ }
+ else if (!_wcsicmp(ext, L"wsz") || !_wcsicmp(ext, L"wal") || !_wcsicmp(ext, L"wpz"))
+ {
+ if(!lstrcmpiW(WINAMP_SKINZIPW, app)){ rval = 1; }
+ }
+ else if (!_wcsicmp(ext, L"wlz"))
+ {
+ if(!lstrcmpiW(WINAMP_LANGZIPW, app)){ rval = 1; }
+ }
+ else
+ {
+ wchar_t str[64] = {0};
+ StringCchPrintfW(str, 64, L"%s%hs", WINAMP_FILEW, b);
+ if(!lstrcmpiW(str, app)){ rval = 1; }
+ }
+ if (app) CoTaskMemFree(app);
+ }
+ }
+ else if (version.dwMajorVersion >= 6) // Vista
+ {
+ IApplicationAssociationRegistration* pAAR = NULL;
+ HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
+ NULL, CLSCTX_INPROC,
+ __uuidof(IApplicationAssociationRegistration),
+ (void**)&pAAR);
+ if (SUCCEEDED(hr) && pAAR)
+ {
+ BOOL hasExt=FALSE;
+ hr = pAAR->QueryAppIsDefault(b,
+ AT_FILEEXTENSION,
+ AL_EFFECTIVE,
+ AutoWide(app_name),
+ &hasExt);
+ pAAR->Release();
+ if (SUCCEEDED(hr))
+ {
+ rval=!!hasExt;
+ }
+ }
+ }
+ else
+ {
+ HKEY key = NULL;
+ if (RegOpenKeyW(HKEY_CLASSES_ROOT, b, &key) != ERROR_SUCCESS) return 0;
+
+ DWORD vt = 0;
+ if (RegQueryValueExW(key, NULL, 0, &vt, (LPBYTE)b, &s) == ERROR_SUCCESS)
+ {
+ if (vt != REG_SZ || (wcsncmp(b, WINAMP_FILEW, wcslen(WINAMP_FILEW)) &&
+ wcscmp(b, WINAMP_PLAYLISTW) &&
+ wcscmp(b, WINAMP_SKINZIPW) &&
+ wcscmp(b, WINAMP_LANGZIPW))) rval = 0;
+ else rval = 1;
+ }
+ else rval = 0;
+ RegCloseKey(key);
+ }
+
+ return rval;
+}
+
+bool allowed_extension(wchar_t *ext)
+{
+ const wchar_t* blocked[] = {L"exe", L"dll",
+ L"jpg", L"jpeg", L"gif", L"bmp",
+ L"png", L"tif", L"tiff"};
+ // ensure we block at least 'exe' and 'dll', and images if not disabled
+ for (size_t i = 0; i < (config_block_img ? ARRAYSIZE(blocked) : 2); i++)
+ {
+ if (!_wcsicmp(ext, blocked[i])) return false;
+ }
+ return true;
+}
+
+void config_register(wchar_t *ext, int reg)
+{
+ const wchar_t *which_str = WINAMP_FILEW;
+ if (config_no_registry) return ;
+ if (!ext[0]) return ;
+ if (!allowed_extension(ext)) return ; //windows=gay
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ wchar_t family_str[256] = {0};
+
+ if (IsPlaylistExtension(ext))
+ which_str = WINAMP_PLAYLISTW;
+ else if (!_wcsicmp(ext, L"wsz") || !_wcsicmp(ext, L"wal") || !_wcsicmp(ext, L"wpz"))
+ which_str = WINAMP_SKINZIPW;
+ else if (!_wcsicmp(ext, L"wlz"))
+ which_str = WINAMP_LANGZIPW;
+ else
+ {
+ StringCchPrintfW(family_str, 256, L"%s.%s", WINAMP_FILEW, ext);
+
+ wchar_t family_description[256] = {0};
+ if (in_get_extended_fileinfoW(family_str, L"family", family_description, 255) && family_description[0])
+ {
+ which_str=family_str;
+ if (reg)
+ config_setup_filetype(family_str, family_description, 0);
+ }
+ }
+
+ if (reg && !_wcsicmp(ext, L"asx"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"video/x-asx", programname, L".asx", 0);
+ regmimetype(L"video/asx", programname, L".asx", 0);
+ regmimetype(L"video/x-ms-asf", programname, L".asx", 0);
+ }
+ if (reg && !_wcsicmp(ext, L"wal"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"interface/x-winamp3-skin", programname, L".wal", 0);
+ }
+ if (reg && !_wcsicmp(ext, L"wsz"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"interface/x-winamp-skin", programname, L".wsz", 0);
+ }
+ if (reg && !_wcsicmp(ext, L"wlz"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"interface/x-winamp-lang", programname, L".wlz", 0);
+ }
+ if (reg && !_wcsicmp(ext, L"pls"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"audio/x-scpls", programname, L".pls", 0);
+ regmimetype(L"audio/scpls", programname, L".pls", 0);
+ }
+ if (reg && !_wcsicmp(ext, L"wma"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"audio/x-ms-wma", programname, L".wma", 1);
+ regmimetype(L"application/x-msdownload", programname, L".wma", 1);
+ }
+ if (reg && !_wcsicmp(ext, L"m3u"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"audio/x-mpegurl", programname, L".m3u", 0);
+ regmimetype(L"audio/mpegurl", programname, L".m3u", 0);
+ }
+ if (reg && !_wcsicmp(ext, L"mp3"))
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, programname, MAX_PATH);
+ regmimetype(L"audio/x-mpeg", programname, L".mp3", 1);
+ regmimetype(L"audio/x-mp3", programname, L".mp3", 1);
+ regmimetype(L"audio/x-mpg", programname, L".mp3", 1);
+ regmimetype(L"audio/mp3", programname, L".mp3", 1);
+ regmimetype(L"audio/mpg", programname, L".mp3", 1);
+ regmimetype(L"audio/mpeg", programname, L".mp3", 1);
+ }
+
+ wchar_t b[128] = {0};
+ StringCchPrintfW(b, 128, L".%s", ext);
+ CharLowerBuffW(b, ARRAYSIZE(b));
+ if (reg)
+ registrar->RegisterType(b, which_str, AutoWide(app_name));
+ else
+ {
+ // avoid removing WINAMP_FILEW as this will break some parts
+ // this will generally happen from 3rd party plugins where
+ // no %family% will be correctly returned in the relevant
+ if(_wcsicmp(which_str, WINAMP_FILEW))
+ {
+ registrar->UnregisterType(b, which_str, AutoWide(app_name), IsPlaylistExtension(ext));
+ }
+ }
+
+ registrar->Release();
+ }
+}
+
+void regmimetype(const wchar_t *mtype, const wchar_t *programname, const wchar_t *ext, int nsonly)
+{
+ if (config_no_registry)
+ return ;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->RegisterMIMEType(mtype, programname, ext, nsonly);
+ registrar->Release();
+ }
+}
+
+void trimPathW(wchar_t *pathStart)
+{
+ PathRemoveBlanksW(pathStart);
+ PathRemoveBackslashW(pathStart);
+}
+
+void config_setinifile(wchar_t *inifile)
+{
+ lstrcpynW(INI_FILE, inifile, sizeof(INI_FILE) / sizeof(INI_FILE[0]));
+}
+
+void config_setinidir(const wchar_t *inidir)
+{
+ if (SUCCEEDED(StringCchCopyW(CONFIGDIR, MAX_PATH, inidir)))
+ trimPathW(CONFIGDIR);
+ else
+ CONFIGDIR[0] = 0;
+}
+
+void config_setm3udir(const wchar_t *m3udir)
+{
+ if (SUCCEEDED(StringCchCopyW(M3UDIR, MAX_PATH, m3udir)))
+ trimPathW(M3UDIR);
+ else
+ M3UDIR[0] = 0;
+}
+
+void config_setm3ubase(const wchar_t *m3ubase)
+{
+ if (SUCCEEDED(StringCchCopyW(M3UBASE, MAX_PATH, m3ubase)))
+ trimPathW(M3UBASE);
+ else
+ M3UBASE[0] = 0;
+}
+
+void init_config()
+{
+ GetModuleFileNameW(hMainInstance, PROGDIR, MAX_PATH);
+ PathRemoveFileSpecW(PROGDIR);
+ SetEnvironmentVariableW(L"WINAMP_PROGRAM_DIR", PROGDIR);
+ wchar_t winamp_root[MAX_PATH] = {0};
+ StringCchCopyW(winamp_root, MAX_PATH, PROGDIR);
+ PathStripToRootW(winamp_root);
+ SetEnvironmentVariableW(L"WINAMP_ROOT_DIR", winamp_root);
+}
+
+void setup_config(void)
+{
+ if (!CONFIGDIR[0])
+ StringCchCopyW(CONFIGDIR, MAX_PATH, PROGDIR);
+
+ if (!M3UDIR[0])
+ StringCchCopyW(M3UDIR, MAX_PATH, CONFIGDIR);
+
+ if (!M3UBASE[0])
+ StringCchCopyW(M3UBASE, MAX_PATH, M3UDIR);
+
+ CreateDirectoryW(M3UDIR, NULL);
+ CreateDirectoryW(CONFIGDIR, NULL);
+
+ // basic config files
+ PathCombineW(OLD_M3U_FILE, M3UDIR, L"Winamp.m3u");
+ PathCombineW(M3U_FILE, M3UDIR, L"Winamp.m3u8");
+ PathCombineW(BOOKMARKFILE, CONFIGDIR, L"Winamp.bm");
+ PathCombineW(BOOKMARKFILE8, CONFIGDIR, L"Winamp.bm8");
+ // just make sure if a winamp.bm8 doesn't exist then
+ // go make one from winamp.bm - implemented for 5.58+
+ if(!PathFileExistsW(BOOKMARKFILE8))
+ {
+ CopyFileW(BOOKMARKFILE,BOOKMARKFILE8,FALSE);
+ }
+ PathCombineW(EQDIR1, CONFIGDIR, L"Winamp.q1");
+ PathCombineW(EQDIR2, CONFIGDIR, L"Winamp.q2");
+ wchar_t tempPath[MAX_PATH] = {0};
+ GetTempPathW(MAX_PATH, tempPath);
+ PathCombineW(TEMP_FILE, tempPath, L"Winamp.tmp");
+ PathCombineW(DEMOMP3, M3UDIR, L"demo.mp3");
+ PathCombineW(JSAPI2_INIFILE, CONFIGDIR, L"jsapisec.ini");
+ PathCombineW(ML_INI_FILE, CONFIGDIR, L"Plugins\\gen_ml.ini");
+
+ // override INI_FILE if specified
+ if (INI_FILE[0])
+ {
+ if (PathIsFileSpecW(INI_FILE) || PathIsRelativeW(INI_FILE))
+ {
+ wchar_t temp[MAX_PATH] = {0};
+ PathCombineW(temp, CONFIGDIR, INI_FILE);
+ lstrcpynW(INI_FILE, temp, MAX_PATH);
+ }
+ }
+ else
+ PathCombineW(INI_FILE, CONFIGDIR, L"Winamp.ini");
+
+ // maintain a ansi version of INI_FILE for some aspects
+ StringCchCopyA(INI_FILEA, MAX_PATH, AutoCharFn(INI_FILE));
+
+ RI(utf8);
+
+ // skin and plugin directories
+ PathCombineW(SKINDIR, PROGDIR, L"Skins");
+ PathCombineW(PLUGINDIR, PROGDIR, L"Plugins");
+ PathCombineW(SYSPLUGINDIR, PROGDIR, L"System");
+ PathCombineW(SKINDIR, PROGDIR, L"Skins");
+ PathCombineW(LANGDIR, PROGDIR, L"Lang");
+ PathCombineW(VISDIR, PROGDIR, L"Plugins");
+ PathCombineW(DSPDIR, PROGDIR, L"Plugins");
+
+ // override skin/plugin directories from config
+ {
+ wchar_t bW[MAX_PATH] = {0}, *pW;
+
+ bW[0]=0;
+ _r_sW("PluginDir", bW, MAX_PATH);
+ pW = bW;
+ while (pW && (*pW == L' ' || *pW == L'\t')) pW++;
+ if (pW && *pW)
+ {
+ StringCchCopyW(PLUGINDIR, MAX_PATH, bW);
+ }
+
+ ZeroMemory(bW, sizeof(bW));
+ _r_sW("DSPDir", bW, MAX_PATH);
+ pW = bW;
+ while (pW && (*pW == L' ' || *pW == L'\t')) pW++;
+ if (pW && *pW)
+ {
+ StringCchCopyW(DSPDIR, MAX_PATH, bW);
+ }
+
+ ZeroMemory(bW, sizeof(bW));
+ _r_sW("VISDir", bW, MAX_PATH);
+ pW = bW;
+ while (pW && (*pW == L' ' || *pW == L'\t')) pW++;
+ if (pW && *pW)
+ {
+ StringCchCopyW(VISDIR, MAX_PATH, bW);
+ }
+
+ ZeroMemory(bW, sizeof(bW));
+ _r_sW("SkinDir", bW, MAX_PATH);
+ pW = bW;
+ while (pW && (*pW == L' ' || *pW == L'\t')) pW++;
+ if (pW && *pW)
+ {
+ StringCchCopyW(SKINDIR, MAX_PATH, bW);
+ }
+
+ ZeroMemory(bW, sizeof(bW));
+ _r_sW("LangDir", bW, MAX_PATH);
+ pW = bW;
+ while (pW && (*pW == L' ' || *pW == L'\t')) pW++;
+ if (pW && *pW)
+ {
+ StringCchCopyW(LANGDIR, MAX_PATH, bW);
+ }
+ }
+
+ // create a skin temp directory, too
+ wchar_t buf[MAX_PATH] = {0};
+ GetTempPathW(MAX_PATH, buf);
+ GetTempFileNameW(buf, L"WAS", GetTickCount(), SKINTEMPDIR);
+
+ // create a lang temp directory, too by
+ // trying to use part of the wlz's name
+ // so it's easier to see when debugging
+ // e.g. W<lang>XXXX.tmp otherwise it'll
+ // revert back to the older WLZXXXX.tmp
+ config_load_langpack_var();
+ if (wcstok(config_langpack, L"-"))
+ {
+ wchar_t *p = wcstok(NULL, L"-");
+ if (p)
+ {
+ wchar_t buf2[4] = {0};
+ StringCchPrintfW(buf2, 4, L"W%s", p);
+ CharUpperBuffW(buf2, 4);
+ GetTempFileNameW(buf, buf2, GetTickCount(), LANGTEMPDIR);
+ }
+ else
+ {
+ GetTempFileNameW(buf, L"WLZ", GetTickCount(), LANGTEMPDIR);
+ }
+ }
+ else
+ {
+ GetTempFileNameW(buf, L"WLZ", GetTickCount(), LANGTEMPDIR);
+ }
+
+ RI(minst);
+}
+
+BOOL config_removedircontext(BOOL use_fallback)
+{
+ if (config_no_registry)
+ return TRUE;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, !use_fallback) == 0 && registrar)
+ {
+ registrar->RemoveDirectoryContext(WINAMP_PLAYW);
+ registrar->RemoveDirectoryContext(WINAMP_ENQUEUEW);
+ registrar->RemoveDirectoryContext(WINAMP_BOOKMARKW);
+ registrar->Release();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int config_iscdplayer(void)
+{
+ DWORD r = 0, s;
+ HKEY mp3Key;
+ char buf[MAX_PATH], buf2[MAX_PATH] = "\"";;
+ if (!GetModuleFileNameA(hMainInstance, buf2 + 1, sizeof(buf2) - 8)) return 0;
+ if (RegOpenKeyA(HKEY_CLASSES_ROOT, "AudioCD\\shell\\play\\command", &mp3Key) != ERROR_SUCCESS) return 0;
+ StringCchCatA(buf2, MAX_PATH, "\" %1");
+ s = sizeof(buf);
+ if (RegQueryValueEx(mp3Key, NULL, 0, NULL, (LPBYTE)buf, &s) == ERROR_SUCCESS)
+ {
+ if (!lstrcmpiA(buf, buf2)) r = 1;
+ }
+ RegCloseKey(mp3Key);
+ return r;
+}
+
+BOOL config_regcdplayer(int reg, int mode)
+{
+ if (config_no_registry) return TRUE;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, !mode) == 0 && registrar)
+ {
+ wchar_t programName[MAX_PATH] = {0};
+ if (GetModuleFileNameW(hMainInstance, programName, MAX_PATH))
+ {
+ if (reg)
+ registrar->RegisterCDPlayer(programName);
+ else
+ registrar->UnregisterCDPlayer(programName);
+ }
+ registrar->Release();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void config_load_langpack_var(void)
+{
+ RSW(langpack);
+}
+
+void config_save_langpack_var(void)
+{
+ WSW(langpack);
+}
+
+void config_agent_add(void)
+{
+ if (config_no_registry) return;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ wchar_t exe_name[MAX_PATH + 2] = {0};
+ GetModuleFileNameW(hMainInstance, exe_name, sizeof(exe_name)/sizeof(wchar_t));
+ PathRemoveFileSpecW(exe_name);
+ PathCombineW(exe_name, exe_name, L"winampa.exe");
+ PathQuoteSpacesW(exe_name);
+
+ registrar->AddAgent(exe_name);
+ registrar->Release();
+ }
+
+ Lang_LocaliseAgentOnTheFly(TRUE);
+}
+
+void config_agent_remove(void)
+{
+ if (config_no_registry) return ;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ HWND hwnd = FindWindowW(L"WinampAgentMain", NULL);
+ if (hwnd)
+ {
+ SendMessageW(hwnd, WM_CLOSE, 0, 0);
+ }
+ registrar->RemoveAgent();
+ registrar->Release();
+ }
+
+ Lang_LocaliseAgentOnTheFly(FALSE);
+}
+
+BOOL config_register_capability(wchar_t *ext, int mode)
+{
+ if (config_no_registry) return TRUE;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, !mode) == 0 && registrar)
+ {
+ WCHAR szApplication[128] = {0}, szExtension[64] = {0}, szProgId[256] = {0};
+ size_t required = MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, NULL, 0);
+ if (required > ARRAYSIZE(szApplication))
+ return TRUE;
+
+ if (0 == MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, szApplication, ARRAYSIZE(szApplication)))
+ return TRUE;
+
+ LPWSTR cursor = szProgId;
+ size_t remaining = ARRAYSIZE(szProgId);
+
+ if (FAILED(StringCchCopyExW(cursor, remaining, WINAMP_FILEW, &cursor, &remaining, 0)))
+ return TRUE;
+
+ if (FAILED(StringCchCopyExW(cursor, remaining, L".", &cursor, &remaining, 0)))
+ return TRUE;
+
+ if (FAILED(StringCchCopyExW(cursor, remaining, ext/*szExtension*/, &cursor, &remaining, 0)))
+ return TRUE;
+
+ //CharLowerW(szExtension);
+
+ registrar->RegisterCapability(szApplication, szProgId, szExtension);
+ registrar->Release();
+ return TRUE;
+ }
+ return FALSE;
+} \ No newline at end of file
diff --git a/Src/Winamp/CurrentSongCOM.cpp b/Src/Winamp/CurrentSongCOM.cpp
new file mode 100644
index 00000000..7bcf5978
--- /dev/null
+++ b/Src/Winamp/CurrentSongCOM.cpp
@@ -0,0 +1,317 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "Main.h"
+#include "CurrentSongCOM.h"
+#include "../nu/AutoWide.h"
+#include "Browser.h"
+#include "JSAPI.h"
+#include <malloc.h>
+
+HANDLE DuplicateCurrentThread()
+{
+ HANDLE fakeHandle = GetCurrentThread();
+ HANDLE copiedHandle = 0;
+ HANDLE processHandle = GetCurrentProcess();
+ DuplicateHandle(processHandle, fakeHandle, processHandle, &copiedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ return copiedHandle;
+}
+
+enum
+{
+ DISP_CURRENTSONG_GETFILENAME = 777,
+ DISP_CURRENTSONG_GETFILETITLE ,
+ DISP_CURRENTSONG_GETFILELENGTH,
+ DISP_CURRENTSONG_GETMETADATA ,
+ DISP_CURRENTSONG_GETPLAYPOSITION ,
+ DISP_CURRENTSONG_ISPLAYING ,
+ DISP_CURRENTSONG_ISSTOPPED ,
+ DISP_CURRENTSONG_ISPAUSED ,
+ DISP_CURRENTSONG_PAUSE ,
+ DISP_CURRENTSONG_RESUME,
+ DISP_CURRENTSONG_REGISTERMETADATACALLBACK,
+ DISP_CURRENTSONG_UNREGISTERMETADATACALLBACK,
+ DISP_CURRENTSONG_REGISTERTITLECHANGECALLBACK,
+ DISP_CURRENTSONG_UNREGISTERTITLECHANGECALLBACK,
+ DISP_CURRENTSONG_REFRESHTITLE,
+};
+
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT CurrentSongCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ UNREFERENCED_PARAMETER(riid);
+
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("GetFilename", DISP_CURRENTSONG_GETFILENAME) // July 27, 2005
+ CHECK_ID("GetFileTitle", DISP_CURRENTSONG_GETFILETITLE) // July 27, 2005
+ CHECK_ID("GetFileLength", DISP_CURRENTSONG_GETFILELENGTH) // July 27, 2005
+ CHECK_ID("GetMetadata", DISP_CURRENTSONG_GETMETADATA) // July 27, 2005
+ CHECK_ID("GetPlayPosition", DISP_CURRENTSONG_GETPLAYPOSITION) // July 27, 2005
+ CHECK_ID("IsPlaying", DISP_CURRENTSONG_ISPLAYING) // July 27, 2005
+ CHECK_ID("IsStopped", DISP_CURRENTSONG_ISSTOPPED) // July 27, 2005
+ CHECK_ID("IsPaused", DISP_CURRENTSONG_ISPAUSED) // July 27, 2005
+ CHECK_ID("Pause", DISP_CURRENTSONG_PAUSE)
+ CHECK_ID("Resume", DISP_CURRENTSONG_RESUME)
+ CHECK_ID("RegisterMetadataCallback", DISP_CURRENTSONG_REGISTERMETADATACALLBACK)
+ CHECK_ID("UnregisterMetadataCallback", DISP_CURRENTSONG_UNREGISTERMETADATACALLBACK)
+ CHECK_ID("RegisterTitleChangeCallback", DISP_CURRENTSONG_REGISTERTITLECHANGECALLBACK)
+ CHECK_ID("UnregisterTitleChangeCallback", DISP_CURRENTSONG_UNREGISTERTITLECHANGECALLBACK)
+ CHECK_ID("RefreshTitle", DISP_CURRENTSONG_REFRESHTITLE)
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT CurrentSongCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ UNREFERENCED_PARAMETER(itinfo);
+ UNREFERENCED_PARAMETER(lcid);
+ UNREFERENCED_PARAMETER(pptinfo);
+
+ return E_NOTIMPL;
+}
+
+HRESULT CurrentSongCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ UNREFERENCED_PARAMETER(pctinfo);
+
+ return E_NOTIMPL;
+}
+
+
+HRESULT CurrentSongCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ UNREFERENCED_PARAMETER(riid);
+ UNREFERENCED_PARAMETER(lcid);
+ UNREFERENCED_PARAMETER(wFlags);
+ UNREFERENCED_PARAMETER(pexecinfo);
+
+ switch (dispid)
+ {
+ case DISP_CURRENTSONG_REFRESHTITLE:
+
+ SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
+ return S_OK;
+
+ case DISP_CURRENTSONG_REGISTERTITLECHANGECALLBACK:
+ return titleChangeCallbacks.RegisterFromDispParam(pdispparams, 0, puArgErr);
+ case DISP_CURRENTSONG_UNREGISTERTITLECHANGECALLBACK:
+ return titleChangeCallbacks.UnregisterFromDispParam(pdispparams, 0, puArgErr);
+ case DISP_CURRENTSONG_REGISTERMETADATACALLBACK:
+ return metadataCallbacks.RegisterFromDispParam(pdispparams, 0, puArgErr);
+ case DISP_CURRENTSONG_UNREGISTERMETADATACALLBACK:
+ return metadataCallbacks.UnregisterFromDispParam(pdispparams, 0, puArgErr);
+ case DISP_CURRENTSONG_GETMETADATA:
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+ {
+ wchar_t buffer[4096] = {0};
+ extendedFileInfoStructW info;
+
+ info.filename = FileName;
+ info.metadata = pdispparams->rgvarg[0].bstrVal;
+ info.ret = buffer;
+ info.retlen = sizeof(buffer)/sizeof(wchar_t);
+
+ if (NULL != info.filename &&
+ NULL != info.metadata)
+ {
+ if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ info.ret = NULL;
+
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
+ }
+ else
+ JSAPI_EMPTY_RESULT(pvarResult);
+
+ return S_OK;
+ }
+ break;
+
+ case DISP_CURRENTSONG_GETFILENAME:
+ {
+ BSTR name = SysAllocString(FileName);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = name;
+ return S_OK;
+ }
+ break;
+
+ case DISP_CURRENTSONG_GETFILETITLE:
+ {
+ BSTR title = SysAllocString(FileTitle);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = title;
+ return S_OK;
+ }
+ break;
+
+ case DISP_CURRENTSONG_GETFILELENGTH:
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = in_getlength();
+ return S_OK;
+
+ case DISP_CURRENTSONG_GETPLAYPOSITION:
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = in_getouttime();
+ return S_OK;
+
+ case DISP_CURRENTSONG_ISPLAYING:
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ V_BOOL(pvarResult) = (0 != playing) ? VARIANT_TRUE : VARIANT_FALSE;
+ return S_OK;
+
+ case DISP_CURRENTSONG_ISSTOPPED:
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ V_BOOL(pvarResult) = (0 == playing) ? VARIANT_TRUE : VARIANT_FALSE;
+ return S_OK;
+
+ case DISP_CURRENTSONG_ISPAUSED:
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ V_BOOL(pvarResult) = (0 != paused) ? VARIANT_TRUE : VARIANT_FALSE;
+ return S_OK;
+ case DISP_CURRENTSONG_PAUSE:
+ PausePlaying();
+ return S_OK;
+ case DISP_CURRENTSONG_RESUME:
+ UnPausePlaying();
+ return S_OK;
+
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP CurrentSongCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+
+ULONG CurrentSongCOM::AddRef(void)
+{
+
+ return 0;
+}
+
+ULONG CurrentSongCOM::Release(void)
+{
+ return 0;
+}
+
+static void TitleChanged_NotifyCb(IDispatch *dispatch, void *param)
+{
+ UNREFERENCED_PARAMETER(param);
+
+ DISPPARAMS params;
+ unsigned int ret;
+
+ if (NULL == dispatch)
+ return;
+
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = 0;
+ params.rgvarg = 0;
+
+ if (!(config_no_visseh&8))
+ {
+ try
+ {
+ dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+ }
+ catch (...)
+ {}
+ }
+ else
+ dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+}
+
+void CurrentSongCOM::TitleChanged()
+{
+ titleChangeCallbacks.Notify(TitleChanged_NotifyCb, NULL, NULL);
+}
+
+static void MetadataChanged_NotifyCb(IDispatch *dispatch, void *param)
+{
+ VARIANT argument;
+ DISPPARAMS params;
+
+ if (NULL == dispatch)
+ return;
+
+ VariantInit(&argument);
+ V_VT(&argument) = VT_BSTR;
+ V_BSTR(&argument) = (BSTR)param;
+
+ params.cArgs = 1;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = NULL;
+ params.rgvarg = &argument;
+ unsigned int ret;
+
+ if (!(config_no_visseh&8))
+ {
+ try
+ {
+ dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+ }
+ catch (...)
+ {}
+ }
+ else
+ dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+
+}
+
+static void MetadataChanged_FreeCb(void *param)
+{
+ BSTR bstr = (BSTR)param;
+ SysFreeString(bstr);
+}
+
+void CurrentSongCOM::MetadataChanged(char *metadataString)
+{
+ AutoWide wideMetadata(metadataString);
+ BSTR bstr = SysAllocString(wideMetadata);
+
+ metadataCallbacks.Notify(MetadataChanged_NotifyCb, MetadataChanged_FreeCb, bstr);
+}
+
diff --git a/Src/Winamp/CurrentSongCOM.h b/Src/Winamp/CurrentSongCOM.h
new file mode 100644
index 00000000..6839861a
--- /dev/null
+++ b/Src/Winamp/CurrentSongCOM.h
@@ -0,0 +1,31 @@
+#ifndef NULLSOFT_CURRENTSONGCOM
+#define NULLSOFT_CURRENTSONGCOM
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./dispatchCallback.h"
+//#include <ocidl.h>
+
+class CurrentSongCOM : public IDispatch
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ void MetadataChanged(char *metadataString);
+ void TitleChanged();
+
+ DispatchCallbackStore metadataCallbacks;
+ DispatchCallbackStore titleChangeCallbacks;
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/DOCK.cpp b/Src/Winamp/DOCK.cpp
new file mode 100644
index 00000000..3275cac7
--- /dev/null
+++ b/Src/Winamp/DOCK.cpp
@@ -0,0 +1,233 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+
+void FixMainWindowRect(RECT *r)
+{
+ if (r->right-r->left > 280)
+ {
+ if (r->bottom-r->top < 200)
+ r->bottom=r->top+14*2;
+ }
+ else
+ {
+ if (r->bottom-r->top < 100)
+ r->bottom=r->top+14;
+ }
+}
+
+void EstMainWindowRect( RECT *r )
+{
+ r->left = config_wx;
+ r->top = config_wy;
+ r->right = config_wx + ( WINDOW_WIDTH << ( config_dsize ? 1 : 0 ) );
+ r->bottom = config_wy + ( ( config_windowshade ? 14 : WINDOW_HEIGHT ) << ( config_dsize ? 1 : 0 ) );
+}
+
+void EstEQWindowRect( RECT *r )
+{
+ r->left = config_eq_wx;
+ r->top = config_eq_wy;
+ r->right = config_eq_wx + ( WINDOW_WIDTH << ( config_dsize && config_eqdsize ? 1 : 0 ) );
+ r->bottom = config_eq_wy + ( ( config_eq_ws ? 14 : WINDOW_HEIGHT ) << ( config_dsize && config_eqdsize ? 1 : 0 ) );
+}
+
+void EstPLWindowRect( RECT *r )
+{
+ r->left = config_pe_wx;
+ r->top = config_pe_wy;
+ r->right = config_pe_wx + config_pe_width;
+ r->bottom = config_pe_wy + config_pe_height;
+}
+
+void EstVidWindowRect( RECT *r )
+{
+ r->left = config_video_wx;
+ r->top = config_video_wy;
+ r->right = config_video_wx + config_video_width;
+ r->bottom = config_video_wy + config_video_height;
+}
+
+void SetMainWindowRect(RECT *r)
+{
+ config_wx=r->left;
+ config_wy=r->top;
+}
+
+void SetEQWindowRect(RECT *r)
+{
+ config_eq_wx=r->left;
+ config_eq_wy=r->top;
+}
+
+void SetPLWindowRect(RECT *r)
+{
+ config_pe_wx=r->left;
+ config_pe_wy=r->top;
+}
+
+void SetVidWindowRect(RECT *r)
+{
+ config_video_wx=r->left;
+ config_video_wy=r->top;
+}
+
+void MoveRect(RECT *r, int x, int y)
+{
+ r->left+=x;
+ r->right+=x;
+ r->top+=y;
+ r->bottom+=y;
+}
+
+int IsWindowAttached(RECT rc, RECT rc2)
+{
+#define INREG(x,l,h) ((x) >= (l) && (x) <= (h))
+ int r=0;
+ if (rc2.right == rc.left || rc2.left == rc.right)
+ {
+ if (INREG(rc.top,rc2.top,rc2.bottom) || INREG(rc.bottom,rc2.top,rc2.bottom) ||
+ INREG(rc2.top,rc.top,rc.bottom) || INREG(rc2.bottom,rc.top,rc.bottom))
+ r|=1;
+ }
+ if (rc2.bottom == rc.top || rc2.top == rc.bottom)
+ {
+ if (INREG(rc2.left,rc.left,rc.right) || INREG(rc2.right,rc.left,rc.right) ||
+ INREG(rc.left,rc2.left,rc2.right) || INREG(rc.right,rc2.left,rc2.right))
+ r|=2;
+ }
+#undef INREG
+ return r;
+}
+
+void SnapWindowToWindow(RECT *rcSrc, RECT rcDest)
+{
+
+#define INREG(x,l,h) ((x) >= (l) && (x) <= (h))
+#define IRR(l1,r1,l2,r2) (INREG(l1,l2,r2)||INREG(r1,l2,r2)||INREG(l2,l1,r1)||INREG(r2,l1,r1))
+#define CLOSETO(x,t) INREG(x,t-config_snaplen,t+config_snaplen)
+ if (IRR(rcDest.left,rcDest.right,rcSrc->left,rcSrc->right))
+ {
+ if (CLOSETO(rcSrc->top,rcDest.bottom))
+ {
+ rcSrc->bottom+=rcDest.bottom-rcSrc->top;
+ rcSrc->top=rcDest.bottom;
+ }
+ else if (CLOSETO(rcSrc->bottom,rcDest.top))
+ {
+ rcSrc->top=rcDest.top-(rcSrc->bottom-rcSrc->top);
+ rcSrc->bottom=rcDest.top;
+ }
+ }
+
+ if (IRR(rcDest.top,rcDest.bottom,rcSrc->top,rcSrc->bottom))
+ {
+ if (CLOSETO(rcSrc->right,rcDest.left))
+ {
+ rcSrc->left = rcDest.left-(rcSrc->right-rcSrc->left);
+ rcSrc->right= rcDest.left;
+ }
+ else if (CLOSETO(rcSrc->left,rcDest.right))
+ {
+ rcSrc->right += (rcDest.right-rcSrc->left);
+ rcSrc->left=rcDest.right;
+ }
+ }
+
+ if (rcSrc->right == rcDest.left || rcSrc->left== rcDest.right)
+ {
+ if (CLOSETO(rcSrc->top,rcDest.top))
+ {
+ rcSrc->bottom += rcDest.top-rcSrc->top;
+ rcSrc->top = rcDest.top;
+ }
+ else if (CLOSETO(rcSrc->bottom,rcDest.bottom))
+ {
+ rcSrc->top += rcDest.bottom-rcSrc->bottom;
+ rcSrc->bottom=rcDest.bottom;
+ }
+ }
+
+ if (rcSrc->bottom == rcDest.top || rcSrc->top == rcDest.bottom)
+ {
+ if (CLOSETO(rcSrc->left,rcDest.left))
+ {
+ rcSrc->right += rcDest.left-rcSrc->left;
+ rcSrc->left = rcDest.left;
+ }
+ else if (CLOSETO(rcSrc->right,rcDest.right))
+ {
+ rcSrc->left += rcDest.right-rcSrc->right;
+ rcSrc->right = rcDest.right;
+ }
+ }
+#undef INREG
+#undef IRR
+#undef CLOSETO
+}
+
+void AdjustSnap(RECT old1, RECT old2, RECT *new1, RECT *new2)
+{
+#define INREG(x,l,h) ((x) >= (l) && (x) < (h))
+ if (INREG(old1.top,old2.top,old2.bottom) || INREG(old2.top,old1.top,old1.bottom)) {
+#undef INREG
+ // xpos
+ if (old1.right >= old2.left && old1.left < old2.right) // old1/old2
+ {
+ MoveRect(new1,(new2->left-(new1->right-new1->left)) - new1->left,0);
+ }
+ else if (old2.right >= old1.left && old2.left < old1.right) // old2/old1
+ {
+ MoveRect(new2,(new1->left-(new2->right-new2->left)) - new2->left,0);
+ }
+ }
+#define INREG(x,l,h) ((x) >= (l) && (x) < (h))
+ if (INREG(old1.left,old2.left,old2.right) || INREG(old2.left,old1.left,old1.right)) {
+#undef INREG
+ // ypos
+ if (old1.bottom >= old2.top && old1.top < old2.bottom) // old1/old2
+ {
+ MoveRect(new1,0,(new2->top-(new1->bottom-new1->top)) - new1->top);
+ }
+ else if (old2.bottom >= old1.top && old2.top < old1.bottom) // old2/old1
+ {
+ MoveRect(new2,0,(new1->top-(new2->bottom-new2->top)) - new2->top);
+ }
+ }
+}
+
+int IsPointInRect(int x, int y, RECT *r)
+{
+ if (x >= r->left && x < r->right && y >= r->top && y < r->bottom)
+ return 1;
+ return 0;
+}
+
+void FixOverlaps(RECT *r1, RECT *r2)
+{
+ if (r1->left >= r2->left) // r1 - r2
+ {
+ RECT *t=r1;
+ r1=r2;
+ r2=t;
+ }
+ {
+ if (IsPointInRect(r2->left,r2->top,r1))
+ {
+ if (r1->right-r2->left < r1->bottom-r2->top)
+ {
+ MoveRect(r2,r1->right-r2->left,0);
+ }
+ else
+ {
+ MoveRect(r2,0,r1->bottom-r2->top);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/DSP.H b/Src/Winamp/DSP.H
new file mode 100644
index 00000000..0a2c1d58
--- /dev/null
+++ b/Src/Winamp/DSP.H
@@ -0,0 +1,80 @@
+#ifndef NULLSOFT_WINAMP_DSP_H
+#define NULLSOFT_WINAMP_DSP_H
+// DSP plugin interface
+
+typedef struct winampDSPModule
+{
+ char *description; // description
+ HWND hwndParent; // parent window (filled in by calling app)
+ HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app)
+
+ void( __cdecl *Config )( struct winampDSPModule *this_mod ); // configuration dialog (if needed)
+ int( __cdecl *Init )( struct winampDSPModule *this_mod ); // 0 on success, creates window, etc (if needed)
+
+ // modify waveform samples: returns number of samples to actually write
+ // (typically numsamples, but no more than twice numsamples, and no less than half numsamples)
+ // numsamples should always be at least 128. should, but I'm not sure
+ int( __cdecl *ModifySamples )( struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate );
+
+ void( __cdecl *Quit )( struct winampDSPModule *this_mod ); // called when unloading
+
+ void *userData; // user data, optional
+} winampDSPModule;
+
+typedef struct
+{
+ int version; // DSP_HDRVER
+ char *description; // description of library
+ winampDSPModule *( __cdecl *getModule )( int ); // module retrieval function
+ int( __cdecl *sf )( int key ); // DSP_HDRVER == 0x21
+} winampDSPHeader;
+
+// exported symbols
+#ifdef USE_DSP_HDR_HWND
+typedef winampDSPHeader *( __cdecl *winampDSPGetHeaderType )( HWND );
+#define DSP_HDRVER 0x22
+#else
+// Note: Unless using USE_DSP_HDR_HWND or a Winamp 5.5+ client then winampDSPGetHeaderType(..)
+// will not receive a HWND parameter & with be called as winampDSPGetHeaderType(void).
+// This is only defined with an HWND to allow for correct compiling of the client exe.
+typedef winampDSPHeader *( __cdecl *winampDSPGetHeaderType )( HWND );
+// header version: 0x20 == 0.20 == winamp 2.0
+#define DSP_HDRVER 0x20
+#endif
+
+// These are the return values to be used with the uninstall plugin export function:
+// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
+// which determines if Winamp can uninstall the plugin immediately or on winamp restart.
+// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
+//
+#define DSP_PLUGIN_UNINSTALL_NOW 0x0
+#define DSP_PLUGIN_UNINSTALL_REBOOT 0x1
+//
+// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
+// that it is down to you to ensure that if uninstall now is returned that it will not
+// cause a crash i.e. don't use if you've been subclassing the main window.
+//
+// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
+//
+//
+// Version note:
+//
+// Added passing of Winamp's main hwnd in the call to the exported winampDSPHeader()
+// which allows for primarily the use of localisation features with the bundled plugins.
+// If you want to use the new version then either you can edit you version of dsp.h or
+// you can add USE_DSP_HDR_HWND to your project's defined list or before use of dsp.h
+//
+
+// For a DSP plugin to be correctly detected by Winamp you need to ensure that
+// the exported winampDSPGetHeader2(..) is exported as an undecorated function
+// e.g.
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+// __declspec(dllexport) winampDSPGetHeaderType * __cdecl winampDSPGetHeader2(){ return &plugin; }
+// #ifdef __cplusplus
+// }
+// #endif
+//
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/DSP.cpp b/Src/Winamp/DSP.cpp
new file mode 100644
index 00000000..88c3dc53
--- /dev/null
+++ b/Src/Winamp/DSP.cpp
@@ -0,0 +1,85 @@
+#include "Main.h"
+#include "dsp.h"
+
+static int initted=0;
+static HINSTANCE hLib=0;
+static winampDSPModule *mod=0;
+
+void dsp_init(void)
+{
+ if (g_safeMode)
+ return;
+
+ wchar_t str[1024] = {0};
+
+ if (initted)
+ dsp_quit();
+
+ if (!config_dspplugin_name[0])
+ return;
+
+ PathCombineW(str,DSPDIR,config_dspplugin_name);
+ hLib = LoadLibraryW(str);
+
+ if (!hLib)
+ return;
+
+ winampDSPGetHeaderType pr = (winampDSPGetHeaderType) GetProcAddress(hLib,"winampDSPGetHeader2");
+
+ if (!pr || (pr(hMainWindow)->version < DSP_HDRVER && pr(hMainWindow)->version >= DSP_HDRVER+0x10) || !(mod = pr(hMainWindow)->getModule(config_dspplugin_num)))
+ {
+ FreeLibrary(hLib);
+ hLib=0;
+ return;
+ }
+
+ mod->hwndParent=hMainWindow;
+ mod->hDllInstance=hLib;
+ mod->Init(mod);
+ initted=1;
+}
+
+void dsp_quit(void)
+{
+ if (!initted)
+ return;
+
+ initted=0;
+ if (mod)
+ {
+ if (!(config_no_visseh&2))
+ {
+ try
+ {
+ mod->Quit(mod);
+ }
+ catch(...)
+ {
+ }
+ }
+ else
+ {
+ mod->Quit(mod);
+ }
+ }
+
+ FreeLibrary(hLib);
+ hLib=0;
+ mod=0;
+}
+
+int dsp_isactive(void)
+{
+ return (in_mod && initted && mod);
+}
+
+int dsp_dosamples(short int *samples, int numsamples, int bps, int nch, int srate)
+{
+ if (dsp_isactive())
+ {
+ if (mod)
+ return (mod->ModifySamples(mod,samples,numsamples,bps,nch,srate));
+ }
+
+ return numsamples;
+} \ No newline at end of file
diff --git a/Src/Winamp/DataStoreCOM.cpp b/Src/Winamp/DataStoreCOM.cpp
new file mode 100644
index 00000000..3581f7a5
--- /dev/null
+++ b/Src/Winamp/DataStoreCOM.cpp
@@ -0,0 +1,130 @@
+#include "DataStoreCOM.h"
+
+enum
+{
+ DISP_DATASTORE_STORE,
+ DISP_DATASTORE_RETRIEVE,
+ DISP_DATASTORE_GENERATE_GUID,
+};
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT DataStoreCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("Store", DISP_DATASTORE_STORE);
+ CHECK_ID("Retrieve", DISP_DATASTORE_RETRIEVE);
+ CHECK_ID("GenerateGUID", DISP_DATASTORE_GENERATE_GUID);
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT DataStoreCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT DataStoreCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT DataStoreCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ case DISP_DATASTORE_GENERATE_GUID:
+ {
+ GUID guid;
+ UuidCreate(&guid);
+ wchar_t *guid_string;
+ UuidToStringW(&guid, (unsigned short **)&guid_string);
+ BSTR tag = SysAllocString(guid_string);
+ RpcStringFreeW((unsigned short **)&guid_string);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = tag;
+ return S_OK;
+ }
+ case DISP_DATASTORE_STORE:
+ if (pdispparams->cArgs == 2)
+ {
+ GUID guid;
+ UuidFromStringW((unsigned short *)pdispparams->rgvarg[1].bstrVal, &guid);
+
+ SAFEARRAY *bufferArray=pdispparams->rgvarg[0].parray;
+ SAFEARRAY *store;
+ HRESULT hr = SafeArrayCopy(bufferArray, &store);
+ dataStore[guid]=store;
+ return hr;
+
+ }
+ else
+ return DISP_E_BADPARAMCOUNT;
+ case DISP_DATASTORE_RETRIEVE:
+ if (pdispparams->cArgs == 1)
+ {
+ GUID guid;
+ UuidFromStringW((unsigned short *)pdispparams->rgvarg[0].bstrVal, &guid);
+
+ SAFEARRAY *store = dataStore[guid];
+ if (store)
+ {
+ SAFEARRAY *bufferArray;
+ SafeArrayCopy(store, &bufferArray);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_ARRAY|VT_UI1;
+ V_ARRAY(pvarResult) = bufferArray;
+ return S_OK;
+ }
+ else
+ return E_FAIL;
+
+ }
+ else
+ return DISP_E_BADPARAMCOUNT;
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP DataStoreCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+
+ULONG DataStoreCOM::AddRef(void)
+{
+ return 0;
+}
+
+
+ULONG DataStoreCOM::Release(void)
+{
+ return 0;
+}
diff --git a/Src/Winamp/DataStoreCOM.h b/Src/Winamp/DataStoreCOM.h
new file mode 100644
index 00000000..f903140c
--- /dev/null
+++ b/Src/Winamp/DataStoreCOM.h
@@ -0,0 +1,20 @@
+#pragma once
+#include <map>
+#include <ocidl.h>
+#include "replicant/foundation/guid.h"
+
+
+class DataStoreCOM : public IDispatch
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ std::map<GUID, SAFEARRAY *> dataStore;
+}; \ No newline at end of file
diff --git a/Src/Winamp/Dde.cpp b/Src/Winamp/Dde.cpp
new file mode 100644
index 00000000..a0a15bcd
--- /dev/null
+++ b/Src/Winamp/Dde.cpp
@@ -0,0 +1,327 @@
+#include "Main.h"
+
+/*
+static HDDEDATA CALLBACK GroupDDECallback (UINT uiType, UINT uiFmt, HANDLE hConv,
+ HSZ sz1, HSZ sz2, HDDEDATA hData, LONG lData1, LONG lData2) {
+ return ((HDDEDATA) NULL);
+}
+static BOOL CreateGroup(HWND hwnd);
+static BOOL AddProgramItems (HWND hwnd, LPSTR szDummy);
+
+static CONVCONTEXT CCFilter = { sizeof (CONVCONTEXT), 0, 0, 0, 0L, 0L };
+static LONG lIdInst;
+static LONG lIdInst2;
+*/
+
+//CreateShortCut(hwnd,"D:\\WINNT\\Profiles\\Administrator\\Application Data\\Microsoft\\Internet Explorer\\Quick Launch\\Winamp.lnk","C:\\winamp\\winamp.exe");
+//CreateShortCut(hwnd,"D:\\WINNT\\Profiles\\Administrator\\Desktop\\Winamp.lnk","C:\\winamp\\winamp.exe");
+
+
+#if 0
+void dde_adddesktop(HWND hwnd)
+{
+ HKEY mp3Key;
+ char name[MAX_PATH]="";
+ if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
+ {
+ int s=sizeof(name);
+ if (RegQueryValueEx(mp3Key,"Desktop",0,NULL,name,&s) == ERROR_SUCCESS)
+ {
+ }
+ RegCloseKey(mp3Key);
+ }
+ if (lstrlen(name))
+ {
+ char exe[MAX_PATH];
+ GetModuleFileName(NULL,exe,sizeof(exe));
+ lstrcat(name,"\\WINAMP.LNK");
+ CreateShortCut(hwnd,name,exe,NULL,0);
+ }
+}
+
+
+void dde_addquicklaunch(HWND hwnd)
+{
+ HKEY mp3Key;
+ char name[MAX_PATH]="";
+ if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
+ {
+ int s=sizeof(name);
+ if (RegQueryValueEx(mp3Key,"AppData",0,NULL,name,&s) == ERROR_SUCCESS)
+ {
+ }
+ RegCloseKey(mp3Key);
+ }
+ if (lstrlen(name))
+ {
+ char exe[MAX_PATH];
+ GetModuleFileName(NULL,exe,sizeof(exe));
+ lstrcat(name,"\\Microsoft\\Internet Explorer\\Quick Launch\\WINAMP.LNK");
+ CreateShortCut(hwnd,name,exe,NULL,0);
+ }
+}
+
+int dde_isquicklaunchavailable(void)
+{
+ HKEY mp3Key;
+ char name[MAX_PATH]="";
+ if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
+ {
+ int s=sizeof(name);
+ if (RegQueryValueEx(mp3Key,"AppData",0,NULL,name,&s) == ERROR_SUCCESS)
+ {
+ }
+ RegCloseKey(mp3Key);
+ }
+ if (lstrlen(name))
+ {
+ HANDLE h;
+ WIN32_FIND_DATA fd;
+ lstrcat(name,"\\Microsoft\\Internet Explorer\\Quick Launch");
+ h=FindFirstFile(name,&fd);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ FindClose(h);
+ if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) return 1;
+
+ }
+ }
+ return 0;
+}
+
+
+#if 1
+int dde_addstart(HWND hwnd)
+{
+ HKEY mp3Key;
+ char startMenu[MAX_PATH]="";
+ if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
+ {
+ int s=sizeof(startMenu)/sizeof(startMenu[0]);
+ if (RegQueryValueEx(mp3Key, "Programs", 0, NULL, startMenu, &s) == ERROR_SUCCESS)
+ {
+ char exe[MAX_PATH], shortcut[MAX_PATH], target[MAX_PATH];
+ GetModuleFileName(NULL,exe,sizeof(exe));
+
+ // create Winamp folder
+ PathAppend(startMenu, "Winamp");
+ CreateDirectory(startMenu, NULL);
+
+ // winamp.exe
+ PathCombine(shortcut, startMenu, "Winamp.lnk");
+ CreateShortCut(hwnd, shortcut, exe, NULL, 0);
+
+ // we don't need the executable filename anymore, but we need its path
+ PathRemoveFileSpec(exe);
+
+ // whatsnew.txt
+ PathCombine(target, exe, "whatsnew.txt");
+ PathCombine(shortcut, startMenu, "What's new.lnk");
+ CreateShortCut(hwnd, startMenu, target, NULL, 0);
+
+ // uninstwa.exe
+ PathCombine(shortcut, startMenu, "Uninstall Winamp.lnk");
+ PathAppend(target, exe, "uninstwa.exe");
+ CreateShortCut(hwnd, shortcut, target, NULL, 0);
+ }
+ RegCloseKey(mp3Key);
+ }
+ return 0;
+}
+
+
+#else
+
+int dde_addstart(HWND hwnd)
+{
+ CreateGroup(hwnd);
+ AddProgramItems (hwnd, NULL);
+ return 0;
+}
+
+void dde_delstart(void)
+{
+ HDDEDATA hData;
+ LPSTR szText;
+ LPSTR szCommand;
+ HCONV hConv;
+ HSZ szProgMan;
+ LONG lResult;
+ szText = VirtualAlloc (NULL, 64, MEM_COMMIT, PAGE_READWRITE);
+ szCommand = VirtualAlloc (NULL, 128, MEM_COMMIT, PAGE_READWRITE);
+ if (szText) {
+ if (DdeInitialize(&lIdInst, (PFNCALLBACK) GroupDDECallback,
+ (DWORD) APPCMD_CLIENTONLY, 0L)) {
+ VirtualFree (szText, 128, MEM_DECOMMIT);
+ return;
+ }
+ szProgMan = DdeCreateStringHandle (lIdInst, "PROGMAN", CP_WINANSI);
+ if (szProgMan) {
+ hConv = DdeConnect (lIdInst, szProgMan, szProgMan, &CCFilter);
+ lstrcpy(szText,app_name);
+ wsprintf (szCommand, "[DeleteGroup(%s)]", szText);
+ hData = DdeCreateDataHandle (lIdInst, szCommand,
+ lstrlen (szCommand) + 1, 0, (HSZ) NULL, CF_TEXT, 0L);
+ if (!DdeClientTransaction ((LPBYTE) hData, 0xFFFFFFFF, hConv,
+ (HSZ) NULL, 0, XTYP_EXECUTE, 10000, &lResult)) {
+ lResult = DdeGetLastError (lIdInst);
+ }
+
+ DdeFreeStringHandle (lIdInst, szProgMan);
+ DdeDisconnect (hConv);
+ } else {
+ lResult = DdeGetLastError (lIdInst);
+ }
+ VirtualFree (szText, 64, MEM_DECOMMIT);
+ VirtualFree (szCommand, 64, MEM_DECOMMIT);
+ DdeUninitialize (lIdInst);
+ lIdInst = 0L;
+ return;
+ } else {
+ }
+}
+
+static BOOL CreateGroup(HWND hwnd) {
+ HDDEDATA hData;
+ LPSTR szText;
+ LPSTR szCommand;
+ HCONV hConv;
+ HSZ szProgMan;
+ LONG lResult;
+ szText = VirtualAlloc (NULL, 64, MEM_COMMIT, PAGE_READWRITE);
+ szCommand = VirtualAlloc (NULL, 128, MEM_COMMIT, PAGE_READWRITE);
+ if (szText) {
+ if (DdeInitialize(&lIdInst, (PFNCALLBACK) GroupDDECallback,
+ (DWORD) APPCMD_CLIENTONLY, 0L)) {
+// MessageBox (hwnd, "DDEML Initialization Failure", "Error", MB_OK);
+ VirtualFree (szText, 128, MEM_DECOMMIT);
+ return (FALSE);
+ }
+ szProgMan = DdeCreateStringHandle (lIdInst, "PROGMAN", CP_WINANSI);
+ if (szProgMan) {
+ hConv = DdeConnect (lIdInst, szProgMan, szProgMan, &CCFilter);
+ lstrcpy(szText,app_name);
+ wsprintf (szCommand, "[CreateGroup(%s)]", szText);
+ hData = DdeCreateDataHandle (lIdInst, szCommand,
+ lstrlen (szCommand) + 1, 0, (HSZ) NULL, CF_TEXT, 0L);
+ if (!DdeClientTransaction ((LPBYTE) hData, 0xFFFFFFFF, hConv,
+ (HSZ) NULL, 0, XTYP_EXECUTE, 10000, &lResult)) {
+ lResult = DdeGetLastError (lIdInst);
+// MessageBox (hwnd, "DdeClientTransaction Failed", "Error",
+ // MB_OK);
+ }
+
+ DdeFreeStringHandle (lIdInst, szProgMan);
+ DdeDisconnect (hConv);
+ } else {
+ lResult = DdeGetLastError (lIdInst);
+ }
+ VirtualFree (szText, 64, MEM_DECOMMIT);
+ VirtualFree (szCommand, 64, MEM_DECOMMIT);
+ DdeUninitialize (lIdInst);
+ lIdInst = 0L;
+ return (TRUE);
+ } else {
+// MessageBox (hwnd, "Memory Allocation failure", "Error", MB_OK);
+ }
+ return (FALSE);
+}
+
+
+static BOOL AddProgramItems (HWND hwnd, LPSTR szDummy) {
+ HDDEDATA hData;
+ HCONV hConv;
+ HSZ szProgMan;
+ int lSelCount;
+ LONG lResult;
+ LPLONG lpSelection;
+ LPSTR szProgName;
+ LPSTR szExePath;
+ LPSTR szExecuteString;
+ int iIndex;
+ int iGroupCount;
+
+ iGroupCount = 2;
+ lSelCount = 3;
+
+ lpSelection = VirtualAlloc (NULL, lSelCount * sizeof (int), MEM_COMMIT,PAGE_READWRITE);
+ if (lpSelection) {
+ if (DdeInitialize (&lIdInst2, (PFNCALLBACK) GroupDDECallback,
+ (DWORD) APPCMD_CLIENTONLY, 0L)) {
+ VirtualFree (lpSelection, lSelCount * sizeof (int), MEM_DECOMMIT);
+ return (FALSE);
+ }
+
+ szProgMan = DdeCreateStringHandle (lIdInst2, "PROGMAN", CP_WINANSI);
+ hConv = DdeConnect (lIdInst2, szProgMan, szProgMan, &CCFilter);
+ DdeFreeStringHandle (lIdInst2, szProgMan);
+ szProgName = VirtualAlloc (NULL, MAX_PATH * 2, MEM_COMMIT, PAGE_READWRITE);
+ szExePath = szProgName + MAX_PATH;
+
+ szExecuteString = VirtualAlloc (NULL, MAX_PATH * 4, MEM_COMMIT,
+ PAGE_READWRITE);
+
+ for (iIndex = 0; iIndex < lSelCount; iIndex++) {
+ {
+ static char *paths[4] = {
+ "Winamp.exe",
+ "WhatsNew.txt",
+ "Winamp.exe"
+ };
+ static char *names[4] =
+ {
+ "Winamp",
+ "What's New",
+ "Uninstall Winamp",
+
+ };
+ lstrcpy(szProgName,names[iIndex]);
+ {
+ szExePath[0] = '\"';
+ GetModuleFileName(NULL,szExePath+1,MAX_PATH);
+ scanstr_back(szExePath,"\\",szExePath-1)[1]=0;
+ lstrcat(szExePath,paths[iIndex]);
+ lstrcat(szExePath,"\"");
+ if (iIndex==2) lstrcat(szExePath," /UNINSTALL");
+ }
+ }
+
+// Create the command string to add the item.
+ wsprintf (szExecuteString, "[AddItem(%s,%s)]", szExePath,
+ (LPARAM) szProgName);
+
+// Create a DDEML Data handle for the command string.
+ hData = DdeCreateDataHandle (lIdInst2, szExecuteString,
+ lstrlen (szExecuteString) + 1, 0, (HSZ) NULL, CF_TEXT, 0L);
+
+// Send the command over to the program manager.
+ if (!DdeClientTransaction ((LPBYTE) hData, 0xFFFFFFFF,
+ hConv, (HSZ) NULL, 0, XTYP_EXECUTE, 1000, &lResult)) {
+ lResult = DdeGetLastError (lIdInst2);
+ }/*endIf*/
+ }/*endFor*/
+
+// Release the memory allocated for path and name retrieval.
+ VirtualFree (szProgName, MAX_PATH * 2, MEM_DECOMMIT);
+
+// Release the command line memory.
+ VirtualFree (szExecuteString, MAX_PATH * 4, MEM_DECOMMIT);
+
+// Disoconnect the DDEML Conversation
+ DdeDisconnect (hConv);
+
+// Release the memory allocate for the list selections.
+ VirtualFree (lpSelection, lSelCount * sizeof (int), MEM_DECOMMIT);
+ }/*endIf*/
+
+// Clear the selection in the lists.
+
+// Uninitialize the local conversation.
+ DdeUninitialize (lIdInst2);
+
+ lIdInst2 = 0L;
+ return (TRUE);
+}/* end AddProgramItems */
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/DecodeFile.cpp b/Src/Winamp/DecodeFile.cpp
new file mode 100644
index 00000000..d1a07388
--- /dev/null
+++ b/Src/Winamp/DecodeFile.cpp
@@ -0,0 +1,202 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include <stddef.h>
+#include "DecodeFile.h"
+#include "ExtendedReader.h"
+#include "OutputPluginAudioStream.h"
+#include "ResamplingReader.h"
+#include "CommonReader.h"
+
+// "input" means input FROM the decoder, "output" means output TO the person using the ifc_audiostream
+static bool RequiresResampling(const AudioParameters *input, size_t outputChannels, size_t outputBits, size_t outputSampleRate)
+{
+ if (outputChannels != input->channels)
+ return true; // need to up or downmix
+
+ if (outputBits != input->bitsPerSample)
+ return true;
+
+ if (outputSampleRate != input->sampleRate)
+ return true;
+
+ return false;
+}
+
+static void SetResamplingParameters(const AudioParameters *input, size_t &outputChannels, size_t &outputBits, size_t &outputSampleRate)
+{
+ // channels
+ if (!outputChannels)
+ outputChannels=input->channels;
+ else if ((input->flags & AUDIOPARAMETERS_MAXCHANNELS) && input->channels <= outputChannels)
+ outputChannels = input->channels;
+
+ // bits
+ if (!outputBits) outputBits = input->bitsPerSample;
+
+ // samplerate
+ if (!outputSampleRate)
+ outputSampleRate = input->sampleRate;
+ else if ((input->flags & AUDIOPARAMETERS_MAXSAMPLERATE) && input->sampleRate <= outputSampleRate)
+ outputSampleRate = input->sampleRate;
+
+}
+
+ifc_audiostream *DecodeFile::OpenAudio(const wchar_t *filename, AudioParameters *parameters)
+{
+ // save some info
+ size_t outputChannels = parameters->channels;
+ size_t outputBits = parameters->bitsPerSample;
+ size_t outputSampleRate = parameters->sampleRate;
+
+ CommonReader *reader = MakeReader(filename, parameters, true);
+ if (!reader)
+ return 0;
+
+ // check if they've requested certain output parameters
+ if (outputChannels || outputBits || outputSampleRate)
+ {
+ SetResamplingParameters(parameters, outputChannels, outputBits, outputSampleRate);
+
+ // check if we need any resampling/conversion
+ if (RequiresResampling(parameters, outputChannels, outputBits, outputSampleRate))
+ {
+ Resampler *resampler = new Resampler(parameters->bitsPerSample, parameters->channels, parameters->sampleRate,
+ outputBits, outputChannels, outputSampleRate, parameters->flags & AUDIOPARAMETERS_FLOAT);
+
+ if (!resampler->OK())
+ {
+ parameters->errorCode = API_DECODEFILE_BAD_RESAMPLE;
+ delete resampler;
+ return 0;
+ }
+
+ parameters->bitsPerSample = (uint32_t)outputBits;
+ parameters->channels = (uint32_t)outputChannels;
+ parameters->sampleRate = (uint32_t)outputSampleRate;
+ parameters->sizeBytes =(size_t)((double)parameters->sizeBytes * resampler->sizeFactor);
+ ResamplingReader *resampleReader = new ResamplingReader(resampler, reader, outputChannels * outputBits / 8);
+
+ return resampleReader;
+ }
+
+ }
+ return reader;
+}
+
+ifc_audiostream *DecodeFile::OpenAudioBackground(const wchar_t *filename, AudioParameters *parameters)
+{
+ // save some info
+ size_t outputChannels = parameters->channels;
+ size_t outputBits = parameters->bitsPerSample;
+ size_t outputSampleRate = parameters->sampleRate;
+
+ CommonReader *reader = MakeReader(filename, parameters, false);
+ if (!reader)
+ return 0;
+
+ // check if they've requested certain output parameters
+ if (outputChannels || outputBits || outputSampleRate)
+ {
+ SetResamplingParameters(parameters, outputChannels, outputBits, outputSampleRate);
+
+ // check if we need any resampling/conversion
+ if (RequiresResampling(parameters, outputChannels, outputBits, outputSampleRate))
+ {
+ Resampler *resampler = new Resampler(parameters->bitsPerSample, parameters->channels, parameters->sampleRate,
+ outputBits, outputChannels, outputSampleRate, parameters->flags & AUDIOPARAMETERS_FLOAT);
+
+ if (!resampler->OK())
+ {
+ parameters->errorCode = API_DECODEFILE_BAD_RESAMPLE;
+ delete resampler;
+ delete reader;
+ return 0;
+ }
+
+ parameters->bitsPerSample = (uint32_t)outputBits;
+ parameters->channels = (uint32_t)outputChannels;
+ parameters->sampleRate = (uint32_t)outputSampleRate;
+
+ ResamplingReader *resampleReader = new ResamplingReader(resampler, reader, outputChannels * outputBits / 8);
+
+ return resampleReader;
+ }
+
+ }
+ return reader;
+}
+
+CommonReader *DecodeFile::MakeReader(const wchar_t *filename, AudioParameters *parameters, bool useUnagi)
+{
+ In_Module *in;
+ int a = 0;
+ bool found = false;
+
+ while (a >= 0)
+ {
+ OpenFunc open = 0, openFloat=0;
+ OpenWFunc openW=0, openWFloat=0;
+ GetDataFunc getData = 0;
+ CloseFunc close = 0;
+ SetTimeFunc setTime = 0;
+
+ in = in_setmod_noplay(filename, &a);
+ if (!in) break;
+ if (a >= 0) a++;
+
+ found = true;
+
+ open = (OpenFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_open");
+ openFloat = (OpenFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_open_float");
+ openW = (OpenWFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_openW");
+ openWFloat = (OpenWFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_openW_float");
+ getData = (GetDataFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_getData");
+ close = (CloseFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_close");
+ setTime = (SetTimeFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_setTime"); //optional!
+ if ((open || openW) && getData && close)
+ {
+ ExtendedReader *reader = new ExtendedReader(open, openW, openFloat, openWFloat, getData, close, setTime);
+ if (reader->Open(filename, parameters))
+ return reader;
+ else
+ delete reader;
+ }
+
+ }
+
+ if (!found || !useUnagi)
+ {
+ parameters->errorCode = API_DECODEFILE_UNSUPPORTED;
+ }
+ else
+ {
+ OutputPluginAudioStream *reader = new OutputPluginAudioStream;
+ in = in_setmod_noplay(filename, 0);
+ if (reader->Open(in, filename, parameters))
+ return reader;
+ delete reader;
+ }
+
+ return 0;
+}
+
+void DecodeFile::CloseAudio(ifc_audiostream *audioStream)
+{
+ CommonReader *reader = static_cast<CommonReader *>(audioStream);
+ delete reader;
+ //audioStream=0;
+}
+
+
+#define CBCLASS DecodeFile
+START_DISPATCH;
+CB(API_DECODEFILE_OPENAUDIO, OpenAudio)
+CB(API_DECODEFILE_OPENAUDIO2, OpenAudioBackground)
+VCB(API_DECODEFILE_CLOSEAUDIO, CloseAudio)
+END_DISPATCH;
diff --git a/Src/Winamp/DecodeFile.h b/Src/Winamp/DecodeFile.h
new file mode 100644
index 00000000..d827045e
--- /dev/null
+++ b/Src/Winamp/DecodeFile.h
@@ -0,0 +1,21 @@
+#ifndef NULLSOFT_WINAMP_DECODEFILE_H
+#define NULLSOFT_WINAMP_DECODEFILE_H
+
+#include "api_decodefile.h"
+#include "CommonReader.h"
+class DecodeFile : public api_decodefile
+{
+public:
+ static const char *getServiceName() { return "File Decode API"; }
+ static const GUID getServiceGuid() { return decodeFileGUID; }
+public:
+ ifc_audiostream *OpenAudio(const wchar_t *filename, AudioParameters *parameters);
+ ifc_audiostream *OpenAudioBackground(const wchar_t *filename, AudioParameters *parameters);
+ void CloseAudio(ifc_audiostream *audioStream);
+protected:
+ RECVS_DISPATCH;
+private:
+ CommonReader *MakeReader(const wchar_t *filename, AudioParameters *parameters, bool useUnagi);
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/DeveloperConfigGroup.cpp b/Src/Winamp/DeveloperConfigGroup.cpp
new file mode 100644
index 00000000..84e6a2eb
--- /dev/null
+++ b/Src/Winamp/DeveloperConfigGroup.cpp
@@ -0,0 +1,57 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "DeveloperConfigGroup.h"
+
+#include "../Agave/Config/ifc_configitem.h"
+#include "WinampAttributes.h"
+
+class MaskBoolConfigItem : public ifc_configitem
+{
+public:
+ MaskBoolConfigItem(int _mask) : mask(_mask) {}
+ bool GetBool()
+ {
+ return !!(config_no_visseh&mask);
+ }
+protected:
+ RECVS_DISPATCH;
+
+private:
+ int mask;
+};
+
+#define CBCLASS MaskBoolConfigItem
+START_DISPATCH;
+CB(IFC_CONFIGITEM_GETBOOL, GetBool)
+END_DISPATCH;
+#undef CBCLASS
+
+static MaskBoolConfigItem sehVisItem(1), sehDSPItem(2), sehGenItem(4), sehIEItem(8);
+
+ifc_configitem *DeveloperConfigGroup::GetItem(const wchar_t *name)
+{
+ if (!wcscmp(name, L"no_visseh"))
+ return &sehVisItem;
+ else if (!wcscmp(name, L"no_dspseh"))
+ return &sehDSPItem;
+ else if (!wcscmp(name, L"no_genseh"))
+ return &sehGenItem;
+ else if (!wcscmp(name, L"no_ieseh"))
+ return &sehIEItem;
+
+ return 0;
+}
+
+
+#define CBCLASS DeveloperConfigGroup
+START_DISPATCH;
+CB(IFC_CONFIGGROUP_GETITEM, GetItem)
+CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/DeveloperConfigGroup.h b/Src/Winamp/DeveloperConfigGroup.h
new file mode 100644
index 00000000..f3368803
--- /dev/null
+++ b/Src/Winamp/DeveloperConfigGroup.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "main.h"
+#include "../Agave/Config/ifc_configgroup.h"
+
+
+// {113D413A-5D1F-4f4c-8AB7-5BDED46033A4}
+static const GUID developerConfigGroupGUID=
+{ 0x113d413a, 0x5d1f, 0x4f4c, { 0x8a, 0xb7, 0x5b, 0xde, 0xd4, 0x60, 0x33, 0xa4 } };
+
+
+class DeveloperConfigGroup : public ifc_configgroup
+{
+public:
+ ifc_configitem *GetItem(const wchar_t *name);
+ GUID GetGUID() { return developerConfigGroupGUID; }
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern DeveloperConfigGroup developerConfigGroup;
diff --git a/Src/Winamp/EQConfigGroup.cpp b/Src/Winamp/EQConfigGroup.cpp
new file mode 100644
index 00000000..00996743
--- /dev/null
+++ b/Src/Winamp/EQConfigGroup.cpp
@@ -0,0 +1,33 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "EqConfigGroup.h"
+#include "WinampAttributes.h"
+
+
+ifc_configitem *EQConfigGroup::GetItem(const wchar_t *name)
+{
+ if (!wcscmp(name, L"frequencies"))
+ return &config_eq_frequencies;
+ else if (!wcscmp(name, L"type"))
+ return &config_eq_type;
+ else if (!wcscmp(name, L"limiter"))
+ return &config_eq_limiter;
+
+
+ return 0;
+}
+
+
+
+#define CBCLASS EQConfigGroup
+START_DISPATCH;
+CB(IFC_CONFIGGROUP_GETITEM, GetItem)
+CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Winamp/EQConfigGroup.h b/Src/Winamp/EQConfigGroup.h
new file mode 100644
index 00000000..28ab65c1
--- /dev/null
+++ b/Src/Winamp/EQConfigGroup.h
@@ -0,0 +1,24 @@
+#ifndef NULLSOFT_WINAMP_EQCONFIGGROUP_H
+#define NULLSOFT_WINAMP_EQCONFIGGROUP_H
+
+#include "main.h"
+#include "../Agave/Config/ifc_configgroup.h"
+
+// {72409F84-BAF1-4448-8211-D84A30A1591A}
+static const GUID eqConfigGroupGUID =
+{ 0x72409f84, 0xbaf1, 0x4448, { 0x82, 0x11, 0xd8, 0x4a, 0x30, 0xa1, 0x59, 0x1a } };
+
+
+class EQConfigGroup : public ifc_configgroup
+{
+public:
+ ifc_configitem *GetItem(const wchar_t *name);
+ GUID GetGUID() { return eqConfigGroupGUID; }
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern EQConfigGroup eqConfigGroup;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Eq.cpp b/Src/Winamp/Eq.cpp
new file mode 100644
index 00000000..df6d7e36
--- /dev/null
+++ b/Src/Winamp/Eq.cpp
@@ -0,0 +1,1025 @@
+#include <windowsx.h>
+
+#include "Main.h"
+#include "api.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+
+unsigned char eq_tab[10] = {31, 31, 31, 31, 31, 31, 31, 31, 31, 31};
+
+static int writeEQfile(wchar_t *file, char *name);
+static int readEQfile(wchar_t *file, char *name);
+static void deleteEQfile(wchar_t *file, char *name);
+static void addEQtolistbox(wchar_t *file, HWND listbox);
+
+static BOOL CALLBACK loadpresetProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK delpresetProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK savepresetProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK loadmp3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK savemp3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK delmp3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK eqProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static int EQ_OnRButtonUp(HWND hwnd, int x, int y, UINT flags);
+static int EQ_OnLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
+{
+ if ((config_dsize && config_eqdsize ? 1 : 0)) { x /= 2; y /= 2; }
+ if (y <= 14 && x < 252)
+ {
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_OPTIONS_WINDOWSHADE_EQ, 0);
+ }
+ return 1;
+}
+
+static int EQ_OnLButtonUp(HWND hwnd, int x, int y, UINT flags);
+static int EQ_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
+static int EQ_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
+static BOOL EQ_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized);
+
+static char last_preset[128] = "Default";
+static char sig[] = "Winamp EQ library file v1.1\x1A!--";
+
+void eq_autoload(const char *mp3fn)
+{
+ if (!config_autoload_eq)
+ return;
+
+ if (readEQfile(EQDIR2, scanstr_back((char*)mp3fn, "\\", (char*)mp3fn - 1) + 1))
+ readEQfile(EQDIR1, "Default");
+
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+}
+
+void eq_dialog(HWND hwnd, int init_state)
+{
+ if (!hEQWindow)
+ return;
+
+ int toggle = Ipc_WindowToggle(IPC_CB_WND_EQ, !config_eq_open);
+ KillTimer(hEQWindow, 3);
+ if (!toggle)
+ return;
+
+ if (!config_eq_open)
+ {
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_EQ, MF_CHECKED);
+ if (eq_startuphack)
+ {
+ if(!GetParent(hEQWindow))
+ SetTimer(hEQWindow, 3, 10, NULL);
+
+ config_eq_open = 1;
+ }
+ else
+ {
+ if(!init_state && !config_minimized)
+ ShowWindow(hEQWindow, SW_SHOWNA);
+
+ config_eq_open = 1;
+
+ if (config_eq_ws)
+ draw_eq_tbar(GetForegroundWindow() == hEQWindow ? 1 : (config_hilite ? 0 : 1));
+
+ set_aot(1);
+ }
+ }
+ else
+ {
+ if (GetForegroundWindow() == hEQWindow || IsChild(hEQWindow, GetForegroundWindow()))
+ {
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_NEXT_WINDOW, 0);
+ }
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_EQ, MF_UNCHECKED);
+ ShowWindow(hEQWindow, SW_HIDE);
+ config_eq_open = 0;
+ }
+ draw_eqplbut(config_eq_open, 0, config_pe_open, 0);
+ return ;
+}
+
+static void
+EqWindow_OnMouseWheel(HWND hwnd, INT virtualKeys, INT distance, LONG pointer_s)
+{
+ SendMessageW(hMainWindow, WM_MOUSEWHEEL, MAKEWPARAM(virtualKeys, distance), (LPARAM)pointer_s);
+}
+
+LRESULT CALLBACK EQ_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_NOTIFY:
+ {
+ LPTOOLTIPTEXT tt = (LPTOOLTIPTEXT)lParam;
+ if(tt->hdr.hwndFrom = hEQTooltipWindow)
+ {
+ switch (tt->hdr.code)
+ {
+ case TTN_SHOW:
+ SetWindowPos(tt->hdr.hwndFrom,HWND_TOPMOST,0,0,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
+ break;
+ }
+ }
+ }
+ break;
+ case WM_DESTROY:
+ KillTimer(hwnd, 3);
+ if (eq_init)
+ draw_eq_kill();
+ if (NULL != WASABI_API_APP) WASABI_API_APP->app_unregisterGlobalWindow(hwnd);
+ break;
+ case WM_TIMER:
+ if (wParam == 3)
+ {
+ KillTimer(hwnd, 3);
+ if (!IsMinimized(hMainWindow))
+ {
+ ShowWindow(hwnd, SW_SHOWNA);
+ }
+
+ // works around a quirk with Bento docked to the right-hand edge
+ // where the pledit is left docked on reverting to classic skin (dro)
+ if(!GetParent(hwnd)) set_aot(1);
+ }
+ break;
+ case WM_DISPLAYCHANGE:
+ InvalidateRect(hwnd, NULL, TRUE);
+ break;
+
+ case WM_SHOWWINDOW:
+ if (wParam == TRUE && lParam == SW_PARENTOPENING && !config_eq_open)
+ {
+ return 0;
+ }
+ break;
+
+ HANDLE_MSG(hwnd, WM_QUERYNEWPALETTE, Main_OnQueryNewPalette);
+ HANDLE_MSG(hwnd, WM_PALETTECHANGED, Main_OnPaletteChanged);
+ HANDLE_MSG(hwnd, WM_LBUTTONUP, EQ_OnLButtonUp);
+ HANDLE_MSG(hwnd, WM_RBUTTONUP, EQ_OnRButtonUp);
+ HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, EQ_OnLButtonDblClk);
+ HANDLE_MSG(hwnd, WM_LBUTTONDOWN, EQ_OnLButtonDown);
+ HANDLE_MSG(hwnd, WM_MOUSEMOVE, EQ_OnMouseMove);
+ HANDLE_MSG(hwnd, WM_NCACTIVATE, EQ_OnNCActivate);
+ case WM_SYSCOMMAND:
+ if ((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER)
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+ break;
+
+ case WM_CLOSE:
+ WASABI_API_APP->main_shutdown();
+ return 0;
+ case WM_PRINTCLIENT:
+ draw_printclient_eq((HDC)wParam, lParam);
+ return 0;
+ case WM_PAINT:
+ draw_paint_eq(hwnd);
+ return 0;
+ case WM_SETCURSOR:
+ if (config_usecursors && !disable_skin_cursors)
+ {
+ if ((HWND)wParam == hEQWindow && HIWORD(lParam) == WM_MOUSEMOVE) eq_ui_handlecursor();
+ return TRUE;
+ }
+ else SetCursor(LoadCursor(NULL, IDC_ARROW));
+ break;
+ case WM_CREATE:
+ hEQWindow = hwnd;
+ SetWindowLongPtrW(hEQWindow, GWLP_USERDATA, (config_keeponscreen&2) ? 0x49474541 : 0);
+ {
+ int w = WINDOW_WIDTH << ((config_dsize && config_eqdsize) ? 1 : 0);
+ int h = ((config_eq_ws ? 14 : WINDOW_HEIGHT)) << ((config_dsize && config_eqdsize) ? 1 : 0);
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE)&~(WS_CAPTION));
+ SetWindowPos(hEQWindow, 0, config_eq_wx, config_eq_wy, w, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_HIDEWINDOW);
+
+ HACCEL hAccel = LoadAcceleratorsW(language_pack_instance, MAKEINTRESOURCEW(IDR_ACCELERATOR_EQ));
+ if (!hAccel && language_pack_instance != hMainInstance) hAccel = LoadAcceleratorsW(hMainInstance, MAKEINTRESOURCEW(IDR_ACCELERATOR_EQ));
+ if (hAccel) WASABI_API_APP->app_addAccelerators(hwnd, &hAccel, 1, TRANSLATE_MODE_NORMAL);
+ }
+ if (NULL != WASABI_API_APP) WASABI_API_APP->app_registerGlobalWindow(hwnd);
+ return 0;
+ case WM_USER:
+ {
+ int x;
+ draw_eq_slid(0, config_preamp, 0);
+ for (x = 1; x <= 10; x ++)
+ draw_eq_slid(x, eq_tab[x - 1], 0);
+ draw_eq_graphthingy();
+ }
+ return 0;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case EQ_PANLEFT:
+ if (config_pan - 4 < -128) config_pan = -128;
+ else
+ {
+ if (config_pan - 4 > 0 && config_pan - 4 < 20) config_pan = 0;
+ else config_pan -= 4;
+ }
+ in_setpan(config_pan);
+ draw_panbar(config_pan, 0);
+ update_panning_text(-2);
+ return 0;
+ case EQ_PANRIGHT:
+ if (config_pan + 4 > 127) config_pan = 127;
+ else
+ {
+ if (config_pan + 4 < 0 && config_pan + 4 > -20) config_pan = 0;
+ else config_pan += 4;
+ }
+ in_setpan(config_pan);
+ draw_panbar(config_pan, 0);
+ update_panning_text(-2);
+ return 0;
+
+ case WINAMP_OPTIONS_WINDOWSHADE:
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_OPTIONS_WINDOWSHADE_EQ, 0);
+ return 0;
+ case IDM_EQ_LOADDEFAULT:
+ readEQfile(EQDIR1, "Default");
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ return 0;
+ case IDM_EQ_SAVEDEFAULT:
+ {
+ writeEQfile(EQDIR1, "Default");
+ }
+ return 0;
+ case ID_SAVE_EQF:
+ case ID_LOAD_EQF:
+ {
+ wchar_t filename[1024] = {0};
+ size_t size, ns;
+ wchar_t *filter, *sf;
+ UINT operation;
+ OPENFILENAMEW l = {sizeof(OPENFILENAMEW), 0};
+
+ size = 1024;
+ filter = (wchar_t*)calloc(size, sizeof(wchar_t));
+ sf = filter;
+ ns = 1;
+
+ getStringW(IDS_P_FILE_EQ, filter, size);
+ StringCbLengthW(filter, size, &ns);
+ size -= (++ns);
+ filter += ns;
+ StringCchCopyW(filter, size, L"*.eqf");
+ StringCbLengthW(filter, size, &ns);
+ size -= (++ns);
+ filter += ns;
+ getStringW(IDS_P_FILE_ALL, filter, size);
+ StringCbLengthW(filter, size, &ns);
+ size -= (++ns);
+ filter += ns;
+ StringCchCopyW(filter, size, L"*.*");
+ StringCbLengthW(filter, size, &ns);
+ //size -= (ns + 2);
+
+ l.hwndOwner = hwnd;
+ l.lpstrFilter = sf;
+ l.lpstrFile = filename;
+ l.nMaxFile = sizeof(filename) - 1;
+
+ operation = (LOWORD(wParam) == ID_SAVE_EQF) ? IDS_P_EQ_FILE_WRITE : IDS_P_EQ_FILE_READ;
+ l.lpstrTitle = getStringW(operation, NULL, 0);
+ l.lpstrDefExt = L"eqf";
+ l.Flags = OFN_HIDEREADONLY | OFN_EXPLORER;
+ UninitDragDrops();
+ if ((LOWORD(wParam) == ID_SAVE_EQF && GetSaveFileNameW(&l)) ||
+ (LOWORD(wParam) != ID_SAVE_EQF && GetOpenFileNameW(&l)))
+ {
+ if (LOWORD(wParam) == ID_SAVE_EQF) writeEQfile(filename, "Entry1");
+ else
+ {
+ readEQfile(filename, "Entry1");
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ }
+ }
+ InitDragDrops();
+ free(sf);
+ }
+
+ return 0;
+ case IDM_EQ_SAVEPRE:
+ LPDialogBoxW(IDD_SAVEPRESET, DIALOG_PARENT(hwnd), (WNDPROC)savepresetProc);
+ return 0;
+ case IDM_EQ_SAVEMP3:
+ LPDialogBoxW(IDD_SAVEPRESET, DIALOG_PARENT(hwnd), (WNDPROC)savemp3Proc);
+ return 0;
+ case IDM_EQ_LOADPRE:
+ LPDialogBoxW(IDD_LOADPRESET, DIALOG_PARENT(hwnd), (WNDPROC)loadpresetProc);
+ return 0;
+ case IDM_EQ_DELPRE:
+ LPDialogBoxW(IDD_LOADPRESET, DIALOG_PARENT(hwnd), (WNDPROC)delpresetProc);
+ return 0;
+ case IDM_EQ_DELMP3:
+ LPDialogBoxW(IDD_LOADPRESET, DIALOG_PARENT(hwnd), (WNDPROC)delmp3Proc);
+ return 0;
+ case IDM_EQ_LOADMP3:
+ LPDialogBoxW(IDD_LOADPRESET, DIALOG_PARENT(hwnd), (WNDPROC)loadmp3Proc);
+ return 0;
+ case EQ_PRESETS:
+ {
+ extern HMENU top_menu;
+ POINT p = {218, 19};
+ if ((config_dsize && config_eqdsize))
+ {
+ p.x *= 2;
+ p.y *= 2;
+ }
+ ClientToScreen(hEQWindow, &p);
+ DoTrackPopup(GetSubMenu(top_menu, 1), TPM_LEFTALIGN, p.x, p.y, hEQWindow);
+ }
+ return 0;
+ case EQ_AUTO:
+ config_autoload_eq = !config_autoload_eq;
+ draw_eq_onauto(config_use_eq, config_autoload_eq, 0, 0);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ return 0;
+ case EQ_ENABLE:
+ config_use_eq = !config_use_eq;
+ eq_set(config_use_eq, (char*)eq_tab, config_preamp);
+ draw_eq_onauto(config_use_eq, config_autoload_eq, 0, 0);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ return 0;
+ case WINAMP_NEXT_WINDOW:
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+ case ID_PE_CLOSE:
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_OPTIONS_EQ, 0);
+ return 0;
+ default:
+ {
+ int id = LOWORD(wParam);
+ if (id == EQ_INCPRE || id == EQ_DECPRE ||
+ (id >= EQ_DEC1 && id <= EQ_DEC10) ||
+ (id >= EQ_INC1 && id <= EQ_INC10))
+ {
+ int x;
+ int addsub = ((id >= EQ_DEC1 && id <= EQ_DEC10) || id == EQ_DECPRE) ? -2 : 2;
+ if (id == EQ_INCPRE || id == EQ_DECPRE)
+ {
+ config_preamp -= addsub;
+ if (config_preamp < 0) config_preamp = 0;
+ if (config_preamp > 63) config_preamp = 63;
+ }
+ else
+ {
+ int o = (id - (addsub > 0 ? EQ_INC1 : EQ_DEC1));
+ int p = eq_tab[o];
+ p -= addsub;
+ if (p < 0) p = 0;
+ if (p > 63) p = 63;
+ eq_tab[o] = p;
+ }
+ draw_eq_slid(0, config_preamp, 0);
+ for (x = 1; x <= 10; x ++)
+ draw_eq_slid(x, eq_tab[x - 1], 0);
+ draw_eq_graphthingy();
+ eq_set(config_use_eq, (char*)eq_tab, config_preamp);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ }
+ else
+ {
+ SendMessageW(hMainWindow, uMsg, wParam, lParam);
+ if (GetForegroundWindow() == hMainWindow) SetForegroundWindow(hEQWindow);
+ }
+ }
+ }
+ return 0;
+ case WM_MOUSEWHEEL:
+ EqWindow_OnMouseWheel(hwnd, LOWORD(wParam), (SHORT)HIWORD(wParam), (LONG)lParam);
+ return 0;
+ }
+
+ if (FALSE != IsDirectMouseWheelMessage(uMsg))
+ {
+ SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static BOOL CALLBACK loadpresetProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static unsigned char eqtbk[10];
+ static int eqpa;
+ static char lpp[512];
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ addEQtolistbox(EQDIR1, GetDlgItem(hwndDlg, IDC_LOADEQLIST));
+ int x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)last_preset);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+ StringCchCopyA(lpp, 512, last_preset);
+
+ // show window and restore last position as applicable
+ POINT pt = {load_rect.left, load_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, load_rect.left, load_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+
+ eqpa = config_preamp;
+ memcpy(eqtbk, eq_tab, sizeof(eqtbk));
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ SendMessageA(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) last_preset);
+ readEQfile(EQDIR1, last_preset);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 0);
+ return FALSE;
+ case IDCANCEL:
+ config_preamp = eqpa;
+ memcpy(eq_tab, eqtbk, sizeof(eqtbk));
+ StringCchCopyA(last_preset, 128, lpp);
+ SendMessageW(hEQWindow, WM_USER, 0, 0);
+ eq_set(config_use_eq, (char*)eq_tab, config_preamp);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 1);
+ return FALSE;
+ case IDC_LOADEQLIST:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ SendMessageW(hwndDlg, WM_COMMAND, IDOK, 0);
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ SendMessageA(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) last_preset);
+ readEQfile(EQDIR1, last_preset);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ }
+ return FALSE;
+ }
+ return FALSE;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK loadmp3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static unsigned char eqtbk[10];
+ static int eqpa;
+ char buf[1024] = {0};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ addEQtolistbox(EQDIR2, GetDlgItem(hwndDlg, IDC_LOADEQLIST));
+ SetWindowTextA(hwndDlg, getString(IDS_LOADAUTOLOAD, NULL, 0));
+ {
+ int x;
+ const wchar_t *filespec = PathFindFileNameW(FileName);
+ WideCharToMultiByteSZ(CP_ACP, 0, filespec, -1, buf, 1024, 0, 0);
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), buf);
+ x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)buf);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+
+ // show window and restore last position as applicable
+ POINT pt = {load_rect.left, load_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, load_rect.left, load_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+ }
+ eqpa = config_preamp;
+ memcpy(eqtbk, eq_tab, sizeof(eqtbk));
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) buf);
+ readEQfile(EQDIR2, buf);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 0);
+ return FALSE;
+ case IDCANCEL:
+ config_preamp = eqpa;
+ memcpy(eq_tab, eqtbk, sizeof(eqtbk));
+ SendMessageW(hEQWindow, WM_USER, 0, 0);
+ eq_set(config_use_eq, (char*)eq_tab, config_preamp);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 1);
+ return FALSE;
+ case IDC_LOADEQLIST:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ SendMessageW(hwndDlg, WM_COMMAND, IDOK, 0);
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) buf);
+ readEQfile(EQDIR2, buf);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), 1);
+ }
+ return FALSE;
+ }
+ return FALSE;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK savepresetProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ char buf[1024] = {0};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ addEQtolistbox(EQDIR1, GetDlgItem(hwndDlg, IDC_LOADEQLIST));
+ {
+ int x;
+ StringCchCopyA(buf, 1024, last_preset);
+ SetWindowTextA( GetDlgItem( hwndDlg, IDC_SAVEPRESET_EDIT ), buf );
+ x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)buf);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+
+ // show window and restore last position as applicable
+ POINT pt = {load_rect.left, load_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, load_rect.left, load_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+ }
+
+ SendMessageW(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), EM_LIMITTEXT, _MAX_FNAME, 0);
+
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), last_preset, sizeof(last_preset) - 1);
+ writeEQfile(EQDIR1, last_preset);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 0);
+ return FALSE;
+ case IDCANCEL:
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 1);
+ return FALSE;
+ case IDC_LOADEQLIST:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ SendMessageW(hwndDlg, WM_COMMAND, IDOK, 0);
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) buf);
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), buf);
+ }
+ return FALSE;
+ case IDC_SAVEPRESET_EDIT:
+ if (HIWORD(wParam) == EN_CHANGE)
+ {
+ int x;
+ GetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), buf, sizeof(buf) - 1);
+ if (lstrlenA(buf)) EnableWindow(GetDlgItem(hwndDlg, IDOK), 1);
+ else EnableWindow(GetDlgItem(hwndDlg, IDOK), 0);
+
+ x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)buf);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+ }
+ }
+ return FALSE;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK savemp3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ char buf[1024] = {0};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ addEQtolistbox(EQDIR2, GetDlgItem(hwndDlg, IDC_LOADEQLIST));
+ {
+ int x;
+ const wchar_t *filespec = PathFindFileNameW(FileName);
+ WideCharToMultiByteSZ(CP_ACP, 0, filespec, -1, buf, 1024, 0, 0);
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), buf);
+ x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)buf);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+ SetWindowTextA(hwndDlg, getString(IDS_SAVEAUTOLOAD, NULL, 0));
+
+ // show window and restore last position as applicable
+ POINT pt = {load_rect.left, load_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, load_rect.left, load_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+ }
+ SendMessageW(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), EM_LIMITTEXT, _MAX_FNAME, 0);
+
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), buf, sizeof(buf) - 1);
+ writeEQfile(EQDIR2, buf);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 0);
+ return FALSE;
+ case IDCANCEL:
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 1);
+ return FALSE;
+ case IDC_LOADEQLIST:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ SendMessageW(hwndDlg, WM_COMMAND, IDOK, 0);
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) buf);
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), buf);
+ }
+ return FALSE;
+ case IDC_SAVEPRESET_EDIT:
+ if (HIWORD(wParam) == EN_CHANGE)
+ {
+ int x;
+ GetWindowTextA(GetDlgItem(hwndDlg, IDC_SAVEPRESET_EDIT), buf, sizeof(buf) - 1);
+ x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)buf);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+ }
+ }
+ return FALSE;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK delpresetProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ addEQtolistbox(EQDIR1, GetDlgItem(hwndDlg, IDC_LOADEQLIST));
+ if (SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCOUNT, 0, 0) == 0)
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), 0);
+ SetWindowTextA(hwndDlg, getString(IDS_DELETEPRE1, NULL, 0));
+ SetWindowTextA(GetDlgItem(hwndDlg, IDOK), getString(IDS_DELETEAUTOLOAD2, NULL, 0));
+ int x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)last_preset);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+
+ // show window and restore last position as applicable
+ POINT pt = {load_rect.left, load_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, load_rect.left, load_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) last_preset);
+ deleteEQfile(EQDIR1, last_preset);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 0);
+ return FALSE;
+ case IDCANCEL:
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 1);
+ return FALSE;
+ case IDC_LOADEQLIST:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ SendMessageW(hwndDlg, WM_COMMAND, IDOK, 0);
+ return FALSE;
+ }
+ return FALSE;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK delmp3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ char buf[1024] = {0};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ addEQtolistbox(EQDIR2, GetDlgItem(hwndDlg, IDC_LOADEQLIST));
+ if (SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCOUNT, 0, 0) == 0)
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), 0);
+ SetWindowTextA(hwndDlg, getString(IDS_DELETEAUTOLOAD1, NULL, 0));
+ SetWindowTextA(GetDlgItem(hwndDlg, IDOK), getString(IDS_DELETEAUTOLOAD2, NULL, 0));
+ const wchar_t *filespec = PathFindFileNameW(FileName);
+ WideCharToMultiByteSZ(CP_ACP, 0, filespec, -1, buf, 1024, 0, 0);
+ int x = SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)buf);
+ if (x != LB_ERR)
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)x, 0);
+ else
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_SETCURSEL, (WPARAM)-1, 0);
+
+ // show window and restore last position as applicable
+ POINT pt = {load_rect.left, load_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, load_rect.left, load_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETTEXT,
+ SendMessageW(GetDlgItem(hwndDlg, IDC_LOADEQLIST), LB_GETCURSEL, 0, 0),
+ (LPARAM) buf);
+ deleteEQfile(EQDIR2, buf);
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 0);
+ return FALSE;
+ case IDCANCEL:
+ GetWindowRect(hwndDlg, &load_rect);
+ EndDialog(hwndDlg, 1);
+ return FALSE;
+ case IDC_LOADEQLIST:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ SendMessageW(hwndDlg, WM_COMMAND, IDOK, 0);
+ return FALSE;
+ }
+ return FALSE;
+ }
+ return 0;
+}
+
+static int EQ_OnRButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ POINT p;
+ extern HMENU top_menu;
+ GetCursorPos(&p);
+ if ((config_dsize && config_eqdsize))
+ {
+ x /= 2;
+ y /= 2;
+ }
+
+ if ((flags & MK_LBUTTON)) return 1;
+
+ if (x >= 14 && y >= 18 && x <= 14 + 25 && y <= 18 + 12)
+ {
+ HMENU hmenu = GetSubMenu(GetSubMenu(top_menu, 4), 0);
+ CheckMenuItem(hmenu, EQ_ENABLE, config_use_eq ? MF_CHECKED : MF_UNCHECKED);
+ DoTrackPopup(hmenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else if (x >= 14 + 25 && y >= 18 && x <= 14 + 25 + 33 && y <= 18 + 12)
+ {
+ HMENU hmenu = GetSubMenu(GetSubMenu(top_menu, 4), 1);
+ CheckMenuItem(hmenu, EQ_AUTO, config_autoload_eq ? MF_CHECKED : MF_UNCHECKED);
+ DoTrackPopup(hmenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else
+ {
+ DoTrackPopup(main_menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hMainWindow);
+ }
+ return 1;
+}
+
+static int EQ_OnLButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ ReleaseCapture();
+ if ((config_dsize && config_eqdsize))
+ {
+ equi_handlemouseevent(x / 2, y / 2, -1, flags);
+ }
+ else
+ {
+ equi_handlemouseevent(x, y, -1, flags);
+ }
+ return 1;
+}
+
+// Mousedown handler. Just passes to routines in ui.c, scaling if in doublesize mode
+static int EQ_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
+{
+ if ((config_dsize && config_eqdsize))
+ {
+ x /= 2;
+ y /= 2;
+ }
+
+ SetCapture(hwnd);
+ equi_handlemouseevent(x, y, 1, keyFlags);
+ return 1;
+}
+
+// Mousemove handler. Just passes to routines in ui.c, scaling if in doublesize mode
+static int EQ_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
+{
+ if ((config_dsize && config_eqdsize))
+ {
+ x /= 2;
+ y /= 2;
+ }
+
+ equi_handlemouseevent(x, y, 0, keyFlags);
+ return 1;
+}
+
+static BOOL EQ_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized)
+{
+ if (fActive == FALSE)
+ {
+ draw_eq_tbar(config_hilite ? 0 : 1);
+ }
+ else
+ {
+ draw_eq_tbar(1);
+ }
+ return TRUE;
+}
+
+int writeEQfile_init(wchar_t *file, char *name, unsigned char *tab)
+{
+ unsigned char preamp = 31;
+ char s[2048] = {0};
+ DWORD a = 0;
+ HANDLE hFile = CreateFileW(file, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) return 1;
+ ReadFile(hFile, s, lstrlenA(sig), &a, NULL);
+ if (memcmp(s, sig, lstrlenA(sig)))
+ {
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ a = 0; WriteFile(hFile, sig, lstrlenA(sig), &a, NULL);
+ SetEndOfFile(hFile);
+ }
+ while (1)
+ {
+ a = 0;
+ ReadFile(hFile, s, _MAX_FNAME + 1 + 10 + 1, &a, NULL);
+ if (a != _MAX_FNAME + 1 + 10 + 1)
+ {
+ SetFilePointer(hFile, 0, NULL, FILE_END);
+ break;
+ }
+ if (!_stricmp(name, s))
+ {
+ CloseHandle(hFile);
+ return 0; // don't write it
+ }
+ }
+ StringCchCopyExA(s, _MAX_FNAME+1, name, 0, 0, STRSAFE_FILL_BEHIND_NULL);
+ memcpy(s + _MAX_FNAME + 1, tab, 10);
+ memcpy(s + _MAX_FNAME + 1 + 10, &preamp, 1);
+ a = 0; WriteFile(hFile, s, _MAX_FNAME + 1 + 10 + 1, &a, NULL);
+ CloseHandle(hFile);
+ return 0;
+}
+
+static int writeEQfile(wchar_t *file, char *name)
+{
+ char s[2048] = {0};
+ DWORD a = 0;
+ HANDLE hFile = CreateFileW(file, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) return 1;
+ ReadFile(hFile, s, lstrlenA(sig), &a, NULL);
+ if (memcmp(s, sig, lstrlenA(sig)))
+ {
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ a = 0; WriteFile(hFile, sig, lstrlenA(sig), &a, NULL);
+ SetEndOfFile(hFile);
+ }
+ while (1)
+ {
+ a = 0;
+ ReadFile(hFile, s, _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp), &a, NULL);
+ if (a != _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp))
+ {
+ SetFilePointer(hFile, 0, NULL, FILE_END);
+ break;
+ }
+ if (!_stricmp(name, s))
+ {
+ SetFilePointer(hFile, -(signed)a, NULL, FILE_CURRENT);
+ break;
+ }
+ }
+ StringCchCopyExA(s, _MAX_FNAME+1, name, 0, 0, STRSAFE_FILL_BEHIND_NULL);
+ memcpy(s + _MAX_FNAME + 1, eq_tab, sizeof(eq_tab));
+ memcpy(s + _MAX_FNAME + 1 + sizeof(eq_tab), &config_preamp, sizeof(config_preamp));
+ a = 0; WriteFile(hFile, s, _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp), &a, NULL);
+ CloseHandle(hFile);
+ return 0;
+}
+
+static int readEQfile(wchar_t *file, char *name)
+{
+ char s[2048] = {0};
+ DWORD a = 0;
+ HANDLE hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) return 1;
+ ReadFile(hFile, s, lstrlenA(sig), &a, NULL);
+ if (memcmp(s, sig, lstrlenA(sig)))
+ {
+ CloseHandle(hFile);
+ return 1;
+ }
+ while (1)
+ {
+ a = 0;
+ ReadFile(hFile, s, _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp), &a, NULL);
+ if (a != _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp))
+ {
+ CloseHandle(hFile);
+ return 1;
+ }
+ if (!_stricmp(name, s))
+ break;
+ }
+ CloseHandle(hFile);
+ memcpy(eq_tab, s + _MAX_FNAME + 1, sizeof(eq_tab));
+ memcpy(&config_preamp, s + _MAX_FNAME + 1 + sizeof(eq_tab), sizeof(config_preamp));
+ eq_set(config_use_eq, (char*)eq_tab, config_preamp);
+ if (hEQWindow) SendMessageW(hEQWindow, WM_USER, 0, 0);
+ return 0;
+}
+
+static void deleteEQfile(wchar_t *file, char *name)
+{
+ wchar_t tmpfile[2048] = {0};
+ char s[2048] = {0};
+ DWORD a = 0;
+ HANDLE hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) return ;
+ StringCchPrintfW(tmpfile, 2048, L"%s.TMP", file);
+ HANDLE hFileOut = CreateFileW(tmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFileOut == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hFile);
+ return ;
+ }
+ ReadFile(hFile, s, lstrlenA(sig), &a, NULL);
+ a = 0; WriteFile(hFileOut, s, lstrlenA(sig), &a, NULL);
+ while (1)
+ {
+ a = 0;
+ ReadFile(hFile, s, _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp), &a, NULL);
+ if (a != _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp))
+ {
+ break;
+ }
+ if (_stricmp(name, s))
+ WriteFile(hFileOut, s, a, &a, NULL);
+ }
+ CloseHandle(hFile);
+ CloseHandle(hFileOut);
+ DeleteFileW(file);
+ StringCchPrintfW(tmpfile, 2048, L"%s.TMP", file);
+ MoveFileW(tmpfile, file);
+ return ;
+}
+
+static void addEQtolistbox(wchar_t *file, HWND listbox)
+{
+ char s[2048] = {0};
+ DWORD l = 0;
+ HANDLE hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) return ;
+ ReadFile(hFile, s, lstrlenA(sig), &l, NULL);
+ if (memcmp(s, sig, lstrlenA(sig)))
+ {
+ CloseHandle(hFile);
+ return ;
+ }
+ while (1)
+ {
+ DWORD a = 0;
+ ReadFile(hFile, s, _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp), &a, NULL);
+ if (a != _MAX_FNAME + 1 + sizeof(eq_tab) + sizeof(config_preamp))
+ break;
+ SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)s); // Must stay in ANSI mode
+ }
+ CloseHandle(hFile);
+} \ No newline at end of file
diff --git a/Src/Winamp/Equi.cpp b/Src/Winamp/Equi.cpp
new file mode 100644
index 00000000..0359b2fb
--- /dev/null
+++ b/Src/Winamp/Equi.cpp
@@ -0,0 +1,421 @@
+#include "Main.h"
+#include "WinampAttributes.h"
+#include "resource.h"
+
+#define inreg(x,y,x2,y2) \
+ ((mouse_x <= ( x2 ) && mouse_x >= ( x ) && \
+ mouse_y <= ( y2 ) && mouse_y >= ( y )))
+
+static int mouse_x, mouse_y, mouse_type, mouse_stats;
+
+static int which_cap=0;
+enum { NO_CAP,TITLE_CAP,TB_CAP,QB_CAP,TOGBUTS_CAP,PB_CAP, PAN_CAP,VOL_CAP, SLID_CAP=100 };
+
+static void do_titlebar();
+static void do_titlebuttons();
+static void do_quickbuts();
+static void do_sliders(int which);
+static void do_togbuts();
+static void do_volctrl();
+static void do_panctrl();
+static void do_presetbutton();
+
+void equi_handlemouseevent(int x, int y, int type, int stats)
+{
+ mouse_x = x;
+ mouse_y = y;
+ mouse_type = type;
+ mouse_stats = stats;
+ switch (which_cap)
+ {
+ case PAN_CAP:
+ do_panctrl();
+ return;
+ case VOL_CAP:
+ do_volctrl();
+ return;
+ case PB_CAP:
+ do_presetbutton();
+ return;
+ case TOGBUTS_CAP:
+ do_togbuts();
+ return;
+ case TITLE_CAP:
+ do_titlebar();
+ return;
+ case TB_CAP:
+ do_titlebuttons();
+ return;
+ case QB_CAP:
+ do_quickbuts();
+ return;
+ default:
+ if (which_cap >= SLID_CAP)
+ {
+ do_sliders(which_cap-SLID_CAP);
+ return;
+ }
+ }
+ if (config_eq_ws)
+ {
+ do_volctrl();
+ do_panctrl();
+ }
+ else
+ {
+ for (x = 0; x < 11; x ++)
+ do_sliders(x);
+ }
+ do_titlebuttons();
+ do_quickbuts();
+ do_togbuts();
+ do_presetbutton();
+ do_titlebar();
+}
+
+static void do_volctrl()
+{
+ extern int do_volbar_active;
+ if (inreg(61,3,162,11) || which_cap==VOL_CAP)
+ {
+ if (mouse_type == 1 && !which_cap) which_cap=VOL_CAP;
+ if (which_cap==VOL_CAP && mouse_stats & MK_LBUTTON)
+ {
+ int t=mouse_x-61;
+ if (t < 0) t=0;
+ if (t > 157-61) t=157-61;
+ config_volume=(t*255)/(157-61);
+ in_setvol(config_volume);
+ draw_volumebar(config_volume,0);
+ update_volume_text(-1);
+ do_volbar_active=1;
+ }
+ if (mouse_type == -1 && which_cap == VOL_CAP)
+ {
+ which_cap=0;
+ do_volbar_active=0;
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ }
+ }
+ else if (which_cap==VOL_CAP)
+ {
+ which_cap=0;
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ do_volbar_active=0;
+ }
+}
+
+static void do_panctrl()
+{
+ extern int do_volbar_active;
+ if (inreg(163,3,206,11) || which_cap==PAN_CAP)
+ {
+ if (mouse_type == 1 && !which_cap) which_cap=PAN_CAP;
+ if (which_cap==PAN_CAP && mouse_stats & MK_LBUTTON)
+ {
+ int t=mouse_x-164;
+ if (t < 0) t=0;
+ if (t > 206-164) t=206-164;
+ int p = (t*255)/(206-164)-127;
+ config_pan = (p > 127 ? 127 : p);
+ // changed in 5.64 to have a lower limit (~18% vs 9%) and for
+ // holding shift to drop the central clamp (allows 4% balance)
+ // and the above change fixes the balance to be even going +/-
+ if (!(mouse_stats & MK_SHIFT)) if (config_pan < 9 && config_pan > -9) config_pan=0;
+ in_setpan(config_pan);
+ draw_panbar(config_pan,0);
+ update_panning_text(-1);
+ do_volbar_active=1;
+ }
+ if (mouse_type == -1 && which_cap == PAN_CAP)
+ {
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ do_volbar_active=0;
+ which_cap=0;
+ }
+ }
+ else if (which_cap==PAN_CAP)
+ {
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ do_volbar_active=0;
+ which_cap=0;
+ }
+}
+
+static void do_presetbutton()
+{
+ if (inreg(217,18,217+44,18+12))
+ {
+ if (!which_cap && mouse_stats & MK_LBUTTON)
+ {
+ draw_eq_presets(1);
+ which_cap = PB_CAP;
+ }
+ if (mouse_type == -1 && which_cap == PB_CAP)
+ {
+ draw_eq_presets(0);
+ which_cap=0;
+ SendMessageW(hEQWindow,WM_COMMAND,EQ_PRESETS,0);
+ }
+ } else if (which_cap == PB_CAP)
+ {
+ which_cap=0;
+ draw_eq_presets(0);
+ }
+}
+
+static void do_togbuts()
+{
+ if (inreg(14,18,14+25+33,18+12))
+ {
+ int w=mouse_x >= 14+25 ? 1 : 0;
+ if (mouse_type == -1)
+ {
+ if (w)
+ {
+ config_autoload_eq=!config_autoload_eq;
+ }
+ else
+ {
+ config_use_eq=!config_use_eq;
+ }
+ eq_set(config_use_eq, (char*)eq_tab,config_preamp);
+ draw_eq_onauto(config_use_eq, config_autoload_eq, 0,0);
+ PostMessageW(hMainWindow,WM_WA_IPC,IPC_CB_MISC_EQ,IPC_CB_MISC);
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ which_cap = TOGBUTS_CAP;
+ draw_eq_onauto(config_use_eq, config_autoload_eq, w?0:1,w?1:0);
+ }
+ } else if (which_cap == TOGBUTS_CAP)
+ {
+ which_cap=0;
+ draw_eq_onauto(config_use_eq, config_autoload_eq, 0,0);
+ }
+}
+
+static void do_sliders(int which)
+{
+ int top=39,bottom=98;
+ int xoffs,w=33-21;
+
+ if (!which) xoffs=21;
+ else xoffs=78+(which-1)*(96-78);
+
+ if (which_cap == SLID_CAP+which || inreg(xoffs,top,xoffs+w,bottom))
+ {
+ unsigned char *b = (which?eq_tab+which-1:&config_preamp);
+ if (mouse_type == 1 || which_cap == SLID_CAP+which || (!which_cap && mouse_stats & MK_LBUTTON))
+ {
+ static int click_yoffs=5;
+ int num_pos=63-11;
+ int d;
+ int p;
+ int t= (mouse_type == -1 || (!(mouse_x >= xoffs-3 && mouse_x <= xoffs+w+3) && (mouse_y >= top && mouse_y <= bottom && mouse_x >= 78 && mouse_x <= 180+78) && which));
+ p=63-12-((63-*b)*num_pos)/64;
+ if (mouse_type == 1 && mouse_y-top >= p-1 && mouse_y-top < p + 11)
+ {
+ click_yoffs=mouse_y-top - p;
+ } else if (mouse_type == 1)
+ click_yoffs=5;
+ d=((mouse_y-click_yoffs-top)*64)/num_pos;
+ if (d < 0) d = 0;
+ if (d > 63) d = 63;
+
+ // changed in 5.66 for holding shift to drop the central clamp (allows 7% balance)
+ if (!(mouse_stats & MK_SHIFT)) if (d >= 30 && d <= 32) d=31;
+
+ *b = d;
+ draw_eq_slid(which,*b,t? 0 : 1);
+ draw_eq_graphthingy();
+ if (t)
+ {
+ do_posbar_active=0;
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ which_cap=0;
+ } else
+ {
+ wchar_t buf[128] = {0};
+ float v=(float)d;
+ static wchar_t preampStr[64];
+ static wchar_t *bands[11] =
+ {
+ preampStr, // PREAMP
+ L"70",L"180",L"320",L"600", // Hz
+ L"1",L"3",L"6",L"12",L"14",L"16" // KHz
+ };
+ static wchar_t *bandsISO[11] =
+ {
+ preampStr, // PREAMP
+ L"31.5",L"63",L"125",L"250", // Hz
+ L"500",L"1",L"2",L"4",L"8",L"16" // KHz
+ };
+ getStringW(IDS_PREAMP,preampStr,64);
+ v -= 31.5f;
+ v /= 31.5f;
+ v *= -12.0f;
+ if (v >= -0.32 && v <= 0.32) v=0.0;
+
+ wchar_t HZStr[16] = {0};
+ getStringW((which<5+!(config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?IDS_EQ_HZ:IDS_EQ_KHZ),HZStr,16);
+ StringCchPrintfW(buf,128,L"EQ: %s%s: %s%0.01f %s",
+ ((config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?bands[which]:bandsISO[which]),
+ (!which?L"":HZStr),
+ v>=0.0?L"+":L"", v,
+ getStringW(IDS_EQ_DB,NULL,0));
+
+ d=0;
+ do_posbar_active=1;
+ draw_songname(buf,&d,-1);
+ which_cap = SLID_CAP+which;
+ }
+ eq_set(config_use_eq, (char*)eq_tab,config_preamp);
+ PostMessageW(hMainWindow,WM_WA_IPC,IPC_CB_MISC_EQ,IPC_CB_MISC);
+ }
+ }
+}
+
+static void do_quickbuts()
+{
+ int l=42, r=67;
+ if (inreg(l,65,r,74) || inreg(l,33,r,42) || inreg(l,92,r,101)) // +0
+ {
+ if (mouse_type == -1 && which_cap == QB_CAP)
+ {
+ int v;
+ which_cap=0;
+ if (mouse_y <= 42) v=0;
+ else if (mouse_y <= 74) v=31;
+ else v=63;
+
+ memset(eq_tab,v,10);
+ {
+ int x;
+ for (x = 1; x <= 10; x ++)
+ draw_eq_slid(x,eq_tab[x-1],0);
+ }
+ eq_set(config_use_eq, (char*)eq_tab,config_preamp);
+ draw_eq_graphthingy();
+ PostMessageW(hMainWindow,WM_WA_IPC,IPC_CB_MISC_EQ,IPC_CB_MISC);
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ which_cap=QB_CAP;
+ }
+ }
+ else if (which_cap == QB_CAP)
+ {
+ which_cap=0;
+ }
+}
+
+static void do_titlebar()
+{
+ if (which_cap == TITLE_CAP || (!which_cap && (config_easymove || mouse_y < 14)))
+ {
+ static int clickx, clicky;
+ switch (mouse_type)
+ {
+ case 1:
+ {
+ which_cap=TITLE_CAP;
+ clickx=mouse_x;
+ clicky=mouse_y;
+ }
+ break;
+ case -1:
+ which_cap=0;
+ break;
+ case 0:
+ if (which_cap == TITLE_CAP && mouse_stats & MK_LBUTTON)
+ {
+ POINT p = { mouse_x,mouse_y};
+ ClientToScreen(hEQWindow,&p);
+ config_eq_wx = p.x-clickx;
+ config_eq_wy = p.y-clicky;
+ if ((!!config_snap) ^ (!!(mouse_stats & MK_SHIFT)))
+ {
+ RECT rr;
+ EstEQWindowRect(&rr);
+ SnapWindowToAllWindows(&rr,hEQWindow);
+ SetEQWindowRect(&rr);
+ }
+ SetWindowPos(hEQWindow,0,config_eq_wx,config_eq_wy,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ break;
+ }
+ }
+}
+
+static void do_titlebuttons()
+{
+ if (inreg(253,3,264+9,3+9)) // kill button
+ {
+ int ws;
+ if (mouse_x < 264) ws=1;
+ else ws=0;
+ if (mouse_type == -1 && which_cap == TB_CAP)
+ {
+ which_cap=0;
+ draw_eq_tbutton(0,0);
+ if (ws==0) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_EQ,0);
+ else SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_WINDOWSHADE_EQ,0);
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ which_cap=TB_CAP;
+ if (ws) draw_eq_tbutton(0,1);
+ else draw_eq_tbutton(1,0);
+ }
+ }
+ else if (which_cap == TB_CAP)
+ {
+ which_cap=0;
+ draw_eq_tbutton(0,0);
+ }
+}
+
+void eq_ui_handlecursor(void)
+{
+ int mouse_x, mouse_y;
+ POINT p;
+ static RECT b[] =
+ {
+ {264,3,272,12},//close
+ {0,0,275,13},// titelbar
+ };
+ int b_len;
+ int x;
+ if (!config_usecursors || disable_skin_cursors) return;
+ b_len = sizeof(b)/sizeof(b[0]);
+ GetCursorPos(&p);
+ ScreenToClient(hEQWindow,&p);
+ mouse_x=p.x;
+ mouse_y=p.y;
+ if (config_dsize && config_eqdsize) { mouse_x/=2; mouse_y/=2;}
+
+ {
+ int y;
+ x=1;
+ for (y = 0; y < 11; y ++)
+ {
+ int top=39,bottom=98;
+ int xoffs,w=33-21;
+ if (!y) xoffs=21;
+ else xoffs=78+(y-1)*(96-78);
+ if (inreg(xoffs,top,xoffs+w,bottom))
+ {
+ x=0;
+ break;
+ }
+ }
+ if (x) for (x = 1; x <= b_len; x ++)
+ if (inreg(b[x-1].left,b[x-1].top,b[x-1].right,b[x-1].bottom)) break;
+ }
+
+ x+=25;
+
+ if (Skin_Cursors[x]) SetCursor(Skin_Cursors[x]);
+ else SetCursor(LoadCursor(NULL,IDC_ARROW));
+} \ No newline at end of file
diff --git a/Src/Winamp/ExplorerFindFile.cpp b/Src/Winamp/ExplorerFindFile.cpp
new file mode 100644
index 00000000..99d98c50
--- /dev/null
+++ b/Src/Winamp/ExplorerFindFile.cpp
@@ -0,0 +1,163 @@
+#include "main.h"
+#include "ExplorerFindFile.h"
+
+ExplorerFindFile::ExplorerFindFile()
+{
+}
+
+ExplorerFindFile::~ExplorerFindFile()
+{
+}
+
+void ExplorerFindFile::Reset()
+{
+ pidlList.clear();
+}
+
+// still need to make this handle zip:// entries natively to get them working as needed
+BOOL ExplorerFindFile::AddFile( wchar_t *file )
+{
+ LPSHELLFOLDER pDesktopFolder = 0;
+ if ( SUCCEEDED( SHGetDesktopFolder( &pDesktopFolder ) ) )
+ {
+ LPITEMIDLIST filepidl = 0, folderpidl = 0;
+ wchar_t folder[ MAX_PATH ] = { 0 },
+ param[ 512 ] = { 0 },
+ *filews = 0;
+ int zip = 0;
+
+ // doing this to handle zip:// entries where there is a valid file
+ // path included in the entry so extract it (from FFOD plugin code)
+ lstrcpynW( param, file, 7 );
+ if ( !lstrcmpiW( param, L"zip://" ) )
+ {
+ file += 6;
+ zip = 1;
+ }
+
+ filews = file + lstrlenW( file ) - 1;
+ if ( wcsstr( filews, L"." ) != 0 )
+ {
+ while ( filews && *filews && ( *filews != L'.' ) && ( filews != file ) )
+ {
+ filews = CharPrevW( file, filews );
+ if ( zip && *filews == L',' )
+ {
+ zip = 0;
+ }
+
+ if ( zip && *filews == L'.' )
+ {
+ zip = 0;
+ filews = CharPrevW( file, filews );
+ }
+ }
+ }
+
+ while ( filews && *filews && ( *filews != L',' && *filews != L':' && *filews != L'|' ) )
+ filews = CharNextW( filews );
+
+ if ( filews )
+ *filews = 0;
+
+ // doing this to handle foo.rsn\bar.spc so it'll just
+ // find foo.rsn (which should then be a valid entry)
+ filews = wcsstr( file, L".rsn\\" );
+ if ( filews )
+ {
+ *( filews + 4 ) = 0;
+ }
+
+ // and now get the folder path of the file
+ lstrcpynW( folder, file, MAX_PATH );
+
+ if ( PathIsRelativeW( folder ) )
+ {
+ // sort out relative files based against winamp.exe
+ wchar_t szTemp[ MAX_PATH ] = { 0 }, szTemp2[ MAX_PATH ] = { 0 };
+ GetModuleFileNameW( hMainInstance, szTemp, sizeof( szTemp ) );
+ PathRemoveFileSpecW( szTemp );
+ PathCombineW( szTemp2, szTemp, folder );
+ PathCanonicalizeW( folder, szTemp2 );
+ // and once calculated then we copy the file back
+ lstrcpynW( file, folder, MAX_PATH );
+ }
+
+ PathRemoveFileSpecW( folder );
+
+ HRESULT hr = pDesktopFolder->ParseDisplayName( NULL, 0, folder, 0, &folderpidl, 0 );
+ if ( FAILED( hr ) )
+ {
+ pDesktopFolder->Release();
+
+ return FALSE;
+ }
+
+ hr = pDesktopFolder->ParseDisplayName( NULL, 0, file, 0, &filepidl, 0 );
+ if ( FAILED( hr ) )
+ {
+ pDesktopFolder->Release();
+
+ return FALSE;
+ }
+
+ PIDLListMap::iterator itr = pidlList.begin();
+ for ( ; itr != pidlList.end(); itr++ )
+ {
+ wchar_t tmp[ MAX_PATH ] = { 0 };
+ SHGetPathFromIDListW( itr->first, tmp );
+ // the LPITEMIDLIST isn't consistant for all calls it seems and
+ // so it requires doing a physical check against the folder path
+ // rather than comparing LPITEMIDLIST values which would be nice
+ if ( !_wcsnicmp( folder, tmp, wcslen( folder ) ) )
+ {
+ itr->second.push_back( filepidl );
+ break;
+ }
+ }
+
+ // if we got here then there was no match with the currently parsed
+ // folder and so we need to add it to the pidllist for use later on
+ if ( itr == pidlList.end() )
+ {
+ std::vector<LPCITEMIDLIST> list;
+ list.push_back( filepidl );
+ //PIDLListMap::MapPair p(folderpidl, list);
+ pidlList.insert( { folderpidl, list } );
+ }
+
+ pDesktopFolder->Release();
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL ExplorerFindFile::ShowFiles()
+{
+ if(pidlList.size())
+ {
+ BOOL ret = TRUE;
+ for (PIDLListMap::iterator itr=pidlList.begin();itr!=pidlList.end();itr++)
+ {
+ if(FAILED(SHOpenFolderAndSelectItems(itr->first,(UINT)itr->second.size(),itr->second.data(),NULL))){
+ ret = FALSE;
+ }
+ }
+ Reset();
+ return ret;
+ }
+ return FALSE;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS ExplorerFindFile
+START_DISPATCH;
+CB(API_EXPLORERFINDFILE_ADDFILE, AddFile)
+CB(API_EXPLORERFINDFILE_SHOWFILES, ShowFiles)
+VCB(API_EXPLORERFINDFILE_RESET, Reset)
+END_DISPATCH \ No newline at end of file
diff --git a/Src/Winamp/ExplorerFindFile.h b/Src/Winamp/ExplorerFindFile.h
new file mode 100644
index 00000000..5f8b47b0
--- /dev/null
+++ b/Src/Winamp/ExplorerFindFile.h
@@ -0,0 +1,27 @@
+#ifndef NULLSOFT_WINAMP_EXPLORERFINDFILE_H
+#define NULLSOFT_WINAMP_EXPLORERFINDFILE_H
+
+#include "../Agave/ExplorerFindFile/api_explorerfindfile.h"
+#include <map>
+#include <vector>
+
+class ExplorerFindFile : public api_explorerfindfile
+{
+public:
+ ExplorerFindFile();
+ ~ExplorerFindFile();
+ static const char *getServiceName() { return "ExplorerFindFile API"; }
+ static const GUID getServiceGuid() { return ExplorerFindFileApiGUID; }
+ BOOL AddFile(wchar_t* file);
+ BOOL ShowFiles();
+ void Reset();
+protected:
+ RECVS_DISPATCH;
+
+ typedef std::map<LPITEMIDLIST, std::vector<LPCITEMIDLIST>> PIDLListMap;
+ PIDLListMap pidlList;
+};
+
+extern ExplorerFindFile *explorerFindFileManager;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/ExtendedInfo.cpp b/Src/Winamp/ExtendedInfo.cpp
new file mode 100644
index 00000000..4c743583
--- /dev/null
+++ b/Src/Winamp/ExtendedInfo.cpp
@@ -0,0 +1,363 @@
+#include "main.h"
+#include "api.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoWideFn.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoCharFn.h"
+#include "../nu/AutoLock.h"
+#include "../nu/ns_wc.h"
+#include <malloc.h>
+
+using namespace Nullsoft::Utility;
+/* Get Extended File Info */
+
+typedef int (__cdecl *GetANSIInfo)(const char *fn, const char *data, char *dest, size_t destlen);
+typedef int (__cdecl *GetUnicodeInfo)(const wchar_t *fn, const char *data, wchar_t *dest, size_t destlen);
+
+int ConvertGetExtendedFileInfo(GetUnicodeInfo getter, const char *fn, const char *data, char *dest, size_t destlen)
+{
+ wchar_t *destW = 0;
+
+ if (dest && destlen)
+ {
+ destW = (wchar_t *)_malloca(destlen * sizeof(wchar_t));
+ memset(destW, 0, destlen * sizeof(wchar_t));
+ }
+
+ int retVal = getter(AutoWideFn(fn), data, destW, destlen);
+ if (retVal && dest && destlen)
+ WideCharToMultiByteSZ(CP_ACP, 0, destW, -1, dest, (int)destlen, 0, 0);
+
+ if (destW) _freea(destW);
+ return retVal;
+}
+
+int ConvertGetExtendedFileInfo(GetANSIInfo getter, const char *fn, const char *data, wchar_t *dest, size_t destlen)
+{
+ char *destA = 0;
+
+ if (dest && destlen)
+ {
+ destA = (char *)_malloca(destlen * sizeof(char));
+ memset(destA, 0, destlen * sizeof(char));
+ }
+
+ int retVal = getter(fn, data, destA, destlen);
+ if (retVal && dest && destlen)
+ MultiByteToWideCharSZ(CP_ACP, 0, destA, -1, dest, (int)destlen);
+
+ if (destA) _freea(destA);
+ return retVal;
+}
+
+static GetANSIInfo gefi;
+static GetUnicodeInfo gefiW;
+static char cachedExt[16];
+LockGuard getMetadataGuard;
+
+int in_get_extended_fileinfo(const char *fn, const char *metadata, char *dest, size_t destlen)
+{
+ AutoLock lock(getMetadataGuard);
+
+ In_Module *i=0;
+ char ext[16] = {0};
+ int a = 0;
+
+ // do some extra checks on the params as quite a few clients crash when accessing here
+ try {
+ if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
+ fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
+ metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
+ return 0;
+ } catch (...) {
+ return 0;
+ }
+
+ if (dest)
+ memset(dest, 0, destlen);
+
+ extension_ex(fn, ext, sizeof(ext));
+
+ if (!_stricmp(cachedExt, ext) && *ext)
+ {
+ if (gefi)
+ return gefi(fn, metadata, dest, destlen);
+ else if (gefiW) // should always be true if we got this far
+ return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
+ else
+ return 0;
+ }
+
+ while (a >= 0)
+ {
+ i = in_setmod_noplay(AutoWideFn(fn), &a);
+ if (!i)
+ break;
+
+ if (a >= 0) a++;
+
+ lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
+
+ gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
+ gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
+ if (gefi || gefiW)
+ break;
+ }
+
+ // if no one claimed it, then check if it's the currently playing track
+ // benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
+ if (!i && !lstrcmpiW(FileName, AutoWide(fn)))
+ {
+ i=in_mod;
+ if (i)
+ {
+ cachedExt[0]=0;
+ gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
+ gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
+ }
+ }
+
+ if (!i)
+ return 0;
+
+ if (gefi)
+ return gefi(fn, metadata, dest, destlen);
+ else if (gefiW)
+ return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
+ else
+ return 0;
+}
+
+int in_get_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *dest, size_t destlen)
+{
+ AutoLock lock(getMetadataGuard);
+
+ In_Module *i=0;
+ char ext[16] = {0};
+ int a = 0;
+
+ // do some extra checks on the params as quite a few clients crash when accessing here
+ try {
+ if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
+ fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
+ metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
+ return 0;
+ } catch (...) {
+ return 0;
+ }
+
+ if (dest)
+ memset(dest, 0, destlen);
+
+ AutoCharFn charFn(fn);
+ extension_ex(charFn, ext, sizeof(ext));
+
+ if (!_stricmp(cachedExt, ext) && *ext)
+ {
+ if (gefiW) // should always be true if we got this far
+ return gefiW(fn, AutoChar(metadata), dest, destlen);
+ if (gefi)
+ return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
+ else
+ return 0;
+ }
+
+ while (a >= 0)
+ {
+ i = in_setmod_noplay(fn, &a);
+ if (!i)
+ break;
+
+ if (a >= 0) a++;
+
+ lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
+
+ gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
+ gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
+ if (gefi || gefiW)
+ break;
+ }
+
+ // if no one claimed it, then check if it's the currently playing track
+ // benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
+ if (!i && !lstrcmpiW(FileName, fn)) // currently playing file?
+ {
+ i=in_mod;
+ if (i)
+ {
+ cachedExt[0]=0;
+ gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
+ gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
+ }
+ }
+
+ if (!i)
+ return 0;
+
+ if (gefiW)
+ return gefiW(fn, AutoChar(metadata), dest, destlen);
+ else if (gefi)
+ return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
+ else
+ return 0;
+}
+
+/* Set Extended File Info */
+
+typedef int (__cdecl *SetANSIInfo)(const char *fn, const char *metadata, const char *data);
+typedef int (__cdecl *SetUnicodeInfo)(const wchar_t *fn, const char *metadata, const wchar_t *data);
+
+static SetANSIInfo sefi;
+static SetUnicodeInfo sefiW;
+static int (*wefi)();
+static char cachedExtSet[16];
+
+static int ConvertSetExtendedFileInfo(SetUnicodeInfo setter, const char *fn, const char *metadata, const char *data)
+{
+ return setter(AutoWide(fn), metadata, AutoWide(data));
+}
+
+static int ConvertSetExtendedFileInfo(SetANSIInfo setter, const char *fn, const char *metadata, const wchar_t *data)
+{
+ return setter(fn, metadata, AutoChar(data));
+}
+
+int in_set_extended_fileinfo(const char *fn, const char *metadata, char *data)
+{
+ AutoLock lock(getMetadataGuard);
+ char ext[16] = {0};
+ int a = 0;
+
+ extension_ex(fn, ext, sizeof(ext));
+ if (!_stricmp(cachedExtSet, ext) && *ext)
+ {
+ if (sefi)
+ return sefi(fn, metadata, data);
+ else if (sefiW)
+ return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
+ else
+ return 0;
+ }
+
+ while (a >= 0)
+ {
+ wefi = NULL;
+ sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
+ sefiW = NULL;
+ In_Module *i = in_setmod_noplay(AutoWideFn(fn), &a);
+ if (a >= 0) a++;
+ cachedExtSet[0] = 0;
+ if (!i) return 0;
+ lstrcpynA(cachedExtSet, ext, 16);
+
+ sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
+ sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
+ wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
+ if (sefi || sefiW) break;
+ }
+
+ if (sefi)
+ return sefi(fn, metadata, data);
+ else if (sefiW)
+ return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
+ else
+ return 0;
+}
+
+int in_set_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *data)
+{
+ AutoLock lock(getMetadataGuard);
+
+ char ext[16] = {0};
+ int a = 0;
+
+ AutoCharFn charFn(fn);
+ extension_ex(charFn, ext, sizeof(ext));
+ if (!_stricmp(cachedExtSet, ext) && *ext)
+ {
+ if (sefiW)
+ return sefiW(fn, AutoChar(metadata), data);
+ else if (sefi)
+ return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
+ else
+ return 0;
+ }
+
+ while (a >= 0)
+ {
+ wefi = NULL;
+ sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
+ sefiW = NULL;
+ In_Module *i = in_setmod_noplay(fn, &a);
+ if (a >= 0) a++;
+ cachedExtSet[0] = 0;
+ if (!i) return 0;
+ lstrcpynA(cachedExtSet, ext, 16);
+
+ sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
+ sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
+ wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
+ if (sefi || sefiW) break;
+ }
+ if (sefiW)
+ return sefiW(fn, AutoChar(metadata), data);
+ else if (sefi)
+ return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
+ else
+ return 0;
+}
+
+int in_write_extended_fileinfo()
+{
+ AutoLock lock(getMetadataGuard);
+ if (!wefi)
+ return 0;
+ return
+ wefi();
+}
+
+inline void COPY_METADATA(const wchar_t *src, const wchar_t *dest, const wchar_t *item, wchar_t *buf, size_t buflen)
+{
+ if (NULL != src && NULL != item && NULL != buf)
+ {
+ buf[0]=0;
+ extendedFileInfoStructW efis=
+ {
+ src,
+ item,
+ buf,
+ buflen,
+ };
+
+ if (SendMessageW(hMainWindow,WM_WA_IPC,(WPARAM)&efis,IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ in_set_extended_fileinfoW(dest, item, buf);
+ }
+
+}
+
+
+//#define COPY_METADATA(src, dest, item, buf, buflen) { buf[0]=0; if (in_get_extended_fileinfoW(src, item, buf, buflen)) in_set_extended_fileinfoW(dest, item, buf); }
+void CopyExtendedFileInfo(const wchar_t *source, const wchar_t *destination)
+{
+ wchar_t bigData[32768] = {0}; // hopefully big enough for all reasonable metadata
+
+ COPY_METADATA(source, destination, L"title", bigData, 32768);
+ COPY_METADATA(source, destination, L"artist", bigData, 32768);
+ COPY_METADATA(source, destination, L"albumartist", bigData, 32768);
+ COPY_METADATA(source, destination, L"album", bigData, 32768);
+ COPY_METADATA(source, destination, L"genre", bigData, 32768);
+ COPY_METADATA(source, destination, L"year", bigData, 32768);
+ COPY_METADATA(source, destination, L"disc", bigData, 32768);
+ COPY_METADATA(source, destination, L"publisher", bigData, 32768);
+ COPY_METADATA(source, destination, L"comment", bigData, 32768);
+ COPY_METADATA(source, destination, L"track", bigData, 32768);
+ COPY_METADATA(source, destination, L"tool", bigData, 32768);
+ COPY_METADATA(source, destination, L"composer", bigData, 32768);
+ COPY_METADATA(source, destination, L"conductor", bigData, 32768);
+ COPY_METADATA(source, destination, L"bpm", bigData, 32768);
+ COPY_METADATA(source, destination, L"GracenoteFileID", bigData, 32768);
+ COPY_METADATA(source, destination, L"GracenoteExtData", bigData, 32768);
+ in_write_extended_fileinfo();
+
+ //albumArt->CopyAlbumArt(source, destination);
+} \ No newline at end of file
diff --git a/Src/Winamp/ExtendedReader.cpp b/Src/Winamp/ExtendedReader.cpp
new file mode 100644
index 00000000..3565be1f
--- /dev/null
+++ b/Src/Winamp/ExtendedReader.cpp
@@ -0,0 +1,87 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "ExtendedReader.h"
+#include "../nu/AutoCharFn.h"
+
+ExtendedReader::ExtendedReader(OpenFunc _open, OpenWFunc _openW, OpenFunc _openFloat, OpenWFunc _openWFloat, GetDataFunc _getData, CloseFunc _close, SetTimeFunc _setTime)
+ : open(_open), openFloat(_openFloat), openW(_openW), openWFloat(_openWFloat), getData(_getData), close(_close), setTime(_setTime), handle(0)
+{}
+
+bool ExtendedReader::Open(const wchar_t *filename, AudioParameters *parameters)
+{
+ if (parameters->flags & AUDIOPARAMETERS_FLOAT)
+ {
+ if (this->openWFloat)
+ handle = this->openWFloat(filename, (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
+ else if (this->openFloat)
+ handle = this->openFloat(AutoCharFn(filename), (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
+ }
+ else
+ {
+ if (this->openW)
+ handle = this->openW(filename, (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
+ else
+ handle = this->open(AutoCharFn(filename), (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
+ }
+ if (handle > 0)
+ return true;
+ else
+ {
+ if (handle == -1)
+ parameters->errorCode = API_DECODEFILE_FAIL_NO_WARN;
+ else
+ parameters->errorCode = API_DECODEFILE_FAILURE;
+ return false;
+ }
+}
+
+size_t ExtendedReader::ReadAudio(void *buffer, size_t sizeBytes)
+{
+ int killswitch = 0;
+ return this->getData(handle, buffer, sizeBytes, &killswitch);
+}
+
+size_t ExtendedReader::ReadAudio_kill(void *buffer, size_t sizeBytes, int *killswitch, int *error)
+{
+ *error=0;
+ intptr_t ret = this->getData(handle, buffer, sizeBytes, killswitch);
+ if (ret < 0)
+ {
+ *error=1;
+ return 0;
+ }
+ else
+ return static_cast<size_t>(ret);
+}
+
+BOOL ExtendedReader::SeekToTimeMs(int millisecs)
+{
+ if (!setTime)
+ return FALSE;
+ return this->setTime(handle, millisecs);
+}
+
+int ExtendedReader::CanSeek()
+{
+ return setTime?1:0;
+}
+
+ExtendedReader::~ExtendedReader()
+{
+ if (handle)
+ this->close(handle);
+}
+
+#define CBCLASS ExtendedReader
+START_DISPATCH;
+CB(IFC_AUDIOSTREAM_READAUDIO, ReadAudio)
+CB(IFC_AUDIOSTREAM_READAUDIO2, ReadAudio_kill)
+CB(IFC_AUDIOSTREAM_SEEKTOTIMEMS, SeekToTimeMs)
+CB(IFC_AUDIOSTREAM_CANSEEK, CanSeek)
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Winamp/ExtendedReader.h b/Src/Winamp/ExtendedReader.h
new file mode 100644
index 00000000..ddb7f251
--- /dev/null
+++ b/Src/Winamp/ExtendedReader.h
@@ -0,0 +1,37 @@
+#ifndef NULLSOFT_WINAMP_EXTENDEDREADER_H
+#define NULLSOFT_WINAMP_EXTENDEDREADER_H
+
+#include <stddef.h>
+#include "../Agave/DecodeFile/ifc_audiostream.h"
+#include "../Agave/DecodeFile/api_decodefile.h"
+#include "CommonReader.h"
+
+typedef intptr_t (__cdecl *OpenFunc)(const char *filename, int *size, int *bps, int *nch, int *srate);
+typedef intptr_t (__cdecl *OpenWFunc)(const wchar_t *filename, int *size, int *bps, int *nch, int *srate);
+typedef size_t (__cdecl *GetDataFunc)(intptr_t handle, void *buffer, size_t bufferBytes, int *killswitch);
+typedef void (__cdecl *CloseFunc)(intptr_t);
+typedef int (__cdecl *SetTimeFunc)(intptr_t handle, int millisecs);
+
+class ExtendedReader : public CommonReader
+{
+public:
+ ExtendedReader(OpenFunc _open, OpenWFunc _openW, OpenFunc _openFloat, OpenWFunc _openWFloat, GetDataFunc _getData, CloseFunc _close, SetTimeFunc _setTime = 0);
+ ~ExtendedReader();
+ bool Open(const wchar_t *filename, AudioParameters *parameters);
+ size_t ReadAudio(void *buffer, size_t sizeBytes);
+ size_t ReadAudio_kill(void *buffer, size_t sizeBytes, int *killswitch, int *error);
+ BOOL SeekToTimeMs(int millisecs);
+ int CanSeek();
+
+ OpenFunc open, openFloat;
+ OpenWFunc openW, openWFloat;
+ GetDataFunc getData;
+ CloseFunc close;
+ SetTimeFunc setTime;
+ intptr_t handle;
+protected:
+ RECVS_DISPATCH;
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/ExternalCOM.cpp b/Src/Winamp/ExternalCOM.cpp
new file mode 100644
index 00000000..1fbed2f6
--- /dev/null
+++ b/Src/Winamp/ExternalCOM.cpp
@@ -0,0 +1,520 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "Main.h"
+#include "ExternalCOM.h"
+#include "BrowserCOM.h"
+#include "CurrentSongCOM.h"
+#include "SkinCOM.h"
+#include "ApplicationCOM.h"
+#include "BookmarksCOM.h"
+#include "MediaCoreCOM.h"
+#include "DataStoreCOM.h"
+#include "JNetCOM.h"
+#include "SecurityCOM.h"
+#include "../nu/ConfigCOM.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoCharFn.h"
+#include "./Winamp/JSAPI.h"
+#include "JSAPI2_ExternalObject.h"
+#include "JSAPI2_Security.h"
+
+static volatile LONG unique_dispid;
+
+enum
+{
+ DISPID_CONFIG = 0,
+ DISPID_JNET = 1,
+ INITIAL_DISPID = 776,
+};
+
+static ExternalCOM *externalCOM = NULL;
+
+HRESULT __cdecl JSAPI1_Initialize()
+{
+ if (NULL != externalCOM)
+ return S_FALSE;
+
+ ExternalCOM *temp = new ExternalCOM();
+ if (NULL == temp)
+ return E_OUTOFMEMORY;
+
+ externalCOM = temp;
+ return S_OK;
+}
+
+HRESULT __cdecl JSAPI1_Uninitialize()
+{
+ if (NULL == externalCOM)
+ return S_FALSE;
+
+ ExternalCOM *temp = externalCOM;
+ externalCOM = NULL;
+ temp->Release();
+
+ return S_OK;
+}
+
+HRESULT __cdecl JSAPI1_GetExternal(ExternalCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ if (NULL == externalCOM)
+ {
+ *instance = NULL;
+ return E_UNEXPECTED;
+ }
+
+ externalCOM->AddRef();
+ *instance = externalCOM;
+
+ return S_OK;
+}
+
+HRESULT __cdecl JSAPI1_GetSkinCOM(SkinCOM **instance)
+{
+ ExternalCOM *external = 0;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (SUCCEEDED(hr) && external)
+ {
+ hr = external->GetSkinCOM(instance);
+ external->Release();
+ }
+ else
+ {
+ if (NULL == instance) hr = E_POINTER;
+ else *instance = NULL;
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_GetMediaCoreCOM(MediaCoreCOM **instance)
+{
+ ExternalCOM *external = 0;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (SUCCEEDED(hr) && external)
+ {
+ hr = external->GetMediaCoreCOM(instance);
+ external->Release();
+ }
+ else
+ {
+ if (NULL == instance) hr = E_POINTER;
+ else *instance = NULL;
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_GetCurrentSongCOM(CurrentSongCOM **instance)
+{
+ ExternalCOM *external = 0;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (SUCCEEDED(hr) && external)
+ {
+ hr = external->GetCurrentSongCOM(instance);
+ external->Release();
+ }
+ else
+ {
+ if (NULL == instance) hr = E_POINTER;
+ else *instance = NULL;
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_SkinChanged()
+{
+ SkinCOM *skinCOM = 0;
+ HRESULT hr = JSAPI1_GetSkinCOM(&skinCOM);
+ if (SUCCEEDED(hr) && skinCOM)
+ {
+ skinCOM->SkinChanged();
+ skinCOM->Release();
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_CurrentTitleChanged()
+{
+ CurrentSongCOM *songCOM = 0;
+ HRESULT hr = JSAPI1_GetCurrentSongCOM(&songCOM);
+ if (SUCCEEDED(hr) && songCOM)
+ {
+ songCOM->TitleChanged();
+ songCOM->Release();
+ }
+ return hr;
+}
+
+DISPID __cdecl JSAPI1_GenerateUniqueDispatchId()
+{
+ return (DISPID)InterlockedIncrement(&unique_dispid);
+}
+
+#define REGISTER_DISPATCH_EX(__name, __creator, __dispId, __pDisp)\
+ { __pDisp = new __creator;\
+ if (NULL != __pDisp) {\
+ __dispId = AddDispatch(__name, __pDisp);\
+ if (0 == __dispId) { (__pDisp)->Release(); (__pDisp) = NULL;}\
+ }\
+ }
+
+#define REGISTER_DISPATCH(__name, __creator)\
+ { DISPID __dispId; IDispatch *pDisp; \
+ REGISTER_DISPATCH_EX(__name, __creator, __dispId, pDisp);\
+ if (NULL != pDisp) pDisp->Release(); }
+
+static const wchar_t *api1_api2_key = L"1";
+
+ExternalCOM::ExternalCOM() : ref(1), mediaCoreCOM(NULL), skinCOM(NULL), songCOM(NULL), api2(0)
+{
+ InitializeCriticalSection(&tableLock);
+ unique_dispid = INITIAL_DISPID; // we can't count on the CRT to have initialized this yet.
+ configFilename[0]=0;
+
+ DISPID dispId = 0;
+ REGISTER_DISPATCH(L"Browser", BrowserCOM());
+ REGISTER_DISPATCH_EX(L"CurrentSong", CurrentSongCOM(), dispId, songCOM);
+ REGISTER_DISPATCH_EX(L"CurrentSkin", SkinCOM(), dispId, skinCOM);
+ REGISTER_DISPATCH(L"Application", ApplicationCOM());
+ REGISTER_DISPATCH(L"Bookmarks", BookmarksCOM());
+ REGISTER_DISPATCH_EX(L"MediaCore", MediaCoreCOM(), dispId, mediaCoreCOM);
+ REGISTER_DISPATCH(L"DataStore", DataStoreCOM());
+ REGISTER_DISPATCH(L"Security", SecurityCOM());
+ JSAPI2::security.SetBypass(api1_api2_key, true);
+ REGISTER_DISPATCH_EX(L"API2", JSAPI2::ExternalObject(api1_api2_key), dispId, api2);
+}
+
+ExternalCOM::~ExternalCOM()
+{
+ EnterCriticalSection(&tableLock);
+
+ for ( JSAPI::Dispatcher *l_dispatch_table : dispatchTable )
+ delete l_dispatch_table;
+
+ for ( ConfigCOM *l_config : configs )
+ l_config->Release();
+
+ LeaveCriticalSection(&tableLock);
+
+ DeleteCriticalSection(&tableLock);
+
+ if (NULL != mediaCoreCOM) mediaCoreCOM->Release();
+ if (NULL != songCOM) songCOM->Release();
+ if (NULL != skinCOM) skinCOM->Release();
+ if (NULL != api2) api2->Release();
+}
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+STDMETHODIMP ExternalCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ UINT unknowns = 0;
+
+ EnterCriticalSection(&tableLock);
+ size_t tableCount = dispatchTable.size();
+
+ for (unsigned int i = 0;i != cNames; i++)
+ {
+ rgdispid[i]=DISPID_UNKNOWN;
+
+ for (size_t entry = 0; entry < tableCount; entry++)
+ {
+ if (!wcscmp(rgszNames[i], dispatchTable[entry]->name))
+ {
+ rgdispid[i] = dispatchTable[entry]->id;
+ break;
+ }
+ }
+
+ if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"Config"))
+ rgdispid[i] = DISPID_CONFIG;
+ else if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"JNetLib"))
+ rgdispid[i] = DISPID_JNET;
+ else if (rgdispid[i] == DISPID_UNKNOWN)
+ unknowns++;
+ }
+
+ LeaveCriticalSection(&tableLock);
+
+ if (0 != unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+STDMETHODIMP ExternalCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP ExternalCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP ExternalCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch(dispid)
+ {
+ case DISPID_CONFIG:
+ {
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+
+ LPCWSTR configName;
+ JSAPI_GETSTRING(configName, pdispparams, 1, puArgErr);
+
+ if (NULL != pvarResult)
+ {
+ VariantInit(pvarResult);
+
+ ConfigCOM *config;
+ if (SUCCEEDED(GetConfig(configName, &config)))
+ {
+ V_VT(pvarResult) = VT_DISPATCH;
+ V_DISPATCH(pvarResult) = config;
+ }
+ else
+ {
+ V_VT(pvarResult) = VT_NULL;
+ }
+ }
+ }
+ return S_OK;
+
+ case DISPID_JNET:
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_DISPATCH;
+ V_DISPATCH(pvarResult) = new JNetCOM(pdispparams->rgvarg[0].pdispVal);
+ return S_OK;
+ }
+ break;
+ }
+
+ EnterCriticalSection(&tableLock);
+ size_t index = dispatchTable.size();
+ while(index--)
+ {
+ if (dispatchTable[index]->id == dispid)
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_DISPATCH;
+ V_DISPATCH(pvarResult) = dispatchTable[index]->object;
+ dispatchTable[index]->object->AddRef();
+ break;
+ }
+ }
+ LeaveCriticalSection(&tableLock);
+ if (((size_t)-1) != index) return S_OK;
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP ExternalCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) ExternalCOM::AddRef(void)
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+STDMETHODIMP_(ULONG) ExternalCOM::Release(void)
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+STDMETHODIMP ExternalCOM::QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable)
+{
+ if (IsEqualIID(riid, JSAPI::IID_JSAPI_ifc_info))
+ {
+ *ppDispatchable = (JSAPI::ifc_info *)this;
+ }
+ else
+ {
+ *ppDispatchable = NULL;
+ return E_NOINTERFACE;
+ }
+ (*ppDispatchable)->AddRef();
+ return S_OK;
+}
+
+const wchar_t *ExternalCOM::GetUserAgent()
+{
+ return L"JSAPI1";
+}
+
+HRESULT ExternalCOM::GetConfig(LPCWSTR configName, ConfigCOM **config)
+{
+ if (NULL == config) return E_POINTER;
+
+ AutoChar nameAnsi(configName);
+ if (NULL == (const char*)nameAnsi)
+ {
+ *config = NULL;
+ return E_INVALIDARG;
+ }
+
+ EnterCriticalSection(&tableLock);
+
+ // check if there's already an open config object
+ size_t index = configs.size();
+ while (index-- && FALSE != configs[index]->IsEqual(nameAnsi));
+
+ if ((size_t)-1 == index)
+ {
+ if (L'\0' != configFilename[0] ||
+ NULL != PathCombineW(configFilename, CONFIGDIR, L"jscfg.ini"))
+ {
+ if (SUCCEEDED(ConfigCOM::CreateInstanceA(nameAnsi, AutoCharFn(configFilename), config)))
+ configs.push_back(*config);
+ }
+ }
+ else
+ {
+ *config = configs[index];
+ }
+
+ HRESULT hr = S_OK;
+ if (NULL != *config)
+ {
+ (*config)->AddRef();
+ }
+ else
+ hr = E_FAIL;
+
+ LeaveCriticalSection(&tableLock);
+
+ return hr;
+}
+
+HRESULT ExternalCOM::FindDispatch(DISPID dispId, IDispatch **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ EnterCriticalSection(&tableLock);
+ size_t index = dispatchTable.size();
+ while(index--)
+ {
+ if (dispatchTable[index]->id == dispId)
+ {
+ *instance = dispatchTable[index]->object;
+ break;
+ }
+ }
+ LeaveCriticalSection(&tableLock);
+
+ if (((size_t)-1) != index)
+ return S_OK;
+
+ *instance = NULL;
+ return S_FALSE;
+}
+
+DISPID ExternalCOM::AddDispatch(const wchar_t *name, IDispatch *object)
+{
+ if (NULL == object)
+ return 0;
+
+ DISPID id = JSAPI1_GenerateUniqueDispatchId();
+
+ JSAPI::Dispatcher *dispatcher = new JSAPI::Dispatcher(name, id, object);
+ if (NULL == dispatcher) return 0;
+
+ EnterCriticalSection(&tableLock);
+ dispatchTable.push_back(dispatcher);
+ LeaveCriticalSection(&tableLock);
+
+ return id;
+}
+
+BOOL ExternalCOM::RemoveDispatch(DISPID dispatchId)
+{
+ EnterCriticalSection(&tableLock);
+ size_t index = dispatchTable.size();
+ while(index--)
+ {
+ if (dispatchTable[index]->id == dispatchId)
+ {
+ JSAPI::Dispatcher *dispatcher = dispatchTable[index];
+ dispatchTable.erase(dispatchTable.begin() + index);
+ delete dispatcher;
+ break;
+ }
+ }
+ LeaveCriticalSection(&tableLock);
+ return (((size_t)-1) != index);
+}
+
+HRESULT ExternalCOM::GetSkinCOM(SkinCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = skinCOM;
+ if (NULL != *instance)
+ (*instance)->AddRef();
+
+ return S_OK;
+}
+
+HRESULT ExternalCOM::GetMediaCoreCOM(MediaCoreCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = mediaCoreCOM;
+ if (NULL != *instance)
+ (*instance)->AddRef();
+
+ return S_OK;
+}
+
+HRESULT ExternalCOM::GetCurrentSongCOM(CurrentSongCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = songCOM;
+ if (NULL != *instance)
+ (*instance)->AddRef();
+
+ return S_OK;
+}
+
+#define CBCLASS ExternalCOM
+START_DISPATCH;
+CB(JSAPI_IFC_INFO_GETUSERAGENT, GetUserAgent)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/ExternalCOM.h b/Src/Winamp/ExternalCOM.h
new file mode 100644
index 00000000..9a9aa5fc
--- /dev/null
+++ b/Src/Winamp/ExternalCOM.h
@@ -0,0 +1,89 @@
+#ifndef NULLSOFT_EXTERNALCOMH
+#define NULLSOFT_EXTERNALCOMH
+
+#include <ocidl.h>
+
+
+#if defined(__cplusplus)
+
+#include <vector>
+#include "JSAPI_DispatchTable.h"
+#include "IWasabiDispatchable.h"
+#include "JSAPI_Info.h"
+
+class SkinCOM;
+class MediaCoreCOM;
+class CurrentSongCOM;
+class ExternalCOM;
+class ConfigCOM;
+namespace JSAPI2 { class ExternalObject; }
+
+HRESULT __cdecl JSAPI1_GetExternal(ExternalCOM **instance);
+HRESULT __cdecl JSAPI1_GetSkinCOM(SkinCOM **instance);
+HRESULT __cdecl JSAPI1_GetMediaCoreCOM(MediaCoreCOM **instance);
+HRESULT __cdecl JSAPI1_GetCurrentSongCOM(CurrentSongCOM **instance);
+
+class ExternalCOM : public IDispatch,
+ public IWasabiDispatchable,
+ public JSAPI::ifc_info
+{
+public:
+ enum
+ {
+ DISP_EXTERNAL_SIDECAR = 777,
+ DISP_EXTERNAL_BROWSER,
+ DISP_EXTERNAL_CURRENTSONG,
+ DISP_EXTERNAL_CURRENTSKIN,
+ DISP_EXTERNAL_NEW_ENTRIES_MARKER,
+ };
+
+public:
+ ExternalCOM();
+ ~ExternalCOM();
+
+ // *** IUnknown ***
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch ***
+ STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD(GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD(GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ JSAPI::DispatchTable dispatchTable;
+ DISPID AddDispatch(const wchar_t *name, IDispatch *object);
+ BOOL RemoveDispatch(DISPID dispatchId);
+
+
+ // *** IWasabiDispatchable Methods ***
+ STDMETHOD(QueryDispatchable)(REFIID riid, Dispatchable **ppDispatchable);
+
+ // *** JSAPI::ifc_info Methods ***
+ const wchar_t *GetUserAgent();
+
+ HRESULT FindDispatch(DISPID dispId, IDispatch **instance);
+ HRESULT GetSkinCOM(SkinCOM **instance);
+ HRESULT GetMediaCoreCOM(MediaCoreCOM **instance);
+ HRESULT GetCurrentSongCOM(CurrentSongCOM **instance);
+
+ HRESULT GetConfig(LPCWSTR configName, ConfigCOM **config);
+
+protected:
+ RECVS_DISPATCH;
+
+private:
+ typedef std::vector<ConfigCOM*> ConfigsList;
+
+private:
+ ULONG ref;
+ CRITICAL_SECTION tableLock;
+ wchar_t configFilename[MAX_PATH];
+ MediaCoreCOM *mediaCoreCOM;
+ SkinCOM *skinCOM;
+ CurrentSongCOM *songCOM;
+ JSAPI2::ExternalObject *api2;
+ ConfigsList configs;
+};
+#endif // __cplusplus
+#endif \ No newline at end of file
diff --git a/Src/Winamp/FFT.H b/Src/Winamp/FFT.H
new file mode 100644
index 00000000..7fd3adc1
--- /dev/null
+++ b/Src/Winamp/FFT.H
@@ -0,0 +1,10 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void fft_init();
+void fft_9(float wave[512]);
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/FFT.cpp b/Src/Winamp/FFT.cpp
new file mode 100644
index 00000000..4adf6553
--- /dev/null
+++ b/Src/Winamp/FFT.cpp
@@ -0,0 +1,30 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include "main.h"
+#include "fft.h"
+#include "../nsutil/fft.h"
+
+static nsutil_fft_t fft9;
+
+
+void fft_init()
+{
+ if (!fft9)
+ nsutil_fft_Create_F32R(&fft9, 9, nsutil_fft_fast);
+}
+
+void fft_9(float wave[512])
+{
+ fft_init(); // getting crash reports of this not being created. strange
+ nsutil_fft_Forward_F32R_IP(fft9, wave);
+}
+
+
diff --git a/Src/Winamp/FRONTEND.H b/Src/Winamp/FRONTEND.H
new file mode 100644
index 00000000..df1cf903
--- /dev/null
+++ b/Src/Winamp/FRONTEND.H
@@ -0,0 +1,449 @@
+#ifndef _WAFE_H_
+#define _WAFE_H_
+/*
+** Winamp frontend/plug-in control API documentation v1.1.
+** By Justin Frankel. Updates by Christophe Thibault.
+** Copyright (C) 1997-2000, Nullsoft Inc.
+** Last updated: JUL.12.2000.
+**
+** Introduction
+** -----------------------
+** This file describes a means to easily communicate to Winamp
+** via the classic Win32 Message API.
+**
+** These definitions/code assume C/C++. Porting to VB/Delphi shouldn't
+** be too hard.
+**
+** First, you find the HWND of the Winamp main window. From a plug-in
+** you can easily extract this from the plug-in structure (hMainWindow,
+** hwndParent, whatever). For external apps, use:
+**
+** HWND hwnd_winamp = FindWindow("Winamp v1.x",NULL);
+**
+** (note: I know, we're in Winamp 2.x, but it's 1.x for compatibility)
+**
+** Once you have the hwnd_winamp, it's a good idea to check the version
+** number. To do this, you send a WM_WA_IPC message to hwnd_winamp.
+** Note that WM_WA_IPC is defined as Win32's WM_USER.
+**
+** Note that sometimes you might want to use PostMessage instead of
+** SendMessageW.
+*/
+
+#define WM_WA_IPC WM_USER
+
+/**************************************************************************/
+
+#define IPC_GETVERSION 0
+
+/*
+** int version = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION);
+**
+** Version will be 0x20yx for winamp 2.yx. versions previous to Winamp 2.0
+** typically (but not always) use 0x1zyx for 1.zx versions. Weird, I know.
+**
+** The basic format for sending messages to Winamp is:
+** int result=SendMessageW(hwnd_winamp,WM_WA_IPC,command_data,command);
+** (for the version check, command_data is 0).
+*/
+
+
+#define IPC_DELETE 101
+
+/*
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE);
+**
+** You can use IPC_DELETE to clear Winamp's internal playlist.
+*/
+
+
+#define IPC_STARTPLAY 102
+
+/*
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_STARTPLAY);
+**
+** Using IPC_STARTPLAY is like hitting 'Play' in Winamp, mostly.
+*/
+
+
+#define IPC_ISPLAYING 104
+
+/*
+** int res = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING);
+**
+** IPC_ISPLAYING returns the status of playback.
+** If it returns 1, it is playing. if it returns 3, it is paused,
+** if it returns 0, it is not playing.
+*/
+
+
+#define IPC_GETOUTPUTTIME 105
+
+/*
+** int res = SendMessageW(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME);
+**
+** IPC_GETOUTPUTTIME returns the position in milliseconds of the
+** current song (mode = 0), or the song length, in seconds (mode = 1).
+** Returns -1 if not playing or error.
+*/
+
+
+#define IPC_JUMPTOTIME 106
+
+/* (requires Winamp 1.60+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME);
+** IPC_JUMPTOTIME sets the position in milliseconds of the
+** current song (approximately).
+** Returns -1 if not playing, 1 on eof, or 0 if successful
+*/
+
+
+#define IPC_WRITEPLAYLIST 120
+
+/* (requires Winamp 1.666+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST);
+**
+** IPC_WRITEPLAYLIST writes the current playlist to <winampdir>\\Winamp.m3u,
+** and returns the current playlist position.
+** Kinda obsoleted by some of the 2.x new stuff, but still good for when
+** using a front-end (instead of a plug-in)
+*/
+
+
+#define IPC_SETPLAYLISTPOS 121
+
+/* (requires Winamp 2.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS)
+**
+** IPC_SETPLAYLISTPOS sets the playlsit position to 'position'.
+*/
+
+
+#define IPC_SETVOLUME 122
+
+/* (requires Winamp 2.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME);
+**
+** IPC_SETVOLUME sets the volume of Winamp (from 0-255).
+*/
+
+
+#define IPC_SETPANNING 123
+
+/* (requires Winamp 2.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING);
+**
+** IPC_SETPANNING sets the panning of Winamp (from 0 (left) to 255 (right)).
+*/
+
+
+#define IPC_GETLISTLENGTH 124
+
+/* (requires Winamp 2.0+)
+** int length = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH);
+**
+** IPC_GETLISTLENGTH returns the length of the current playlist, in
+** tracks.
+*/
+
+
+#define IPC_SETSKIN 200
+
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN);
+**
+** IPC_SETSKIN sets the current skin to "skinname". Note that skinname
+** can be the name of a skin, a skin .zip file, with or without path.
+** If path isn't specified, the default search path is the winamp skins
+** directory.
+*/
+
+
+#define IPC_GETSKIN 201
+
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN);
+**
+** IPC_GETSKIN puts the directory where skin bitmaps can be found
+** into skinname_buffer.
+** skinname_buffer must be MAX_PATH characters in length.
+** When using a .zip'd skin file, it'll return a temporary directory
+** where the ZIP was decompressed.
+*/
+
+
+#define IPC_EXECPLUG 202
+
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG);
+**
+** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM.
+** the format of this string can be:
+** "vis_whatever.dll"
+** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir)
+** "C:\\dir\\vis_whatever.dll,1"
+*/
+
+
+#define IPC_GETPLAYLISTFILE 211
+
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** char *name=SendMessageW(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE);
+**
+** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index].
+** returns a pointer to it. returns NULL on error.
+*/
+
+
+#define IPC_GETPLAYLISTTITLE 212
+
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** char *name=SendMessageW(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE);
+**
+** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index].
+** returns a pointer to it. returns NULL on error.
+*/
+
+
+#define IPC_GETLISTPOS 125
+
+/* (requires Winamp 2.05+)
+** int pos=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS);
+**
+** IPC_GETLISTPOS returns the playlist position. A lot like IPC_WRITEPLAYLIST
+** only faster since it doesn't have to write out the list. Heh, silly me.
+*/
+
+
+#define IPC_GETINFO 126
+
+/* (requires Winamp 2.05+)
+** int inf=SendMessageW(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO);
+**
+** IPC_GETINFO returns info about the current playing song. The value
+** it returns depends on the value of 'mode'.
+** Mode Meaning
+** ------------------
+** 0 Samplerate (i.e. 44100)
+** 1 Bitrate (i.e. 128)
+** 2 Channels (i.e. 2)
+*/
+
+
+#define IPC_GETEQDATA 127
+
+/* (requires Winamp 2.05+)
+** int data=SendMessageW(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
+**
+** IPC_GETEQDATA queries the status of the EQ.
+** The value returned depends on what 'pos' is set to:
+** Value Meaning
+** ------------------
+** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db)
+** 10 The preamp value. 0-63 (+20db - -20db)
+** 11 Enabled. zero if disabled, nonzero if enabled.
+** 12 Autoload. zero if disabled, nonzero if enabled.
+*/
+
+
+#define IPC_SETEQDATA 128
+/* (requires Winamp 2.05+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA);
+**
+** IPC_SETEQDATA sets the value of the last position retrieved
+** by IPC_GETEQDATA.
+*/
+
+#define IPC_ADDBOOKMARK 129
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_ADDBOOKMARK);
+**
+** IPC_ADDBOOKMARK will add the specified file to the Winamp bookmark list.
+*/
+
+#define IPC_RESTARTWINAMP 135
+/* (requires Winamp 2.2+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP);
+**
+** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :)
+*/
+
+#define IPC_MBOPEN 241
+/* (requires Winamp 2.05+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN);
+**
+** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window.
+*/
+
+#define IPC_INETAVAILABLE 242
+/* (requires Winamp 2.05+)
+** val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE);
+**
+** IPC_INETAVAILABLE will return 1 if the Internet connection is available for Winamp.
+*/
+
+#define IPC_UPDTITLE 243
+/* (requires Winamp 2.2+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE);
+**
+** IPC_UPDTITLE will ask Winamp to update the informations about the current title.
+*/
+
+#define IPC_CHANGECURRENTFILE 245
+/* (requires Winamp 2.05+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE);
+**
+** IPC_CHANGECURRENTFILE will set the current playlist item.
+*/
+
+#define IPC_GETMBURL 246
+/* (requires Winamp 2.2+)
+** char buffer[4096]; // Urls can be VERY long
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL);
+**
+** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer.
+*/
+
+#define IPC_REFRESHPLCACHE 247
+/* (requires Winamp 2.2+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE);
+**
+** IPC_REFRESHPLCACHE will flush the playlist cache buffer.
+*/
+
+#define IPC_MBBLOCK 248
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK);
+**
+** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1
+*/
+
+#define IPC_MBOPENREAL 249
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL);
+**
+** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if
+** IPC_MBBLOCK has been set to 1
+*/
+
+#define IPC_GET_SHUFFLE 250
+/* (requires Winamp 2.4+)
+** val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE);
+**
+** IPC_GET_SHUFFLE returns the status of the Shuffle option (1 if set)
+*/
+
+#define IPC_GET_REPEAT 251
+/* (requires Winamp 2.4+)
+** val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT);
+**
+** IPC_GET_REPEAT returns the status of the Repeat option (1 if set)
+*/
+
+#define IPC_SET_SHUFFLE 252
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE);
+**
+** IPC_SET_SHUFFLE sets the status of the Shuffle option (1 to turn it on)
+*/
+
+#define IPC_SET_REPEAT 253
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT);
+**
+** IPC_SET_REPEAT sets the status of the Repeat option (1 to turn it on)
+*/
+
+/**************************************************************************/
+
+/*
+** Some API calls tend to require that you send data via WM_COPYDATA
+** instead of WM_USER. Such as IPC_PLAYFILE:
+*/
+
+#define IPC_PLAYFILE 100
+
+/*
+** COPYDATASTRUCT cds;
+** cds.dwData = IPC_PLAYFILE;
+** cds.lpData = (void *) "file.mp3";
+** cds.cbData = strlen((char *) cds.lpData)+1; // include space for null char
+** SendMessageW(hwnd_winamp,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
+**
+** This will play the file "file.mp3".
+**
+*/
+
+
+#define IPC_CHDIR 103
+
+/*
+** COPYDATASTRUCT cds;
+** cds.dwData = IPC_CHDIR;
+** cds.lpData = (void *) "c:\\download";
+** cds.cbData = strlen((char *) cds.lpData)+1; // include space for null char
+** SendMessageW(hwnd_winamp,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
+**
+** This will make Winamp change to the directory C:\\download
+**
+*/
+
+
+/**************************************************************************/
+
+/*
+** Finally there are some WM_COMMAND messages that you can use to send
+** Winamp misc commands.
+**
+** To send these, use:
+**
+** SendMessageW(hwnd_winamp, WM_COMMAND,command_name,0);
+*/
+
+#define WINAMP_OPTIONS_EQ 40036 // toggles the EQ window
+#define WINAMP_OPTIONS_PLEDIT 40040 // toggles the playlist window
+#define WINAMP_VOLUMEUP 40058 // turns the volume up a little
+#define WINAMP_VOLUMEDOWN 40059 // turns the volume down a little
+#define WINAMP_FFWD5S 40060 // fast forwards 5 seconds
+#define WINAMP_REW5S 40061 // rewinds 5 seconds
+
+// the following are the five main control buttons, with optionally shift
+// or control pressed
+// (for the exact functions of each, just try it out)
+#define WINAMP_BUTTON1 40044
+#define WINAMP_BUTTON2 40045
+#define WINAMP_BUTTON3 40046
+#define WINAMP_BUTTON4 40047
+#define WINAMP_BUTTON5 40048
+#define WINAMP_BUTTON1_SHIFT 40144
+#define WINAMP_BUTTON2_SHIFT 40145
+#define WINAMP_BUTTON3_SHIFT 40146
+#define WINAMP_BUTTON4_SHIFT 40147
+#define WINAMP_BUTTON5_SHIFT 40148
+#define WINAMP_BUTTON1_CTRL 40154
+#define WINAMP_BUTTON2_CTRL 40155
+#define WINAMP_BUTTON3_CTRL 40156
+#define WINAMP_BUTTON4_CTRL 40157
+#define WINAMP_BUTTON5_CTRL 40158
+
+#define WINAMP_FILE_PLAY 40029 // pops up the load file(s) box
+#define WINAMP_FILE_DIR 40187 // pops up the load directory box
+#define WINAMP_OPTIONS_PREFS 40012 // pops up the preferences
+#define WINAMP_OPTIONS_AOT 40019 // toggles always on top
+#define WINAMP_HELP_ABOUT 40041 // pops up the about box :)
+
+#define ID_MAIN_PLAY_AUDIOCD1 40323 // starts playing the audio CD in the first CD reader
+#define ID_MAIN_PLAY_AUDIOCD2 40323 // plays the 2nd
+#define ID_MAIN_PLAY_AUDIOCD3 40323 // plays the 3nd
+#define ID_MAIN_PLAY_AUDIOCD4 40323 // plays the 4nd
+
+// IDs 42000 to 45000 are reserved for gen_ff
+// IDs from 45000 to 57000 are reserved for library
+
+/*
+** EOF.. Enjoy.
+*/
+
+#endif
diff --git a/Src/Winamp/FeedBase.cpp b/Src/Winamp/FeedBase.cpp
new file mode 100644
index 00000000..633f6c1c
--- /dev/null
+++ b/Src/Winamp/FeedBase.cpp
@@ -0,0 +1,62 @@
+#include "main.h"
+#include "FeedBase.h"
+#include <assert.h>
+
+void FeedBase::dependent_regViewer(api_dependentviewer *viewer, int add)
+{
+ if (viewer)
+ {
+ if (add)
+ {
+ //if (!viewers.contains(viewer))
+ if(viewers.end() == std::find(viewers.begin(), viewers.end(), viewer))
+ {
+ viewers.push_back(viewer);
+ }
+ }
+ else
+ {
+ //viewers.eraseObject(viewer);
+ auto it = std::find(viewers.begin(), viewers.end(), viewer);
+ if (it != viewers.end())
+ {
+ viewers.erase(it);
+ }
+ }
+ }
+}
+
+void *FeedBase::dependent_getInterface(const GUID *classguid)
+{
+ HANDLEGETINTERFACE(svc_textFeed);
+ return NULL;
+}
+
+api_dependent *FeedBase::getDependencyPtr()
+{
+ return static_cast<api_dependent *>(this);
+}
+
+void FeedBase::CallViewers( const wchar_t *feedid, const wchar_t *text, size_t length )
+{
+ for ( api_dependentviewer *l_viewer : viewers )
+ l_viewer->dependentViewer_callback( static_cast<api_dependent *>( this ), svc_textFeed::depend_getClassGuid(), DependentCB::DEPCB_EVENT, Event_TEXTCHANGE, (intptr_t)feedid, (void *)text, length );
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS FeedBase
+START_MULTIPATCH;
+START_PATCH(DependentPatch)
+ M_VCB(DependentPatch, api_dependent, API_DEPENDENT_REGVIEWER, dependent_regViewer);
+ M_CB(DependentPatch, api_dependent, API_DEPENDENT_GETINTERFACE, dependent_getInterface);
+ NEXT_PATCH(TextFeedPatch)
+ M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_HASFEED, hasFeed);
+ M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_GETFEEDTEXT, getFeedText);
+ M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_GETFEEDDESC, getFeedDescription);
+ M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_GETDEPENDENCYPTR, getDependencyPtr);
+END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/FeedBase.h b/Src/Winamp/FeedBase.h
new file mode 100644
index 00000000..6007a008
--- /dev/null
+++ b/Src/Winamp/FeedBase.h
@@ -0,0 +1,33 @@
+#ifndef NULLSOFT_WINAMP_FEEDBASE_H
+#define NULLSOFT_WINAMP_FEEDBASE_H
+
+#include <api/dependency/api_dependent.h>
+#include <api/skin/feeds/api_textfeed.h>
+#include <vector>
+#include <bfc/multipatch.h>
+
+enum {DependentPatch = 10, TextFeedPatch = 20 };
+
+class FeedBase
+ : public MultiPatch<DependentPatch, api_dependent>,
+ public MultiPatch<TextFeedPatch, svc_textFeed>
+{
+private:
+ void dependent_regViewer(api_dependentviewer *viewer, int add);
+ void *dependent_getInterface(const GUID *classguid);
+
+ virtual int hasFeed(const wchar_t *name)=0;
+ virtual const wchar_t *getFeedText(const wchar_t *name)=0;
+ virtual const wchar_t *getFeedDescription(const wchar_t *name)=0;
+ api_dependent *getDependencyPtr();
+protected:
+ void CallViewers(const wchar_t *feedid, const wchar_t *text, size_t length);
+
+protected:
+ std::vector<api_dependentviewer*> viewers;
+
+protected:
+ RECVS_MULTIPATCH;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/FileInfo.cpp b/Src/Winamp/FileInfo.cpp
new file mode 100644
index 00000000..8c186586
--- /dev/null
+++ b/Src/Winamp/FileInfo.cpp
@@ -0,0 +1,2534 @@
+// the modern file info box
+
+#include "Main.h"
+#include "resource.h"
+#include "api.h"
+#include "../nu/AutoWide.h"
+#include <tataki/export.h>
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <api/service/waservicefactory.h>
+#include <api/service/svcs/svc_imgload.h>
+#include "language.h"
+#ifndef IGNORE_API_GRACENOTE
+#ifndef _WIN64
+#include "../gracenote/api_gracenote.h"
+#endif
+#endif
+#include "../Agave/Language/api_language.h"
+#include "decodefile.h"
+#include "../nu/AutoLock.h"
+#include <api/service/svcs/svc_imgwrite.h>
+#include "../Plugins/General/gen_ml/ml.h"
+#include <vector>
+
+extern Nullsoft::Utility::LockGuard getMetadataGuard;
+#define TEXTBUFFER_MAX 65536
+
+enum FileInfoMode {
+ FILEINFO_MODE_0,
+ FILEINFO_MODE_1,
+};
+
+int ModernInfoBox(In_Module * in, FileInfoMode mode, const wchar_t * filename, HWND parent);
+
+static INT_PTR CALLBACK FileInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static INT_PTR CALLBACK FileInfo_Metadata(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static INT_PTR CALLBACK FileInfo_Artwork(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+typedef HWND (__cdecl *AddUnifiedFileInfoPane)(int n, const wchar_t * filename, HWND parent, wchar_t *name, size_t namelen);
+
+class info_params
+{
+public:
+ const wchar_t * filename;
+ In_Module * in;
+ std::vector<HWND> tabs;
+ FileInfoMode mode;
+ size_t initial_position, length;
+ void (*infoBoxExCallback)(size_t position, wchar_t filepath[FILENAME_SIZE]);
+private:
+ wchar_t *buffer_; // to track allocations made by this object
+public:
+ info_params(FileInfoMode mode, const wchar_t* filename, In_Module * in)
+ {
+ if (filename) {
+ // In order to prevent jtfe 1.33 from crashing winamp, we need to make sure that
+ // this->filename doesn't point to the begining of the allocated block, to do
+ // this, buffer_offset set to 2 (4 bytes).
+ size_t buffer_offset = 2; // "voodoo magic"
+ size_t filename_length = wcslen(filename);
+ size_t buffer_size = filename_length + 1;
+ buffer_ = reinterpret_cast<wchar_t*>(malloc((buffer_size + buffer_offset)*sizeof(wchar_t)));
+ if (buffer_) {
+ wchar_t *filename_buffer = buffer_ + buffer_offset;
+ wcsncpy_s(filename_buffer, buffer_size, filename, filename_length);
+ filename_buffer[filename_length] = '\0';
+ this->filename = filename_buffer;
+ } else {
+ // oops, looks like we out of memory (extremly rare but possible). Probably best thing,
+ // every responsible person should do at this point is to crash app asap,
+ // ...but we also can assign filename pointer directly and let nasty things happen
+ // somewhere later (as of writing of this comment, info_params constructed right before
+ // going in to the modal loop, which makes it kind of blocking call).
+ this->filename = filename;
+ }
+ }
+ else {
+ buffer_ = NULL;
+ this->filename = filename;
+ }
+
+ this->mode = mode;
+ this->in = in;
+ this->initial_position = 0;
+ this->length = 0;
+ }
+
+ ~info_params() {
+ free(buffer_);
+ }
+};
+
+int ModernInfoBox(In_Module * in, FileInfoMode mode, const wchar_t * filename, HWND parent)
+{
+ Tataki::Init(WASABI_API_SVC);
+ info_params params(mode, filename, in);
+
+ int ret = (int)LPDialogBoxParamW(IDD_FILEINFO, parent, FileInfo, (LPARAM)&params);
+ Tataki::Quit();
+ return ret;
+}
+
+static VOID WINAPI OnSelChanged(HWND hwndDlg, HWND hwndTab, info_params * p)
+{
+ ShowWindow(p->tabs[config_last_fileinfo_page], SW_HIDE);
+ EnableWindow(p->tabs[config_last_fileinfo_page], 0);
+ config_last_fileinfo_page=TabCtrl_GetCurSel(hwndTab);
+ ShowWindow(p->tabs[config_last_fileinfo_page], SW_SHOWNA);
+ EnableWindow(p->tabs[config_last_fileinfo_page], 1);
+ if (GetFocus() != hwndTab)
+ {
+ SetFocus(p->tabs[config_last_fileinfo_page]);
+ }
+}
+
+static HWND CreateTab(FileInfoMode mode, int n, const wchar_t *file, HWND parent, wchar_t * name, size_t namelen, AddUnifiedFileInfoPane aufip)
+{
+ switch (n)
+ {
+ case 0:
+ if (mode == FILEINFO_MODE_0) {
+ getStringW(IDS_BASICINFO, name, namelen);
+ return LPCreateDialogW(IDD_FILEINFO_METADATA , parent, (WNDPROC)FileInfo_Metadata);
+ } else {
+ getStringW(IDS_STREAMINFO, name, namelen);
+ return LPCreateDialogW(IDD_FILEINFO_STREAMDATA, parent, (WNDPROC)FileInfo_Metadata);
+ }
+ case 1:
+ getStringW(IDS_ARTWORK,name,namelen);
+ return LPCreateDialogW(IDD_FILEINFO_ARTWORK,parent,(WNDPROC)FileInfo_Artwork);
+ default:
+ if (mode == FILEINFO_MODE_0) {
+ getStringW(IDS_ADVANCED,name,namelen);
+ if (aufip) return aufip(n-2,file,parent,name,namelen);
+ }
+ return NULL;
+ }
+}
+
+static INT_PTR CALLBACK FileInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SetPropW(hwndDlg,L"INBUILT_NOWRITEINFO", (HANDLE)0);
+
+ info_params * p = (info_params *)lParam;
+ SetWindowLongPtrW(hwndDlg,GWLP_USERDATA,lParam);
+
+ HWND ok = GetDlgItem(hwndDlg, IDOK);
+ if (p->mode == FILEINFO_MODE_0) {
+ EnableWindow(ok, TRUE);
+ ShowWindow(ok, SW_SHOW);
+ } else {
+ EnableWindow(ok, FALSE);
+ ShowWindow(ok, SW_HIDE);
+ }
+
+ SetDlgItemTextW(hwndDlg,IDC_FN,p->filename);
+
+ // added 5.66 so plug-ins can get a hint that something may change...
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)p->filename, IPC_FILE_TAG_MAY_UPDATEW);
+
+ AddUnifiedFileInfoPane aufip = (AddUnifiedFileInfoPane)GetProcAddress(p->in->hDllInstance, "winampAddUnifiedFileInfoPane");
+
+ HWND hwndTab = GetDlgItem(hwndDlg,IDC_TAB1);
+ wchar_t name[100] = {0};
+ TCITEMW tie = {0};
+ tie.mask = TCIF_TEXT;
+ tie.pszText = name;
+ HWND tab=NULL;
+ int n=0;
+
+ while (NULL != (tab = CreateTab(p->mode, n, p->filename, hwndDlg, name, 100, aufip)))
+ {
+ p->tabs.push_back(tab);
+ ShowWindow(tab,SW_HIDE);
+
+ if (!SendMessageW(hMainWindow,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC))
+ SendMessageW(hMainWindow,WM_WA_IPC,(WPARAM)tab,IPC_USE_UXTHEME_FUNC);
+
+ SendMessageW(hwndTab, TCM_INSERTITEMW, n, (LPARAM)&tie);
+ n++;
+ }
+
+ RECT r;
+ GetWindowRect(hwndTab,&r);
+ TabCtrl_AdjustRect(hwndTab,FALSE,&r);
+ MapWindowPoints(NULL,hwndDlg,(LPPOINT)&r,2);
+ r.left += 3;
+ r.top += 2;
+ r.right -= 4;
+
+ for (size_t i=0; i < p->tabs.size(); i++)
+ SetWindowPos(p->tabs[i],HWND_TOP,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOACTIVATE);
+
+ if (config_last_fileinfo_page >= (int)p->tabs.size()) config_last_fileinfo_page = 0;
+
+ TabCtrl_SetCurSel(hwndTab,config_last_fileinfo_page);
+
+ ShowWindow(p->tabs[config_last_fileinfo_page], SW_SHOWNA);
+
+ // show alt+3 window and restore last position as applicable
+ POINT pt = {alt3_rect.left, alt3_rect.top};
+ if (!windowOffScreen(hwndDlg, pt) && !IsWindowVisible(hwndDlg))
+ SetWindowPos(hwndDlg, HWND_TOP, alt3_rect.left, alt3_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+
+ return 1;
+ }
+ break;
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpn = (LPNMHDR) lParam;
+ if (lpn && lpn->code==TCN_SELCHANGE)
+ {
+ info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
+ OnSelChanged(hwndDlg,GetDlgItem(hwndDlg,IDC_TAB1),p);
+ }
+ }
+ break;
+ case WM_USER:
+ {
+ info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
+ for (size_t i=0; i < p->tabs.size(); i++)
+ SendMessageW(p->tabs[i],uMsg,wParam,lParam);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ Nullsoft::Utility::AutoLock metadata_lock(getMetadataGuard);
+ info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
+ for (size_t i=0; i < p->tabs.size(); i++)
+ {
+ SendMessageW(p->tabs[i],uMsg,wParam,lParam);
+ }
+ GetWindowRect(hwndDlg, &alt3_rect);
+ EndDialog(hwndDlg,0);
+ }
+ break;
+ case IDCANCEL:
+ {
+ Nullsoft::Utility::AutoLock metadata_lock(getMetadataGuard);
+ info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
+ for (size_t i=0; i < p->tabs.size(); i++)
+ {
+ SendMessageW(p->tabs[i],uMsg,wParam,lParam);
+ }
+ GetWindowRect(hwndDlg, &alt3_rect);
+ EndDialog(hwndDlg,1);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ return FileInfo(hwndDlg,WM_COMMAND,MAKEWPARAM(IDCANCEL,0),0);
+ }
+ return 0;
+}
+
+const wchar_t *genres[] =
+{
+ L"Blues", L"Classic Rock", L"Country", L"Dance", L"Disco", L"Funk", L"Grunge", L"Hip-Hop",
+ L"Jazz", L"Metal", L"New Age", L"Oldies", L"Other", L"Pop", L"R&B", L"Rap", L"Reggae", L"Rock",
+ L"Techno", L"Industrial", L"Alternative", L"Ska", L"Death Metal", L"Pranks", L"Soundtrack",
+ L"Euro-Techno", L"Ambient", L"Trip-Hop", L"Vocal", L"Jazz+Funk", L"Fusion", L"Trance",
+ L"Classical", L"Instrumental", L"Acid", L"House", L"Game", L"Sound Clip", L"Gospel", L"Noise",
+ L"Alt Rock", L"Bass", L"Soul", L"Punk", L"Space", L"Meditative", L"Instrumental Pop",
+ L"Instrumental Rock", L"Ethnic", L"Gothic", L"Darkwave", L"Techno-Industrial",
+ L"Electronic", L"Pop-Folk", L"Eurodance", L"Dream", L"Southern Rock", L"Comedy", L"Cult",
+ L"Gangsta Rap", L"Top 40", L"Christian Rap", L"Pop/Funk", L"Jungle", L"Native American",
+ L"Cabaret", L"New Wave", L"Psychedelic", L"Rave", L"Showtunes", L"Trailer", L"Lo-Fi", L"Tribal",
+ L"Acid Punk", L"Acid Jazz", L"Polka", L"Retro", L"Musical", L"Rock & Roll", L"Hard Rock",
+ L"Folk", L"Folk-Rock", L"National Folk", L"Swing", L"Fast-Fusion", L"Bebop", L"Latin", L"Revival",
+ L"Celtic", L"Bluegrass", L"Avantgarde", L"Gothic Rock", L"Progressive Rock", L"Psychedelic Rock",
+ L"Symphonic Rock", L"Slow Rock", L"Big Band", L"Chorus", L"Easy Listening", L"Acoustic", L"Humour",
+ L"Speech", L"Chanson", L"Opera", L"Chamber Music", L"Sonata", L"Symphony", L"Booty Bass", L"Primus",
+ L"Porn Groove", L"Satire", L"Slow Jam", L"Club", L"Tango", L"Samba", L"Folklore",
+ L"Ballad", L"Power Ballad", L"Rhythmic Soul", L"Freestyle", L"Duet", L"Punk Rock", L"Drum Solo",
+ L"A Cappella", L"Euro-House", L"Dance Hall", L"Goa", L"Drum & Bass", L"Club-House",
+ L"Hardcore", L"Terror", L"Indie", L"BritPop", L"Afro-Punk", L"Polsk Punk", L"Beat",
+ L"Christian Gangsta Rap", L"Heavy Metal", L"Black Metal", L"Crossover", L"Contemporary Christian",
+ L"Christian Rock", L"Merengue", L"Salsa", L"Thrash Metal", L"Anime", L"JPop", L"Synthpop",
+ L"Abstract", L"Art Rock", L"Baroque", L"Bhangra", L"Big Beat", L"Breakbeat", L"Chillout", L"Downtempo", L"Dub", L"EBM", L"Eclectic", L"Electro",
+ L"Electroclash", L"Emo", L"Experimental", L"Garage", L"Global", L"IDM", L"Illbient", L"Industro-Goth", L"Jam Band", L"Krautrock", L"Leftfield", L"Lounge",
+ L"Math Rock", L"New Romantic", L"Nu-Breakz", L"Post-Punk", L"Post-Rock", L"Psytrance", L"Shoegaze", L"Space Rock", L"Trop Rock", L"World Music", L"Neoclassical",
+ L"Audiobook", L"Audio Theatre", L"Neue Deutsche Welle", L"Podcast", L"Indie Rock", L"G-Funk", L"Dubstep", L"Garage Rock", L"Psybient",
+ L"Glam Rock", L"Dream Pop", L"Merseybeat", L"K-Pop", L"Chiptune", L"Grime", L"Grindcore", L"Indietronic", L"Indietronica", L"Jazz Rock", L"Jazz Fusion",
+ L"Post-Punk Revival", L"Electronica", L"Psychill", L"Ethnotronic", L"Americana", L"Ambient Dub", L"Digital Dub", L"Chillwave", L"Stoner Rock",
+ L"Slowcore", L"Softcore", L"Flamenco", L"Hi-NRG", L"Ethereal", L"Drone", L"Doom Metal", L"Doom Jazz", L"Mainstream", L"Glitch", L"Balearic",
+ L"Modern Classical", L"Mod", L"Contemporary Classical", L"Psybreaks", L"Psystep", L"Psydub", L"Chillstep", L"Berlin School",
+ L"Future Jazz", L"Djent", L"Musique Concrète", L"Electroacoustic", L"Folktronica", L"Texas Country", L"Red Dirt",
+ L"Arabic", L"Asian", L"Bachata", L"Bollywood", L"Cajun", L"Calypso", L"Creole", L"Darkstep", L"Jewish", L"Reggaeton", L"Smooth Jazz",
+ L"Soca", L"Spiritual", L"Turntablism", L"Zouk", L"Neofolk", L"Nu Jazz", L"Psychobilly", L"Rockabilly", L"Schlager & Volksmusik",
+};
+
+const size_t numberOfGenres = sizeof(genres) / sizeof(genres[0]);
+
+const wchar_t * strfields[] =
+{
+ L"artist",
+ L"album",
+ L"albumartist",
+ L"title",
+ L"year",
+ L"genre",
+ L"comment",
+ L"composer",
+ L"publisher",
+ L"disc",
+ L"track",
+ L"bpm",
+ L"GracenoteFileID",
+ L"GracenoteExtData"
+};
+
+const int strfieldctrls[] =
+{
+ IDC_ARTIST,
+ IDC_ALBUM,
+ IDC_ALBUM_ARTIST,
+ IDC_TITLE,
+ IDC_YEAR,
+ IDC_GENRE,
+ IDC_COMMENT,
+ IDC_COMPOSER,
+ IDC_PUBLISHER,
+ IDC_DISC,
+ IDC_TRACK,
+ IDC_BPM,
+ IDC_GN_FILEID,
+ IDC_GN_EXTDATA
+};
+
+const int staticstrfieldctrls[] =
+{
+ IDC_STATIC_ARTIST,
+ IDC_STATIC_ALBUM,
+ IDC_STATIC_ALBUM_ARTIST,
+ IDC_STATIC_TITLE,
+ IDC_STATIC_YEAR,
+ IDC_STATIC_GENRE,
+ IDC_STATIC_COMMENT,
+ IDC_STATIC_COMPOSER,
+ IDC_STATIC_PUBLISHER,
+ IDC_STATIC_DISC,
+ IDC_STATIC_TRACK,
+ IDC_STATIC_BPM,
+ 0,
+ 0
+};
+
+const wchar_t * streamStrfields[] =
+ {
+ L"streamtitle",
+ L"streamgenre",
+ L"streamurl",
+ L"streamname",
+ L"streamcurrenturl",
+ L"streammetadata",
+ };
+
+ const int streamStrfieldctrls[] =
+ {
+ IDC_TITLE,
+ IDC_GENRE,
+ IDC_URL,
+ IDC_STATION,
+ IDC_PLAY_URL,
+ IDC_EXTRA_METADATA,
+ };
+
+ const int staticStreamStrfieldctrls[] =
+ {
+ IDC_STATIC_TITLE,
+ IDC_STATIC_GENRE,
+ IDC_STATIC_URL,
+ IDC_STATIC_STATION,
+ IDC_STATIC_PLAY_URL,
+ 0,
+ };
+#ifndef IGNORE_API_GRACENOTE
+#ifndef _WIN64
+static IConnectionPoint *GetConnectionPoint(IUnknown *punk, REFIID riid)
+{
+ if (!punk)
+ return 0;
+
+ IConnectionPointContainer *pcpc;
+ IConnectionPoint *pcp = 0;
+
+ HRESULT hr = punk->QueryInterface(IID_IConnectionPointContainer, (void **) & pcpc);
+ if (SUCCEEDED(hr))
+ {
+ pcpc->FindConnectionPoint(riid, &pcp);
+ pcpc->Release();
+ }
+ punk->Release();
+ return pcp;
+}
+
+class autoTagListen : public _ICDDBMusicIDManagerEvents
+{
+public:
+ autoTagListen(api_gracenote* gn, ICDDBMusicIDManager3 *musicid, wchar_t *_gracenoteFileId) : hwndDlg(0), h(0), gn(gn),musicid(musicid), done(0), abort(0), gracenoteFileId(_gracenoteFileId)
+ {
+ }
+
+ HRESULT OnTrackIDStatusUpdate(CddbMusicIDStatus Status, BSTR filename, long* _Abort)
+ {
+ if (abort) *_Abort=1;
+ /*switch(Status)
+ {
+ case STATUS_MUSICID_Error:
+ case STATUS_MUSICID_ProcessingFile:
+ case STATUS_MUSICID_LookingUpWaveForm:
+ case STATUS_MUSICID_LookingUpText:
+ case STATUS_MUSICID_CheckForAbort:
+ case STATUS_ALBUMID_Querying:
+ case STATUS_ALBUMID_Queried:
+ case STATUS_ALBUMID_Processing:
+ case STATUS_ALBUMID_Processed:
+ case STATUS_MUSICID_AnalyzingWaveForm:
+ case STATUS_ALBUMID_QueryingWF:
+ }*/
+ // do shit
+ return S_OK;
+ }
+ HRESULT OnTrackIDComplete(LONG match_code, ICddbFileInfo* pInfoIn, ICddbFileInfoList* pListOut)
+ {
+ done = 1;
+ if (match_code <= 1)
+ {
+ if (!abort)
+ {
+ wchar_t title[16] = {0};
+ MessageBoxW(h, getStringW(IDS_NO_MATCH_FOUND, NULL, 0),
+ getStringW(IDS_FAILED, title, 16), MB_ICONWARNING);
+ }
+ EndDialog(hwndDlg,0);
+ return S_OK;
+ }
+
+ long num = 0;
+ pListOut->get_Count(&num);
+ if (!num) return S_OK;
+ ICddbFileInfoPtr infotag = NULL;
+ pListOut->GetFileInfo(1,&infotag);
+
+ if (infotag)
+ {
+ wchar_t buf[2048] = {0};
+ BSTR bstr = buf;
+
+ ICddbFileTagPtr tag = NULL;
+ ICddbDisc2Ptr disc = NULL;
+ ICddbDisc2_5Ptr disc2_5 = NULL;
+ ICddbFileTag2_5Ptr tag2_5 = NULL;
+
+ infotag->get_Tag(&tag);
+ infotag->get_Disc(&disc);
+
+ if (tag)
+ {
+ tag->QueryInterface(&tag2_5);
+ disc->QueryInterface(&disc2_5);
+
+#define PUTINFO(id, ctrl) if (tag) { tag->get_ ## id ## (&bstr); SetDlgItemTextW(h, ctrl, bstr); }
+#define PUTINFO2(id, ctrl) if (tag2_5) { tag2_5->get_ ## id ## (&bstr); SetDlgItemTextW(h, ctrl, bstr); }
+ PUTINFO(LeadArtist, IDC_ARTIST);
+ PUTINFO(Album, IDC_ALBUM);
+ PUTINFO(Title, IDC_TITLE);
+ PUTINFO(Album, IDC_ALBUM);
+
+ if (disc2_5 == NULL
+ || (FAILED(disc2_5->get_V2GenreStringPrimaryByLevel(3, &bstr))
+ && FAILED(disc2_5->get_V2GenreStringPrimaryByLevel(2, &bstr))
+ && FAILED(disc2_5->get_V2GenreStringPrimaryByLevel(1, &bstr))
+ && FAILED(disc2_5->get_V2GenreStringPrimary(&bstr)))
+ )
+ {
+ PUTINFO(Genre, IDC_GENRE);
+ }
+ else
+ {
+ SetDlgItemTextW(h,IDC_GENRE,bstr);
+ }
+ }
+
+ // sending this will ensure that the genre is applied other than in the metadata page
+ SendMessageW(GetParent(h),WM_USER,(WPARAM)strfields[5],(LPARAM)bstr);
+
+ PUTINFO(Year, IDC_YEAR);
+ PUTINFO(Label, IDC_PUBLISHER);
+ PUTINFO(BeatsPerMinute, IDC_BPM);
+ PUTINFO(TrackPosition, IDC_TRACK);
+ PUTINFO(PartOfSet, IDC_DISC);
+ PUTINFO2(Composer, IDC_COMPOSER);
+ PUTINFO2(DiscArtist, IDC_ALBUM_ARTIST);
+ PUTINFO(FileId, IDC_GN_FILEID);
+ PUTINFO2(ExtDataSerialized, IDC_GN_EXTDATA);
+
+#undef PUTINFO
+#undef PUTINFO2
+ // CRASH POINT
+ // This is the starting cause of crashing in the cddb stuff
+ // Without this or with a manual AddRef() before and it'll work ok
+ //infotag->Release();
+ }
+ EndDialog(hwndDlg,0);
+ return S_OK;
+ }
+ HRESULT FillTag(ICddbFileInfo *info, BSTR filename)
+ {
+ if (info)
+ {
+#define PUTINFO(id, ctrl) GetDlgItemTextW(h, ctrl, buf, 2048); if(buf[0]) if (infotag) { infotag->put_ ## id ## (buf); }
+#define PUTINFO2(id, ctrl) GetDlgItemTextW(h, ctrl, buf, 2048); if(buf[0]) if (tag2_5) { tag2_5->put_ ## id ## (buf); }
+
+ ICddbID3TagPtr infotag = NULL;
+ infotag.CreateInstance(CLSID_CddbID3Tag);
+ ICddbFileTag2_5Ptr tag2_5 = NULL;
+ infotag->QueryInterface(&tag2_5);
+ wchar_t buf[2048] = {0};
+
+ PUTINFO(LeadArtist, IDC_ARTIST);
+ PUTINFO(Album, IDC_ALBUM);
+ PUTINFO(Title, IDC_TITLE);
+ PUTINFO(Album, IDC_ALBUM);
+ PUTINFO(Genre, IDC_GENRE);
+ PUTINFO(Year, IDC_YEAR);
+ PUTINFO(Label, IDC_PUBLISHER);
+ PUTINFO(BeatsPerMinute, IDC_BPM);
+ PUTINFO(TrackPosition, IDC_TRACK);
+ PUTINFO(PartOfSet, IDC_DISC);
+ PUTINFO2(Composer, IDC_COMPOSER);
+ PUTINFO2(DiscArtist, IDC_ALBUM_ARTIST);
+
+ in_get_extended_fileinfoW(filename,L"length",buf,2048);
+ tag2_5->put_LengthMS(buf);
+
+ if (gracenoteFileId && *gracenoteFileId)
+ infotag->put_FileId(gracenoteFileId);
+
+#undef PUTINFO
+#undef PUTINFO2
+ info->put_Tag(infotag);
+ }
+ return S_OK;
+ }
+
+ STDMETHODIMP STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObject)
+ {
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, __uuidof(_ICDDBMusicIDManagerEvents)))
+ *ppvObject = (_ICDDBMusicIDManagerEvents *)this;
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+ }
+ ULONG STDMETHODCALLTYPE AddRef(void)
+ {
+ return 1;
+ }
+ ULONG STDMETHODCALLTYPE Release(void)
+ {
+ return 0;
+ }
+ HRESULT STDMETHODCALLTYPE Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+ {
+ switch (dispid)
+ {
+ case 1: // OnTrackIDStatusUpdate, params: CddbMusicIDStatus Status, BSTR filename, long* Abort
+ {
+ long *abort = pdispparams->rgvarg[0].plVal;
+ BSTR filename = pdispparams->rgvarg[1].bstrVal;
+ CddbMusicIDStatus status = (CddbMusicIDStatus)pdispparams->rgvarg[2].lVal;
+ return OnTrackIDStatusUpdate(status,filename,abort);
+ }
+ case 3: // OnTrackIDComplete, params: LONG match_code, ICddbFileInfo* pInfoIn, ICddbFileInfoList* pListOut
+ {
+ IDispatch *disp1 =pdispparams->rgvarg[0].pdispVal;
+ IDispatch *disp2 =pdispparams->rgvarg[1].pdispVal;
+ long match_code = pdispparams->rgvarg[2].lVal;
+
+ ICddbFileInfoPtr pInfoIn;
+ ICddbFileInfoListPtr matchList;
+ disp1->QueryInterface(&matchList);
+ disp2->QueryInterface(&pInfoIn);
+
+ return OnTrackIDComplete(match_code,pInfoIn,matchList);
+ }
+ case 10: // OnGetFingerprintInfo
+ {
+ long *abort = pdispparams->rgvarg[0].plVal;
+ IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
+ BSTR filename = pdispparams->rgvarg[2].bstrVal;
+ ICddbFileInfo *info;
+ disp->QueryInterface(&info);
+ extern DecodeFile *decodeFile;
+ return gn->CreateFingerprint(musicid, decodeFile, info, filename, abort);
+ }
+ break;
+ case 11: // OnGetTagInfo
+ {
+ //long *Abort = pdispparams->rgvarg[0].plVal;
+ IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
+ BSTR filename = pdispparams->rgvarg[2].bstrVal;
+
+ ICddbFileInfo *info;
+ disp->QueryInterface(&info);
+ return FillTag(info, filename);
+ }
+ break;
+ }
+ return DISP_E_MEMBERNOTFOUND;
+ }
+ HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+ {
+ *rgdispid = DISPID_UNKNOWN; return DISP_E_UNKNOWNNAME;
+ }
+ HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+ {
+ return E_NOTIMPL;
+ }
+ HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR * pctinfo)
+ {
+ return E_NOTIMPL;
+ }
+
+ HWND hwndDlg,h;
+ api_gracenote* gn;
+ ICDDBMusicIDManager3 *musicid;
+ int done;
+ long abort;
+ wchar_t *gracenoteFileId;
+};
+
+static INT_PTR CALLBACK FileInfo_Autotagging(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ // have the close button disabled otherwise it might cause confusion
+ EnableMenuItem(GetSystemMenu(hwndDlg, 0), SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
+ SetWindowLong(hwndDlg,GWLP_USERDATA,lParam);
+ autoTagListen * p = (autoTagListen *)lParam;
+ p->hwndDlg = hwndDlg;
+ if (p->done) EndDialog(hwndDlg,0);
+ }
+ break;
+ }
+ return 0;
+}
+#endif
+#endif
+
+LPCWSTR RepairMutlilineString(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer || cchBufferMax < 1)
+ return NULL;
+
+ LPWSTR temp = (WCHAR*)calloc(cchBufferMax, sizeof(WCHAR));
+ if (NULL == temp) return NULL;
+
+ LPWSTR p1, p2;
+ p1 = pszBuffer;
+ p2 = temp;
+
+ INT cchLen;
+ for (cchLen = 0; L'\0' != *p1 && ((p2 - temp) < cchBufferMax); cchLen++)
+ {
+ if(*p1 == L'\n')
+ {
+ *p2++ = L'\r';
+ cchLen++;
+ }
+ *p2++ = *p1++;
+ }
+ CopyMemory(pszBuffer, temp, sizeof(WCHAR) * cchLen);
+ pszBuffer[cchLen] = L'\0';
+ free(temp);
+ return pszBuffer;
+}
+
+static INT_PTR CALLBACK FileInfo_Metadata(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static int my_change=0;
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ my_change=1;
+
+ int y;
+ SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_RESETCONTENT, (WPARAM)0, 0);
+ SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_SETCURSEL, (WPARAM)-1, 0);
+ for (size_t x = 0; x != numberOfGenres; x ++)
+ {
+ y = SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_ADDSTRING, 0, (LPARAM)genres[x]);
+ SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_SETITEMDATA, y, x);
+ }
+ y = SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_ADDSTRING, 0, (LPARAM)L"");
+ SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_SETITEMDATA, y, 255);
+
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+
+ LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
+
+ if (p->mode == FILEINFO_MODE_0) {
+ for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
+ {
+ memset(pszBuffer, 0, sizeof(WCHAR) * TEXTBUFFER_MAX);
+ int result = in_get_extended_fileinfoW(p->filename,strfields[i],pszBuffer,TEXTBUFFER_MAX);
+ SetDlgItemTextW(hwndDlg, strfieldctrls[i], pszBuffer);
+ EnableWindow(GetDlgItem(hwndDlg, strfieldctrls[i]), result?TRUE:FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, staticstrfieldctrls[i]), result?TRUE:FALSE);
+ }
+ } else {
+ for (int i=0; i<sizeof(streamStrfields)/sizeof(wchar_t*); i++)
+ {
+ memset(pszBuffer, 0, sizeof(WCHAR) * TEXTBUFFER_MAX);
+ int result = in_get_extended_fileinfoW(p->filename,streamStrfields[i],pszBuffer,TEXTBUFFER_MAX);
+ if (streamStrfieldctrls[i] != IDC_EXTRA_METADATA) {
+ SetDlgItemTextW(hwndDlg, streamStrfieldctrls[i], pszBuffer);
+ } else {
+ CheckDlgButton(hwndDlg, streamStrfieldctrls[i], result && pszBuffer[0] == L'1' ? TRUE : FALSE);
+ }
+ EnableWindow(GetDlgItem(hwndDlg, streamStrfieldctrls[i]), result ? TRUE : FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, staticStreamStrfieldctrls[i]), result ? TRUE : FALSE);
+ }
+ }
+
+ pszBuffer[0]=0;
+ if (p->mode == FILEINFO_MODE_0) {
+ in_get_extended_fileinfoW(p->filename,L"formatinformation",pszBuffer, TEXTBUFFER_MAX);
+ } else {
+ in_get_extended_fileinfoW(p->filename,L"streaminformation",pszBuffer, TEXTBUFFER_MAX);
+ }
+ // due to quirks with the more common resource editors, is easier to just store the string
+ // internally only with \n and post-process to be \r\n (as here) so it will appear correctly
+ // on new lines as is wanted (silly multiline edit controls)
+ SetDlgItemTextW(hwndDlg, IDC_FORMATINFO, RepairMutlilineString(pszBuffer, TEXTBUFFER_MAX));
+
+ if (p->mode == FILEINFO_MODE_0) {
+ wchar_t tg[64]=L"", ag[64]=L"";
+ in_get_extended_fileinfoW(p->filename,L"replaygain_track_gain",tg,64);
+ in_get_extended_fileinfoW(p->filename,L"replaygain_album_gain",ag,64);
+
+ if (!tg[0]) getStringW(IDS_NOTPRESENT,tg,64);
+ else
+ {
+ // this isn't nice but it localises the RG values
+ // for display as they're saved in the "C" locale
+ double value = _wtof_l(tg,langManager->Get_C_NumericLocale());
+ StringCchPrintfW(tg,64,L"%-+.2f dB", value);
+ }
+ if (!ag[0]) getStringW(IDS_NOTPRESENT,ag,64);
+ else
+ {
+ // this isn't nice but it localises the RG values
+ // for display as they're saved in the "C" locale
+ double value = _wtof_l(ag,langManager->Get_C_NumericLocale());
+ StringCchPrintfW(ag,64,L"%-+.2f dB", value);
+ }
+ wchar_t tgagstr[128] = {0};
+ StringCbPrintfW(pszBuffer, TEXTBUFFER_MAX, getStringW(IDS_TRACK_GAIN_AND_ALBUM_GAIN,tgagstr,128),tg,ag);
+ SetDlgItemTextW(hwndDlg, IDC_REPLAYGAIN, RepairMutlilineString(pszBuffer, TEXTBUFFER_MAX));
+ my_change=0;
+ free(pszBuffer);
+ } else {
+ SetTimer(hwndDlg, 1, 1000, 0);
+ }
+
+ // test for the musicid feature not being available and remove
+ // the autotag button as required (useful for lite installs)
+ #ifndef IGNORE_API_GRACENOTE
+ waServiceFactory *factory = WASABI_API_SVC?WASABI_API_SVC->service_getServiceByGuid(gracenoteApiGUID):0;
+ api_gracenote* gn = NULL;
+ int remove = FALSE;
+ if(factory){
+ gn = (api_gracenote *)factory->getInterface();
+ if(gn){
+ ICDDBMusicIDManager3 *musicid = gn->GetMusicID();
+ if(musicid){
+ musicid->Shutdown();
+ musicid->Release();
+ }
+ else{
+ remove = TRUE;
+ }
+ factory->releaseInterface(gn);
+ }
+ else{
+ remove = TRUE;
+ }
+ }
+ #else
+ int remove = TRUE;
+ #endif
+
+ // remove or disable the button based on what has been
+ // installed or the internet access levels configured
+ if (remove)
+ {
+ DestroyWindow(GetDlgItem(hwndDlg,IDC_AUTOTAG));
+ }
+ else
+ {
+ if (!isInetAvailable())
+ {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTAG), FALSE);
+ }
+ }
+ }
+ break;
+ case WM_TIMER:
+ if (wParam == 1) {
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ if (p && p->mode == FILEINFO_MODE_1) {
+ LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
+ if (pszBuffer) {
+ int start = -1, end = 0;
+ SendDlgItemMessage(hwndDlg, IDC_FORMATINFO, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ in_get_extended_fileinfoW(p->filename, L"streaminformation", pszBuffer, TEXTBUFFER_MAX);
+ // due to quirks with the more common resource editors, is easier to just store the string
+ // internally only with \n and post-process to be \r\n (as here) so it will appear correctly
+ // on new lines as is wanted (silly multiline edit controls)
+ SetDlgItemTextW(hwndDlg, IDC_FORMATINFO, RepairMutlilineString(pszBuffer, TEXTBUFFER_MAX));
+ SendDlgItemMessage(hwndDlg, IDC_FORMATINFO, EM_SETSEL, start, end);
+
+ for (int i=0; i<sizeof(streamStrfields)/sizeof(wchar_t*); i++) {
+ memset(pszBuffer, 0, sizeof(WCHAR) * TEXTBUFFER_MAX);
+ int result = in_get_extended_fileinfoW(p->filename,streamStrfields[i],pszBuffer,TEXTBUFFER_MAX);
+ if (streamStrfieldctrls[i] != IDC_EXTRA_METADATA) {
+ SendDlgItemMessage(hwndDlg, streamStrfieldctrls[i], EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ SetDlgItemTextW(hwndDlg, streamStrfieldctrls[i], pszBuffer);
+ SendDlgItemMessage(hwndDlg, streamStrfieldctrls[i], EM_SETSEL, start, end);
+ } else {
+ CheckDlgButton(hwndDlg, streamStrfieldctrls[i], result && pszBuffer[0] == L'1' ? TRUE : FALSE);
+ }
+ EnableWindow(GetDlgItem(hwndDlg, streamStrfieldctrls[i]), result ? TRUE : FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, staticStreamStrfieldctrls[i]), result ? TRUE : FALSE);
+ }
+ }
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+#ifndef IGNORE_API_GRACENOTE
+#ifndef _WIN64
+ case IDC_AUTOTAG:
+ {
+ ICDDBMusicIDManager3 *musicid = NULL;
+ waServiceFactory *factory = WASABI_API_SVC?WASABI_API_SVC->service_getServiceByGuid(gracenoteApiGUID):0;
+ api_gracenote* gn = NULL;
+ if (factory)
+ {
+ gn = (api_gracenote *)factory->getInterface();
+ if (gn)
+ {
+ musicid = gn->GetMusicID();
+ }
+ }
+ if (!musicid)
+ {
+ wchar_t title[32] = {0};
+ if (gn)
+ {
+ if (factory)
+ {
+ factory->releaseInterface(gn);
+ }
+ gn = NULL;
+ }
+ MessageBoxW(hwndDlg, getStringW(IDS_GRACENOTE_TOOLS_NOT_INSTALLED, NULL, 0),
+ getStringW(IDS_ERROR, title, 32),0);
+ break;
+ }
+ // we have the musicid pointer, so lets try and tag this mother.
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+
+ if (NULL == p || NULL == p->filename || L'\0' == p->filename)
+ break;
+
+ // first, see if there's a pre-existing gracenote file id
+ wchar_t fileid[1024]=L"";
+ extendedFileInfoStructW gracenote_info;
+ gracenote_info.filename = p->filename;
+ gracenote_info.metadata = L"GracenoteFileID";
+ gracenote_info.ret = fileid;
+ gracenote_info.retlen = 1024;
+ if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&gracenote_info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ fileid[0] = L'\0';
+
+ ICddbFileInfoPtr info = 0;
+ info.CreateInstance(CLSID_CddbFileInfo);
+ info->put_Filename((wchar_t*)p->filename);
+ ICddbFileInfoList *dummy=0;
+ long match_code=666;
+ IConnectionPoint *icp = GetConnectionPoint(musicid, DIID__ICDDBMusicIDManagerEvents);
+
+ DWORD m_dwCookie = 0;
+ autoTagListen listen(gn,musicid, fileid);
+ listen.h = hwndDlg;
+ if (icp) icp->Advise(static_cast<IDispatch *>(&listen), &m_dwCookie);
+
+ musicid->TrackID(info, MUSICID_LOOKUP_ASYNC|MUSICID_RETURN_SINGLE|MUSICID_GET_TAG_FROM_APP|MUSICID_GET_FP_FROM_APP|MUSICID_PREFER_WF_MATCHES, &match_code, &dummy);
+ if (dummy)
+ dummy->Release();
+
+ LPDialogBoxParamW(IDD_AUTOTAGGING,hwndDlg,FileInfo_Autotagging,(LPARAM)&listen);
+
+ musicid->Shutdown();
+ musicid->Release();
+ factory->releaseInterface(gn);
+ }
+ break;
+#endif
+#endif
+
+ case IDOK:
+ if (!GetPropW(GetParent(hwndDlg),L"INBUILT_NOWRITEINFO"))
+ {
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+
+ LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
+ if (pszBuffer)
+ {
+ for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
+ {
+ if (!GetDlgItemTextW(hwndDlg,strfieldctrls[i],pszBuffer, TEXTBUFFER_MAX))
+ pszBuffer[0] = L'\0';
+ in_set_extended_fileinfoW(p->filename,strfields[i], pszBuffer);
+ }
+ free(pszBuffer);
+ }
+
+ if (in_write_extended_fileinfo() == 0)
+ {
+ wchar_t title[256] = {0};
+ MessageBoxW(hwndDlg,
+ getStringW(IDS_METADATA_ERROR, NULL, 0),
+ getStringW(IDS_METADATA_ERROR_TITLE, title, 256),
+ MB_OK | MB_ICONWARNING);
+ }
+ }
+ break;
+ default:
+ if (!my_change && (HIWORD(wParam) == EN_CHANGE || HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_EDITUPDATE))
+ {
+ my_change=1;
+ for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
+ {
+ if (LOWORD(wParam) == strfieldctrls[i])
+ {
+ if (HIWORD(wParam) != CBN_SELCHANGE)
+ {
+ LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
+ if (pszBuffer)
+ {
+ GetDlgItemTextW(hwndDlg,strfieldctrls[i], pszBuffer, TEXTBUFFER_MAX);
+ SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)pszBuffer);
+ free(pszBuffer);
+ }
+ }
+ else
+ {
+ int n = SendMessageW(GetDlgItem(hwndDlg, strfieldctrls[i]), CB_GETCURSEL, 0, 0);
+ int m = SendMessageW(GetDlgItem(hwndDlg, strfieldctrls[i]), CB_GETITEMDATA, n, 0);
+ if (m>=0 && m<numberOfGenres)
+ {
+ SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)genres[m]);
+ }
+ // handles case where genre is cleared
+ else if (!n && m == 255)
+ {
+ SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)L"");
+ }
+ else if(n == CB_ERR)
+ {
+ // if we got here then it is likely to be from a genre not in the built in list
+ LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
+ if (pszBuffer)
+ {
+ if(GetDlgItemTextW(hwndDlg,strfieldctrls[i], pszBuffer, TEXTBUFFER_MAX)){
+ SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)pszBuffer);
+ }
+ free(pszBuffer);
+ }
+ }
+ }
+ }
+ }
+ my_change=0;
+ }
+ }
+ break;
+ case WM_USER:
+ if (wParam && lParam && !my_change)
+ {
+ for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
+ if (_wcsicmp((wchar_t*)wParam,strfields[i])==0)
+ SetDlgItemTextW(hwndDlg,strfieldctrls[i],(wchar_t*)lParam);
+ }
+ break;
+ }
+ return 0;
+}
+
+static void Adjust(int bmpw, int bmph, int &x, int &y, int &w, int &h)
+{
+ // maintain 'square' stretching
+ double aspX = (double)(w)/(double)bmpw;
+ double aspY = (double)(h)/(double)bmph;
+ double asp = min(aspX, aspY);
+ int newW = (int)(bmpw*asp);
+ int newH = (int)(bmph*asp);
+ x = (w - newW)/2;
+ y = (h - newH)/2;
+ w = newW;
+ h = newH;
+}
+
+static HBITMAP getBitmap(ARGB32 * data, int w, int h, HWND parent)
+{
+ BITMAPINFO info={0};
+ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info.bmiHeader.biWidth = w;
+ info.bmiHeader.biHeight = -h;
+ info.bmiHeader.biPlanes = 1;
+ info.bmiHeader.biBitCount = 32;
+ info.bmiHeader.biCompression = BI_RGB;
+ HDC dc = GetDC(parent);
+ HBITMAP bm = CreateCompatibleBitmap(dc,w,h);
+ SetDIBits(dc,bm,0,h,data,&info,DIB_RGB_COLORS);
+ ReleaseDC(parent,dc);
+ return bm;
+}
+
+// these two are also used by AlbumArtRetrival.cpp
+ARGB32 * decompressImage(const void *data, int datalen, int * dataW, int * dataH)
+{
+ ARGB32* ret=NULL;
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ if (l->testData(data,datalen))
+ {
+ ret = l->loadImage(data,datalen,dataW,dataH);
+ sf->releaseInterface(l);
+ break;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return ret;
+}
+
+HBITMAP getBitmap(ARGB32 * data, int dw, int dh, int targetW, int targetH, HWND parent)
+{
+ HQSkinBitmap bm(data,dw,dh);
+ int x=0,y=0,w=targetW,h=targetH;
+ Adjust(dw,dh,x,y,w,h);
+ BltCanvas canv(targetW,targetH);
+ bm.stretch(&canv,x,y,w,h);
+ return getBitmap((ARGB32*)canv.getBits(),targetW,targetH,parent);
+}
+
+void EnableArtFrame(HWND hwndDlg, BOOL enable)
+{
+ const int artFrameElements[] =
+ {
+ IDC_STATIC_FRAME,
+ IDC_ARTHOLDER,
+ IDC_BUTTON_CHANGE,
+ IDC_BUTTON_SAVEAS,
+ IDC_BUTTON_COPY,
+ IDC_BUTTON_PASTE,
+ IDC_BUTTON_DELETE,
+ };
+ for (int i=0; i<sizeof(artFrameElements)/sizeof(int); i++)
+ EnableWindow(GetDlgItem(hwndDlg,artFrameElements[i]),enable);
+ SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME,getStringW(IDS_NO_IMAGE,0,0));
+}
+
+class EditArtItem
+{
+public:
+ ARGB32 * bits;
+ int w;
+ int h;
+ void *data;
+ size_t datalen;
+ wchar_t *mimetype;
+ bool dirty;
+ EditArtItem(ARGB32 *bits, int w, int h, bool dirty=false) : bits(bits), w(w), h(h), data(0), datalen(0), mimetype(0), dirty(dirty) {}
+ ~EditArtItem()
+ {
+ if (bits) WASABI_API_MEMMGR->sysFree(bits);
+ if (mimetype) free(mimetype);
+ if (data) WASABI_API_MEMMGR->sysFree(data);
+ }
+};
+
+static EditArtItem * getCurrentArtItem(HWND hwndDlg)
+{
+ int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
+ if (sel == -1)
+ return NULL;
+ EditArtItem *e = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,sel,0);
+ if (e != (EditArtItem *)-1)
+ return e;
+ return NULL;
+}
+
+static void GetSize(HBITMAP bm, int &w, int &h, HWND hwndDlg)
+{
+ HDC dc = GetDC(hwndDlg);
+ BITMAPINFO info={0};
+ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ GetDIBits(dc,bm,0,0,NULL,&info,DIB_RGB_COLORS);
+ w = abs(info.bmiHeader.biWidth);
+ h = abs(info.bmiHeader.biHeight);
+ ReleaseDC(hwndDlg,dc);
+}
+
+static bool AddNewArtItem(HWND hwndDlg)
+{
+ wchar_t buf[100]=L"";
+ GetDlgItemTextW(hwndDlg,IDC_COMBO_ARTTYPE,buf,100);
+ if (!buf[0]) return false;
+ int s=SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_FINDSTRINGEXACT, (WPARAM)-1,(LPARAM)buf);
+
+ if (s != LB_ERR && SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCOUNT,0,0))
+ {
+ // user has selected something already in our list
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,s,0);
+ SendMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_ARTLIST,LBN_SELCHANGE),0);
+ return true;
+ }
+ // let's add this new item
+ s=SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_ADDSTRING,0,(LPARAM)buf);
+ if (s == LB_ERR) return false;
+ EditArtItem *e = new EditArtItem(0,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETITEMDATA,s,(LPARAM)e);
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,s,0);
+ EnableArtFrame(hwndDlg,TRUE);
+ return true;
+}
+
+static svc_imageLoader *FindImageLoader(const wchar_t *filespec, waServiceFactory **factory)
+{
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ if (l->isMine(filespec))
+ {
+ *factory = sf;
+ return l;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return NULL;
+}
+
+
+static ARGB32 *loadImgFromFile(const wchar_t *file, int *len, int *w, int *h, wchar_t ** mime, ARGB32** imageData)
+{
+ waServiceFactory *sf;
+ svc_imageLoader *loader = FindImageLoader(file, &sf);
+ if (loader)
+ {
+ HANDLE hf = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if (hf != INVALID_HANDLE_VALUE)
+ {
+ *len = GetFileSize(hf, 0);
+ HANDLE hmap = CreateFileMapping(hf, 0, PAGE_READONLY, 0, 0, 0);
+ if (hmap)
+ {
+ void *data = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
+ if (data)
+ {
+ if (loader->testData(data,*len))
+ {
+ ARGB32* im = loader->loadImage(data,*len,w,h);
+ if (im && !_wcsicmp(loader->mimeType(), L"image/jpeg"))
+ {
+ *mime = _wcsdup(L"jpg");
+ *imageData = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(*len);
+ memcpy(*imageData, data, *len);
+ }
+ UnmapViewOfFile(data);
+ CloseHandle(hmap);
+ CloseHandle(hf);
+ sf->releaseInterface(loader);
+ return im;
+ }
+ UnmapViewOfFile(data);
+ }
+ CloseHandle(hmap);
+ }
+ CloseHandle(hf);
+ }
+ sf->releaseInterface(loader);
+ }
+ return 0;
+}
+
+static void * writeImg(const ARGB32 *data, int w, int h, int *length, const wchar_t *ext)
+{
+ if (!ext || (ext && !*ext)) return NULL;
+ if (*ext == L'.') ext++;
+ FOURCC imgwrite = svc_imageWriter::getServiceType();
+ int n = (int) WASABI_API_SVC->service_getNumServices(imgwrite);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgwrite,i);
+ if (sf)
+ {
+ svc_imageWriter * l = (svc_imageWriter*)sf->getInterface();
+ if (l)
+ {
+ if (wcsstr(l->getExtensions(),ext))
+ {
+ void* ret = l->convert(data,32,w,h,length);
+ sf->releaseInterface(l);
+ return ret;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return NULL;
+}
+
+static int writeFile(const wchar_t *file, const void * data, int length)
+{
+ FILE *f=_wfopen(file,L"wb");
+ if (!f) return ALBUMART_FAILURE;
+ if (fwrite(data,length,1,f) != 1)
+ {
+ fclose(f);
+ return ALBUMART_FAILURE;
+ }
+ fclose(f);
+ return ALBUMART_SUCCESS;
+}
+
+static void UpdateArtItemFrame(HWND hwndDlg)
+{
+ EditArtItem * e = getCurrentArtItem(hwndDlg);
+ if (e)
+ {
+ wchar_t type[100] = {0}, buf[100] = {0}, *uiType = 0;
+ int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
+ SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,sel,(LPARAM)type);
+
+ if (e->mimetype)
+ {
+ uiType = wcschr(e->mimetype, L'/');
+ if (uiType && *uiType)
+ {
+ uiType++;
+ }
+ }
+
+ int origin[] = {IDS_ORIGIN_NONE, IDS_ORIGIN_EMBEDDED, IDS_ORIGIN_ALBUM_MATCH, IDS_ORIGIN_NFO,
+ IDS_ORIGIN_COVER_MATCH, IDS_ORIGIN_FOLDER_MATCH, IDS_ORIGIN_FRONT_MATCH, IDS_ORIGIN_ARTWORK_MATCH};
+ StringCchPrintfW(caption,128,getStringW(IDS_ARTWORK_DETAILS, NULL, 0), type, e->w, e->h,
+ // TODO: review what we set as the type for this from pasting...
+ getStringW(origin[2/*ret*/], buf, sizeof(buf)), (uiType && *uiType ? uiType : e->mimetype));
+
+ SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME, caption);
+ }
+ else
+ {
+ SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME,getStringW(IDS_NO_IMAGE,0,0));
+ }
+}
+
+static void writeImageToFile(ARGB32 * img, int w, int h, const wchar_t *file)
+{
+ int length=0;
+ void * data = writeImg(img,w,h,&length,wcsrchr(file,L'.'));
+ if (data)
+ {
+ writeFile(file,data,length);
+ WASABI_API_MEMMGR->sysFree(data);
+ }
+}
+
+static INT_PTR CALLBACK FileInfo_Artwork(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ EnableArtFrame(hwndDlg,FALSE);
+
+ // added 30 May 2012 as per email from Tejas w.r.t. to Rovi deal ending
+ // as doing this means we keep the placeholder incase of a change at a
+ // later time and without doing anything to require an translation updates
+ HWND wnd = GetDlgItem(hwndDlg, IDC_BUTTON_DOWNLOAD);
+ if (IsWindow(wnd)) DestroyWindow(wnd);
+
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ if (AGAVE_API_ALBUMART)
+ {
+ int w = 0, h = 0;
+ ARGB32 *bits = NULL;
+ if (AGAVE_API_ALBUMART->GetAlbumArt(p->filename, L"cover", &w, &h, &bits) == ALBUMART_SUCCESS)
+ {
+ WASABI_API_MEMMGR->sysFree(bits);
+ int i = SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_ADDSTRING,0,(LPARAM)getStringW(IDS_COVER,NULL,0));
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,i,0);
+ PostMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_ARTLIST,LBN_SELCHANGE),0);
+ }
+
+ wchar_t *types = NULL;
+#if 0 // benski> TODO:
+ if (AGAVE_API_ALBUMART->GetAlbumArtTypes(p->filename,&types) == ALBUMART_SUCCESS)
+ {
+ wchar_t *p = types;
+ int sel = 0;
+ while (p && *p)
+ {
+ int is_cover = (!_wcsicmp(p,L"cover") || !_wcsicmp(p,getStringW(IDS_COVER,NULL,0)));
+ int i = SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_ADDSTRING,0,(LPARAM)(is_cover?getStringW(IDS_COVER,NULL,0):p));
+ if (!_wcsicmp(p,L"cover"))
+ sel = i;
+ p += wcslen(p) + 1;
+ }
+ WASABI_API_MEMMGR->sysFree(types);
+
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,sel,0);
+ PostMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_ARTLIST,LBN_SELCHANGE),0);
+ }
+#endif
+
+ if (AGAVE_API_ALBUMART->GetValidAlbumArtTypes(p->filename,&types) == ALBUMART_SUCCESS)
+ {
+ wchar_t *p = types;
+ int sel = 0;
+ while (p && *p)
+ {
+ int is_cover = (!_wcsicmp(p,L"cover") || !_wcsicmp(p,getStringW(IDS_COVER,NULL,0)));
+ int i = SendDlgItemMessageW(hwndDlg,IDC_COMBO_ARTTYPE,CB_ADDSTRING,0,(LPARAM)(is_cover?getStringW(IDS_COVER,NULL,0):p));
+ if (is_cover || !_wcsicmp(p, config_artwork_filter))
+ sel = i;
+ p += wcslen(p) + 1;
+ }
+ WASABI_API_MEMMGR->sysFree(types);
+ SendDlgItemMessage(hwndDlg,IDC_COMBO_ARTTYPE,CB_SETCURSEL,sel,0);
+ }
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_ARTLIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ wchar_t type[100]=L"";
+ int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
+
+ if (sel == -1)
+ {
+ HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)0);
+ if (bmold) DeleteObject(bmold);
+ EnableArtFrame(hwndDlg,FALSE);
+ return 0;
+ }
+
+ EnableArtFrame(hwndDlg,TRUE);
+ SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,sel,(LPARAM)type);
+
+ int w = 0, h = 0;
+ ARGB32 *bits = NULL;
+ if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArt(p->filename,(!_wcsicmp(type,getStringW(IDS_COVER,NULL,0))?L"cover":type),&w,&h,&bits) == ALBUMART_SUCCESS)
+ {
+ HBITMAP bm = getBitmap(bits,w,h,228,228,hwndDlg);
+ HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)bm);
+ if (bmold) DeleteObject(bmold);
+
+ wchar_t caption[128], *mimeType = 0, *uiType = 0;
+ int origin[] = {IDS_ORIGIN_NONE, IDS_ORIGIN_EMBEDDED, IDS_ORIGIN_ALBUM_MATCH, IDS_ORIGIN_NFO,
+ IDS_ORIGIN_COVER_MATCH, IDS_ORIGIN_FOLDER_MATCH, IDS_ORIGIN_FRONT_MATCH, IDS_ORIGIN_ARTWORK_MATCH};
+ int ret = AGAVE_API_ALBUMART->GetAlbumArtOrigin(p->filename,(!_wcsicmp(type,getStringW(IDS_COVER,NULL,0))?L"cover":type), &mimeType);
+ if (mimeType)
+ {
+ uiType = wcschr(mimeType, L'/');
+ if (uiType && *uiType)
+ {
+ uiType++;
+ }
+ }
+
+ EditArtItem *e = new EditArtItem(bits,w,h);
+ if (e)
+ {
+ size_t len = 0;
+ ARGB32 *data = NULL;
+ if (AGAVE_API_ALBUMART->GetAlbumArtData(p->filename, L"cover", (void**)&data, &len, NULL) == ALBUMART_SUCCESS)
+ {
+ e->data = data;
+ e->datalen = len;
+ }
+
+ wchar_t mime[32] = {L"image/jpeg"};
+ if (uiType && *uiType)
+ {
+ StringCchPrintfW(mime, 32, L"image/%s", uiType);
+ }
+ else if(mimeType && *mimeType && _wcsicmp(mimeType, L"image/jpeg"))
+ {
+ lstrcpynW(mime, mimeType, 32);
+ }
+ if (mime && *mime) e->mimetype = _wcsdup(mime);
+
+ EditArtItem *eold = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,sel,0);
+ if (eold && eold != (EditArtItem *)-1) delete eold;
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETITEMDATA,sel,(LPARAM)e);
+ }
+
+ wchar_t buf[100] = {0}, buf2[32] = {0};
+ StringCchPrintfW(caption,128,getStringW(IDS_ARTWORK_DETAILS, NULL, 0), type, w, h,
+ getStringW(origin[ret], buf, ARRAYSIZE(buf)),
+ (uiType && *uiType ? uiType :
+ (mimeType && *mimeType ? mimeType :
+ getStringW(IDS_UNKNOWN_MIME, buf2, ARRAYSIZE(buf2)))));
+
+ SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME, caption);
+
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ }
+ }
+ break;
+ // disabled 30 May 2012 as per email from Tejas w.r.t. to Rovi deal ending
+ #if 0
+ case IDC_BUTTON_DOWNLOAD:
+ {
+ wchar_t artist[256]=L"";
+ wchar_t album[256]=L"";
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ GetDlgItemTextW(p->tabs[0],IDC_ALBUM_ARTIST,artist,256);
+ if (!artist[0]) GetDlgItemTextW(p->tabs[0],IDC_ARTIST,artist,256);
+ GetDlgItemTextW(p->tabs[0],IDC_ALBUM,album,256);
+
+ artFetchData d = {sizeof(d),hwndDlg,artist,album,0};
+ int r = (int)SendMessageW(hMainWindow,WM_WA_IPC,(LPARAM)&d,IPC_FETCH_ALBUMART);
+ if (r == -2) break; // cancel all was pressed
+ if (r == 0 && d.imgData && d.imgDataLen) // success
+ {
+ if (AddNewArtItem(hwndDlg))
+ {
+ bool success=false;
+ EditArtItem *e = getCurrentArtItem(hwndDlg);
+ if (e)
+ {
+ int w=0,h=0;
+ ARGB32* data = decompressImage(d.imgData,d.imgDataLen,&w,&h);
+ if (data)
+ {
+ if (e->bits)
+ {
+ WASABI_API_MEMMGR->sysFree(e->bits);
+ e->bits = 0;
+ }
+ if (e->data)
+ {
+ WASABI_API_MEMMGR->sysFree(e->data);
+ e->data = 0;
+ e->datalen = 0;
+ }
+ e->bits = data;
+ e->w = w;
+ e->h = h;
+ if (e->data) WASABI_API_MEMMGR->sysFree(e->data);
+ e->data = d.imgData;
+ d.imgData = 0;
+ e->datalen = d.imgDataLen;
+ if (e->mimetype) free(e->mimetype);
+ e->mimetype = _wcsdup(L"jpg");
+ e->dirty = true;
+ HBITMAP dispbm = getBitmap(e->bits,e->w,e->h,228,228,hwndDlg);
+ HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)dispbm);
+ if (bmold) DeleteObject(bmold);
+ success=true;
+ }
+ }
+ if (!success)
+ {
+ // fail, remove :(
+ int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
+ if (sel == -1)
+ return 0;
+ if (e) delete e;
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
+ EnableArtFrame(hwndDlg,0);
+ }
+ }
+ if (d.imgData)
+ WASABI_API_MEMMGR->sysFree(d.imgData);
+ }
+ }
+ break;
+ #endif
+ case IDC_BUTTON_LOAD:
+ if (AddNewArtItem(hwndDlg))
+ {
+ if (!FileInfo_Artwork(hwndDlg,WM_COMMAND,IDC_BUTTON_CHANGE,0))
+ {
+ // fail, remove :(
+ int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
+ if (sel == -1)
+ return 0;
+ EditArtItem * e = getCurrentArtItem(hwndDlg);
+ if (e) delete e;
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
+ EnableArtFrame(hwndDlg,0);
+ }
+ }
+ break;
+ case IDC_BUTTON_CHANGE:
+ {
+ EditArtItem *e = getCurrentArtItem(hwndDlg);
+ if (!e) break;
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ wchar_t file[1024]=L"", folder[MAX_PATH]=L"";
+ OPENFILENAMEW fn = {sizeof(OPENFILENAMEW),0};
+ // set the ofd to the current file's folder
+ lstrcpynW(folder,p->filename,MAX_PATH);
+ PathRemoveFileSpecW(folder);
+ PathAddBackslashW(folder);
+ fn.lpstrInitialDir = folder;
+ fn.hwndOwner = hwndDlg;
+ fn.lpstrFile = file;
+ fn.nMaxFile = 1024;
+
+ static wchar_t fileExtensionsString[MAX_PATH] = {0};
+ if(!fileExtensionsString[0])
+ {
+ getStringW(IDS_IMAGE_FILES,fileExtensionsString,MAX_PATH);
+ wchar_t *temp=fileExtensionsString+lstrlenW(fileExtensionsString) + 1;
+
+ // query the available image loaders and build it against the supported formats
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ wchar_t *tests[] = {L"*.jpg",L"*.jpeg",L"*.png",L"*.gif",L"*.bmp"};
+ for(int i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+ {
+ if (l->isMine(tests[i]))
+ {
+ StringCchCatW(temp,MAX_PATH,tests[i]);
+ StringCchCatW(temp,MAX_PATH,L";");
+ }
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ *(temp = temp + lstrlenW(temp) + 1) = 0;
+ }
+ fn.lpstrFilter = fileExtensionsString;
+
+ fn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOVALIDATE;
+ if (GetOpenFileNameW(&fn))
+ {
+ int len = 0, w = 0, h = 0;
+ wchar_t * mime = 0;
+ // TODO: benski> save original bits and mime type
+ // UPDATE: will only grab the raw data for jpeg files at the moment
+ ARGB32 * data = 0, * bits = loadImgFromFile(file,&len,&w,&h,&mime,&data);
+ if (bits)
+ {
+ if (e->bits)
+ {
+ WASABI_API_MEMMGR->sysFree(e->bits);
+ e->bits = 0;
+ }
+ if (e->data)
+ {
+ WASABI_API_MEMMGR->sysFree(e->data);
+ e->data = 0;
+ e->datalen = 0;
+ }
+ e->bits = bits;
+ e->w = w;
+ e->h = h;
+ if (data)
+ {
+ e->data = data;
+ e->datalen = len;
+ }
+ if (e->mimetype) free(e->mimetype);
+ e->mimetype = mime;
+ e->dirty = true;
+ HBITMAP dispbm = getBitmap(e->bits,e->w,e->h,228,228,hwndDlg);
+ HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)dispbm);
+ if (bmold) DeleteObject(bmold);
+ return 1;
+ }
+ }
+ break;
+ }
+ case IDC_BUTTON_SAVEAS:
+ {
+ EditArtItem *e = getCurrentArtItem(hwndDlg);
+ if (!e) break;
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ wchar_t file[1024]=L"", folder[MAX_PATH]=L"";
+ OPENFILENAMEW fn = {sizeof(OPENFILENAMEW),0};
+ // set the ofd to the current file's folder
+ lstrcpynW(folder,p->filename,MAX_PATH);
+ PathRemoveFileSpecW(folder);
+ PathAddBackslashW(folder);
+ fn.lpstrInitialDir = folder;
+ fn.hwndOwner = hwndDlg;
+ fn.lpstrFile = file;
+ fn.nMaxFile = 1020;
+
+ static wchar_t *mimes[4] = {0};
+ wchar_t *tests[] = {L"*.jpg",L"*.png",L"*.gif",L"*.bmp"};
+ static int tests_idx[4] = {0,1,2,3}, tests_run = 0, last_filter = -1;
+ static wchar_t filter[1024] = {0}, *sff = filter;
+
+ if(!tests_run)
+ {
+ int def_idx = 0;
+ tests_run = 1;
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i = 0, j = 0; i < n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ int tests_str[] = {IDS_JPEG_FILE,IDS_PNG_FILE,IDS_GIF_FILE,IDS_BMP_FILE};
+ size_t size = 1024;
+ for(int k = 0; k < ARRAYSIZE(tests); k++)
+ {
+ if (l->isMine(tests[k]))
+ {
+ if (!k) def_idx = tests_idx[j] + 1;
+ tests_idx[j] = k;
+ mimes[j] = _wcsdup(l->mimeType());
+ j++;
+ int len = 0;
+ getStringW(tests_str[k],sff,size);
+ size-=(len = lstrlenW(sff)+1);
+ sff+=len;
+ lstrcpynW(sff,tests[k], (int)size);
+ if (!k) lstrcatW(sff, L";*.jpeg");
+ size-=(len = lstrlenW(sff)+1);
+ sff+=len;
+ }
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+
+ last_filter = _r_i("art_flt",last_filter);
+ if (last_filter == -1) last_filter = def_idx;
+ }
+
+ fn.lpstrFilter = filter;
+ fn.nFilterIndex = last_filter; // default to *.jpg / last filter
+ fn.Flags = OFN_OVERWRITEPROMPT;
+ if (GetSaveFileNameW(&fn))
+ {
+ int l = (int) wcslen(file);
+ if (l>4 && file[l-4]==L'.'); // we have an extention
+ else StringCchCatW(file,1024,tests[tests_idx[fn.nFilterIndex-1]]+1); // map to the extension to use
+
+ // where possible see if we can just save the image data without conversion
+ if (e->data && e->mimetype && !_wcsicmp(mimes[fn.nFilterIndex-1], e->mimetype))
+ {
+ writeFile(file, e->data, (int)e->datalen);
+ }
+ else
+ {
+ // though if we're not sure or it is a different format from what is stored
+ // then we'll need to convert (not nice to do) and hope it doesn't fail...
+ writeImageToFile(e->bits,e->w,e->h,file);
+ }
+ }
+
+ last_filter = fn.nFilterIndex;
+ _w_i("art_flt",last_filter);
+ break;
+ }
+ case IDC_BUTTON_COPY:
+ {
+ EditArtItem *e = getCurrentArtItem(hwndDlg);
+ if (!e) break;
+ if (!OpenClipboard(hwndDlg)) break;
+ EmptyClipboard();
+ HBITMAP bm = getBitmap(e->bits,e->w,e->h,hwndDlg);
+ SetClipboardData(CF_BITMAP,bm);
+ CloseClipboard();
+ DeleteObject(bm);
+ break;
+ }
+ case IDC_BUTTON_PASTENEW:
+ if (AddNewArtItem(hwndDlg))
+ {
+ if (!FileInfo_Artwork(hwndDlg,WM_COMMAND,IDC_BUTTON_PASTE,0))
+ {
+ // fail, remove :(
+ int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
+ if (sel == -1)
+ return 0;
+ EditArtItem * e = getCurrentArtItem(hwndDlg);
+ if (e) delete e;
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
+ EnableArtFrame(hwndDlg,0);
+ }
+ }
+ UpdateArtItemFrame(hwndDlg);
+ break;
+ case IDC_BUTTON_PASTE:
+ {
+ EditArtItem *e = getCurrentArtItem(hwndDlg);
+ if (!e) break;
+ if (!OpenClipboard(hwndDlg)) break;
+ HBITMAP bm = (HBITMAP)GetClipboardData(CF_BITMAP);
+ if (bm)
+ {
+ GetSize(bm,e->w,e->h,hwndDlg);
+ BITMAPINFO info={0};
+ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info.bmiHeader.biWidth = e->w;
+ info.bmiHeader.biHeight = -e->h;
+ info.bmiHeader.biPlanes = 1;
+ info.bmiHeader.biBitCount = 32;
+ info.bmiHeader.biCompression = BI_RGB;
+ HDC dc = GetDC(hwndDlg);
+ if (e->bits)
+ {
+ WASABI_API_MEMMGR->sysFree(e->bits);
+ e->bits = 0;
+ }
+ if (e->data)
+ {
+ WASABI_API_MEMMGR->sysFree(e->data);
+ e->data = 0;
+ e->datalen = 0;
+ }
+ e->bits = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(e->w*e->h*sizeof(ARGB32));
+ if (e->mimetype) free(e->mimetype);
+ e->mimetype = _wcsdup(L"image/jpeg");
+ GetDIBits(dc,bm,0,e->h,e->bits,&info,DIB_RGB_COLORS);
+ ReleaseDC(hwndDlg,dc);
+ e->dirty=true;
+ HBITMAP dispbm = getBitmap(e->bits,e->w,e->h,228,228,hwndDlg);
+ HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)dispbm);
+ if (bmold) DeleteObject(bmold);
+ CloseClipboard();
+ UpdateArtItemFrame(hwndDlg);
+ return 1;
+ }
+ CloseClipboard();
+ break;
+ }
+ case IDC_BUTTON_DELETE:
+ {
+ wchar_t buf[1024] = {0};
+ getStringW(IDS_ARTDELETE,buf,1024);
+ if (MessageBoxW(hwndDlg,buf,getStringW(IDS_AREYOUSURE,0,0),MB_YESNO|MB_ICONQUESTION) != IDYES) break;
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ EditArtItem *e = getCurrentArtItem(hwndDlg);
+ if (!e) break;
+ int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
+ buf[0]=0;
+ SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,sel,(LPARAM)buf);
+ AGAVE_API_ALBUMART->DeleteAlbumArt(p->filename,(!_wcsicmp(buf,getStringW(IDS_COVER,NULL,0))?L"cover":buf));
+ HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)0);
+ if (bmold) DeleteObject(bmold);
+ delete e;
+ SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
+ EnableArtFrame(hwndDlg,0);
+ break;
+ }
+ case IDOK:
+ {
+ info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
+ int l = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCOUNT,0,0);
+ for (int i=0; i<l; i++)
+ {
+ EditArtItem *e = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,i,0);
+ if (e && e->dirty)
+ {
+ wchar_t buf[1024] = {0};
+ SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,i,(LPARAM)buf);
+ if (e->data)
+ {
+ AGAVE_API_ALBUMART->SetAlbumArt(p->filename,(!_wcsicmp(buf,getStringW(IDS_COVER,NULL,0))?L"cover":buf),
+ 0,0,e->data,e->datalen,e->mimetype);
+ }
+ else
+ {
+ AGAVE_API_ALBUMART->SetAlbumArt(p->filename,(!_wcsicmp(buf,getStringW(IDS_COVER,NULL,0))?L"cover":buf),
+ e->w,e->h,e->bits,0,0);
+ }
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ {
+ HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_GETIMAGE,IMAGE_BITMAP,0);
+ if (bmold) DeleteObject(bmold);
+ int l = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCOUNT,0,0);
+ for (int i=0; i<l; i++)
+ {
+ EditArtItem *e = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,i,0);
+ if (e && e != (EditArtItem *)-1) delete e;
+ }
+
+ GetDlgItemTextW(hwndDlg, IDC_COMBO_ARTTYPE, config_artwork_filter, ARRAYSIZE(config_artwork_filter));
+ }
+ break;
+ }
+ return 0;
+}
+
+static int checkEditInfoClick(HWND hwndDlg, POINT p, int item, int check)
+{
+ RECT r = {0};
+ GetWindowRect(GetDlgItem(hwndDlg, item), &r);
+ ScreenToClient(hwndDlg, (LPPOINT)&r);
+ ScreenToClient(hwndDlg, (LPPOINT)&r.right);
+ if (PtInRect(&r, p) && !IsDlgButtonChecked(hwndDlg, check))
+ {
+ CheckDlgButton(hwndDlg, check, TRUE);
+ if (item == IDC_COMBO_RATING) SendDlgItemMessage(hwndDlg, IDC_COMBO_RATING, CB_SHOWDROPDOWN, TRUE, 0);
+ EnableWindow(GetDlgItem(hwndDlg, item), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
+ PostMessageW(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, item), (LPARAM)TRUE);
+ return 1;
+ }
+ return 0;
+}
+
+// sets part and parts to -1 or 0 on fail/missing (e.g. parts will be -1 on "1", but 0 on "1/")
+void ParseIntSlashInt(wchar_t *string, int *part, int *parts)
+{
+ *part = -1;
+ *parts = -1;
+
+ if (string && string[0])
+ {
+ *part = _wtoi(string);
+ while (string && *string && *string != '/')
+ {
+ string++;
+ }
+ if (string && *string == '/')
+ {
+ string++;
+ *parts = _wtoi(string);
+ }
+ }
+}
+
+typedef struct
+{
+ mlQueryStructW item;
+ int idx;
+ int ml;
+} queryStructW;
+
+std::vector<queryStructW*> queryList;
+static int got_local_ml = -1;
+static size_t m_upd_nb, m_stopped, m_upd_nb_all, m_upd_nb_cur;
+#define MAKESAFE(x) ((x)?(x):L"")
+
+static void FreeQueryList()
+{
+ for ( queryStructW *query : queryList )
+ {
+ free( query->item.query );
+
+ if ( query->ml )
+ sendMlIpc( ML_IPC_DB_FREEQUERYRESULTSW, (WPARAM)query );
+ else
+ freeRecordList( &query->item.results );
+
+ free( query );
+ }
+
+ queryList.clear();
+}
+
+void CHECK_AND_COPY(itemRecordW *song, HWND hwndParent, int IDCHECK, int ID, wchar_t *&item)
+{
+ if (IsDlgButtonChecked(hwndParent, IDCHECK)) {
+ wchar_t blah[2048];
+ GetDlgItemTextW(hwndParent, ID, blah, 2048);
+ if (wcscmp(MAKESAFE(item), blah))
+ {
+ free(item);
+ item = _wcsdup(blah);
+ }
+ }
+}
+
+static void CHECK_AND_COPY_EXTENDED(itemRecordW *song, HWND hwndParent, int IDCHECK, int ID, const wchar_t *name)
+{
+ if (IsDlgButtonChecked(hwndParent, IDCHECK)) {
+ wchar_t blah[2048];
+ GetDlgItemTextW(hwndParent, ID, blah, 2048);
+ wchar_t *oldData = getRecordExtendedItem(song, name);
+ if (wcscmp(MAKESAFE(oldData), blah)) {
+ setRecordExtendedItem(song, name, blah);
+ }
+ }
+}
+
+static INT_PTR CALLBACK updateFiles_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SetWindowTextW(hwndDlg, getStringW(IDS_UPDATING_FILES, NULL, 0));
+ SetWindowLong(GetDlgItem(hwndDlg, 1008), GWL_STYLE, (GetWindowLongW(GetDlgItem(hwndDlg, 1008), GWL_STYLE)&~SS_CENTER) | SS_LEFTNOWORDWRAP);
+ SetTimer(hwndDlg, 0x123, 30, NULL);
+ m_upd_nb = 0;
+ m_stopped = 0;
+ SendDlgItemMessage(hwndDlg, 1007, PBM_SETRANGE, 0, MAKELPARAM(0, m_upd_nb_all));
+ m_upd_nb_cur = 0;
+ break;
+ }
+ case WM_TIMER:
+ if (wParam == 0x123 && !m_stopped)
+ {
+ unsigned int start_t = GetTickCount();
+again:
+ {
+ if (m_upd_nb >= queryList.size())
+ {
+ //done
+ if (got_local_ml == 1) sendMlIpc(ML_IPC_DB_SYNCDB, 0);
+ EndDialog(hwndDlg, 1);
+ break;
+ }
+
+ int i = (int) m_upd_nb++;
+ itemRecordW *mlsong = &queryList[i]->item.results.Items[0];
+ itemRecordW copy;
+ itemRecordW *song = &copy;
+ copyRecord(&copy, mlsong);
+ HWND hwndParent = GetParent(hwndDlg);
+
+ wchar_t stattmp[512] = {0};
+ wchar_t *p = scanstr_backW(song->filename, L"\\", song->filename - 1) + 1;
+ wsprintfW(stattmp, getStringW(IDS_UPDATING_X, NULL, 0), p);
+ SetDlgItemTextW(hwndDlg, 1008, stattmp);
+
+ SendDlgItemMessage(hwndDlg, 1007, PBM_SETPOS, m_upd_nb_cur, 0);
+ m_upd_nb_cur++;
+
+ int updtagz = !!IsDlgButtonChecked(hwndParent, 1052);
+
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_ARTIST, IDC_EDIT_ARTIST, song->artist);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_TITLE, IDC_EDIT_TITLE, song->title);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_ALBUM, IDC_EDIT_ALBUM, song->album);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_COMMENT, IDC_EDIT_COMMENT, song->comment);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_GENRE, IDC_EDIT_GENRE, song->genre);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_ALBUMARTIST, IDC_EDIT_ALBUMARTIST, song->albumartist);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_PUBLISHER, IDC_EDIT_PUBLISHER, song->publisher);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_COMPOSER, IDC_EDIT_COMPOSER, song->composer);
+ CHECK_AND_COPY(song, hwndParent, IDC_CHECK_CATEGORY, IDC_EDIT_CATEGORY, song->category);
+
+ CHECK_AND_COPY_EXTENDED(song, hwndParent, IDC_CHECK_DIRECTOR, IDC_EDIT_DIRECTOR, L"director");
+ CHECK_AND_COPY_EXTENDED(song, hwndParent, IDC_CHECK_PRODUCER, IDC_EDIT_PRODUCER, L"producer");
+ CHECK_AND_COPY_EXTENDED(song, hwndParent, IDC_CHECK_PODCAST_CHANNEL, IDC_EDIT_PODCAST_CHANNEL, L"podcastchannel");
+
+#define CHECK_AND_COPY_EXTENDED_PC(IDCHECK, field, name) \
+ wchar_t blah[2048] = {0}; StringCchPrintfW(blah, 2048, L"%d", (IsDlgButtonChecked(hwndParent, IDCHECK) == BST_CHECKED));\
+ wchar_t *oldData = getRecordExtendedItem(song, name);\
+ if (wcscmp(MAKESAFE(oldData), blah)) { setRecordExtendedItem(song, name, blah); }
+
+ CHECK_AND_COPY_EXTENDED_PC(IDC_CHECK_PODCAST, MAINTABLE_ID_ISPODCAST, L"ispodcast");
+
+ if (IsDlgButtonChecked(hwndParent, IDC_CHECK_TRACK))
+ {
+ wchar_t blah[64] = {0};
+ GetDlgItemTextW(hwndParent, IDC_EDIT_TRACK, blah, 64);
+ int track, tracks;
+ ParseIntSlashInt(blah, &track, &tracks);
+ if (tracks <= 0) tracks = -1;
+ if (track <= 0) track = -1;
+
+ if (song->track != track || song->tracks != tracks)
+ {
+ song->track = track;
+ song->tracks = tracks;
+ }
+ }
+
+ if (IsDlgButtonChecked(hwndParent, IDC_CHECK_DISC))
+ {
+ wchar_t blah[64] = {0};
+ GetDlgItemTextW(hwndParent, IDC_EDIT_DISC, blah, 64);
+ int disc, discs;
+ ParseIntSlashInt(blah, &disc, &discs);
+ if (discs <= 0) discs = -1;
+ if (disc <= 0) disc = -1;
+
+ if (song->disc != disc || song->discs != discs)
+ {
+ song->disc = disc;
+ song->discs = discs;
+ }
+ }
+
+ if (IsDlgButtonChecked(hwndParent, IDC_CHECK_YEAR))
+ {
+ char blah[64] = {0};
+ GetDlgItemTextA(hwndParent, IDC_EDIT_YEAR, blah, 64);
+ int n = atoi(blah);
+ if (n <= 0) n = -1;
+ if (song->year != n) song->year = n;
+ }
+
+ if (IsDlgButtonChecked(hwndParent, IDC_CHECK_BPM))
+ {
+ char blah[64] = {0};
+ GetDlgItemTextA(hwndParent, IDC_EDIT_BPM, blah, 64);
+ int n = atoi(blah);
+ if (n <= 0) n = -1;
+ if (song->bpm != n) song->bpm = n;
+ }
+
+ if (IsDlgButtonChecked(hwndParent, IDC_CHECK_RATING))
+ {
+ int n = SendDlgItemMessage(hwndParent, IDC_COMBO_RATING, CB_GETCURSEL, 0, 0), rating = -1;
+ if (n != CB_ERR && (n >= 0 && n < 5)) rating = 5 - n;
+ if (song->rating != rating) song->rating = rating;
+ }
+
+ // no need to send this if there's no ml present
+ if (got_local_ml == 1) sendMlIpc((!config_upd_mode ? ML_IPC_DB_ADDORUPDATEITEMW : ML_IPC_DB_UPDATEITEMW), (WPARAM)song);
+
+ if (updtagz || !got_local_ml)
+ {
+ m_stopped = 1;
+retry:
+ if (in_set_extended_fileinfoW(song->filename, L"title", song->title)) // if this returns 0, then this format doesnt even support extended
+ {
+ in_set_extended_fileinfoW(song->filename, L"artist", song->artist);
+ in_set_extended_fileinfoW(song->filename, L"album", song->album);
+ in_set_extended_fileinfoW(song->filename, L"comment", song->comment);
+ in_set_extended_fileinfoW(song->filename, L"genre", song->genre);
+
+ wchar_t buf[32] = {0};
+ if (song->track > 0)
+ {
+ if (song->tracks > 0)
+ wsprintfW(buf, L"%d/%d", song->track, song->tracks);
+ else
+ wsprintfW(buf, L"%d", song->track);
+ }
+ else buf[0] = 0;
+ in_set_extended_fileinfoW(song->filename, L"track", buf);
+
+ if (song->year > 0) wsprintfW(buf, L"%d", song->year);
+ else buf[0] = 0;
+ in_set_extended_fileinfoW(song->filename, L"year", buf);
+
+ if (song->disc > 0)
+ {
+ if (song->discs > 0)
+ wsprintfW(buf, L"%d/%d", song->disc, song->discs);
+ else
+ wsprintfW(buf, L"%d", song->disc);
+ }
+ else buf[0] = 0;
+ in_set_extended_fileinfoW(song->filename, L"disc", buf);
+
+ if (song->rating > 0) wsprintfW(buf, L"%d", song->rating);
+ else buf[0] = 0;
+ if (!in_set_extended_fileinfoW(song->filename, L"rating", buf))
+ {
+ // for ratings, try using the library just to cover all bases for format types
+ file_set_ratingW rate = {0};
+ rate.fileName = song->filename;
+ rate.newRating = song->rating;
+ sendMlIpc(ML_IPC_SET_FILE_RATINGW, (WPARAM)&rate);
+ }
+
+ if (song->bpm > 0) wsprintfW(buf, L"%d", song->bpm);
+ else buf[0] = 0;
+ in_set_extended_fileinfoW(song->filename, L"bpm", buf);
+
+ in_set_extended_fileinfoW(song->filename, L"albumartist", song->albumartist);
+ in_set_extended_fileinfoW(song->filename, L"publisher", song->publisher);
+ in_set_extended_fileinfoW(song->filename, L"composer", song->composer);
+ in_set_extended_fileinfoW(song->filename, L"category", song->category);
+ in_set_extended_fileinfoW(song->filename, L"director", getRecordExtendedItem(song, L"director"));
+ in_set_extended_fileinfoW(song->filename, L"producer", getRecordExtendedItem(song, L"producer"));
+
+ if (in_write_extended_fileinfo() == 0)
+ {
+ wchar_t tmp[1024] = {0};
+ wsprintfW(tmp, getStringW(IDS_ERROR_UPDATING_FILE, NULL, 0), song->filename);
+ int ret = MessageBoxW(hwndDlg, tmp, getStringW(IDS_INFO_UPDATING_ERROR, NULL, 0), MB_RETRYCANCEL);
+ if (ret == IDRETRY) goto retry;
+ if (ret == IDCANCEL)
+ {
+ EndDialog(hwndDlg, 0);
+ freeRecord(&copy);
+ break;
+ }
+ }
+ }
+
+ int x = queryList[i]->idx;
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)song->filename, IPC_FILE_TAG_MAY_HAVE_UPDATEDW);
+ PlayList_setitem(x, song->filename, PlayList_gettitle(song->filename, 1));
+ PlayList_setlastlen(x);
+
+ m_stopped = 0;
+ }
+ freeRecord(&copy);
+ }
+ if (GetTickCount() - start_t < 30) goto again;
+ }
+ break;
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDCANCEL)
+ {
+ EndDialog(hwndDlg, 0);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT_PTR CALLBACK EditInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ wchar_t *last_artist = NULL, *last_title = NULL, *last_album = NULL, *last_genre = NULL,
+ *last_comment = NULL, *last_albumartist = NULL, *last_composer = NULL,
+ *last_publisher = NULL, *last_ispodcast = NULL, *last_podcastchannel = NULL;
+ const wchar_t *last_category = NULL, *last_director = NULL, *last_producer = NULL;
+ int last_year = -1, last_track = -1, last_disc = -1, last_discs = -1, last_tracks = -1,
+ last_bpm = -1, last_rating = -1, disable_artist = 0, disable_title = 0,
+ disable_album = 0, disable_genre = 0, disable_year = 0, disable_track = 0,
+ disable_comment = 0, disable_disc = 0, disable_albumartist = 0, disable_composer = 0,
+ disable_publisher = 0, disable_discs = 0, disable_tracks = 0, disable_category = 0,
+ disable_director = 0, disable_producer = 0, disable_bpm = 0, disable_rating = 0,
+ disable_ispodcast = 0, disable_podcastchannel = 0, nb = 0;
+
+ if (got_local_ml == -1)
+ {
+ got_local_ml = (got_ml ? !!GetModuleHandleW(L"ml_local.dll") : 0);
+ }
+
+ if (got_local_ml == 1)
+ {
+ if (GetPrivateProfileIntW(L"gen_ml_config", L"upd_tagz", 1, ML_INI_FILE))
+ CheckDlgButton(hwndDlg, 1052, BST_CHECKED);
+ }
+ else
+ ShowWindow(GetDlgItem(hwndDlg, 1052), SW_HIDE);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+
+ SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605\u2605\u2605\u2605");
+ SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605\u2605\u2605");
+ SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605\u2605");
+ SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605");
+ SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605");
+ SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)getStringW(IDS_NO_RATING, NULL, 0));
+
+ FreeQueryList();
+ LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
+ if (pszBuffer)
+ {
+ for (int i = 0; i < PlayList_getlength(); i++)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (PlayList_getselect2(i, fn))
+ {
+ if (!PathIsURLW(fn) || !_wcsnicmp(fn, L"cda://", 6))
+ {
+ queryStructW *query = (queryStructW *)calloc(1, sizeof(queryStructW));
+ if (query)
+ {
+ queryList.push_back(query);
+ query->item.query = _wcsdup(fn);
+
+ // hit the library where possible as it'll be faster (and more integrated)
+ if (got_local_ml == 1)
+ {
+ if (sendMlIpc(ML_IPC_DB_RUNQUERY_FILENAMEW, (WPARAM)query) == 1)
+ {
+#define SAVE_LAST_STR(last, check, disable) if (!disable && check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }
+#define SAVE_LAST_INT(last, check, disable) if (!disable && check > 0) { if (last == -1) last = check; else if (last != check) disable = 1; }
+
+ SAVE_LAST_STR(last_artist, query->item.results.Items[0].artist, disable_artist);
+ SAVE_LAST_STR(last_title, query->item.results.Items[0].title, disable_title);
+ SAVE_LAST_STR(last_album, query->item.results.Items[0].album, disable_album);
+ SAVE_LAST_STR(last_comment, query->item.results.Items[0].comment, disable_comment);
+ SAVE_LAST_STR(last_genre, query->item.results.Items[0].genre, disable_genre);
+
+ SAVE_LAST_INT(last_year, query->item.results.Items[0].year, disable_year);
+ SAVE_LAST_INT(last_track, query->item.results.Items[0].track, disable_track);
+ SAVE_LAST_INT(last_tracks, query->item.results.Items[0].tracks, disable_tracks);
+ SAVE_LAST_INT(last_disc, query->item.results.Items[0].disc, disable_disc);
+ SAVE_LAST_INT(last_discs, query->item.results.Items[0].discs, disable_discs);
+ SAVE_LAST_INT(last_rating, query->item.results.Items[0].rating, disable_rating);
+ SAVE_LAST_INT(last_bpm, query->item.results.Items[0].bpm, disable_bpm);
+
+ SAVE_LAST_STR(last_albumartist, query->item.results.Items[0].albumartist, disable_albumartist);
+ SAVE_LAST_STR(last_composer, query->item.results.Items[0].composer, disable_composer);
+ SAVE_LAST_STR(last_publisher, query->item.results.Items[0].publisher, disable_publisher);
+ SAVE_LAST_STR(last_category, query->item.results.Items[0].category, disable_category);
+
+#define SAVE_LAST_STR_EXTENDED(last, name, disable) if (!disable) { wchar_t *check = getRecordExtendedItem(&query->item.results.Items[0], name); if (check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }};
+
+ SAVE_LAST_STR_EXTENDED(last_director, L"director", disable_director);
+ SAVE_LAST_STR_EXTENDED(last_producer, L"producer", disable_producer);
+ SAVE_LAST_STR_EXTENDED(last_podcastchannel, L"podcastchannel", disable_podcastchannel);
+ SAVE_LAST_STR_EXTENDED(last_ispodcast, L"ispodcast", disable_ispodcast);
+ nb++;
+ query->ml = 1;
+ query->idx = i;
+ }
+ else
+ {
+ goto non_ml;
+ }
+ }
+ else
+ {
+non_ml:
+ allocRecordList(&query->item.results, 1, 0);
+ query->item.results.Items[0].filename = _wcsdup(fn);
+
+#define SAVE_LAST_STR(last, check, disable) if (!disable && check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }
+#define SAVE_LAST_INT(last, check, disable) if (!disable && check > 0) { if (last == -1) last = check; else if (last != check) disable = 1; }
+
+ if (in_get_extended_fileinfoW(fn, L"artist", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].artist = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_artist, query->item.results.Items[0].artist, disable_artist);
+
+ if (in_get_extended_fileinfoW(fn, L"title", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].title = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_title, query->item.results.Items[0].title, disable_title);
+
+ if (in_get_extended_fileinfoW(fn, L"album", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].album = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_album, query->item.results.Items[0].album, disable_album);
+
+ if (in_get_extended_fileinfoW(fn, L"comment", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].comment = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_comment, query->item.results.Items[0].comment, disable_comment);
+
+ if (in_get_extended_fileinfoW(fn, L"genre", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].genre = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_genre, query->item.results.Items[0].genre, disable_genre);
+
+ if (in_get_extended_fileinfoW(fn, L"year", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].year = _wtoi(pszBuffer);
+ SAVE_LAST_INT(last_year, query->item.results.Items[0].year, disable_year);
+
+ if (in_get_extended_fileinfoW(fn, L"track", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].track = _wtoi(pszBuffer);
+ SAVE_LAST_INT(last_track, query->item.results.Items[0].track, disable_track);
+
+ if (in_get_extended_fileinfoW(fn, L"tracks", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].tracks = _wtoi(pszBuffer);
+ SAVE_LAST_INT(last_tracks, query->item.results.Items[0].tracks, disable_tracks);
+
+ if (in_get_extended_fileinfoW(fn, L"disc", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].disc = _wtoi(pszBuffer);
+ SAVE_LAST_INT(last_disc, query->item.results.Items[0].disc, disable_disc);
+
+ if (in_get_extended_fileinfoW(fn, L"discs", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].discs = _wtoi(pszBuffer);
+ SAVE_LAST_INT(last_discs, query->item.results.Items[0].discs, disable_discs);
+
+ // for ratings, try using the library just to cover all bases for format types
+ if (in_get_extended_fileinfoW(fn, L"rating", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].rating = _wtoi(pszBuffer);
+ else
+ query->item.results.Items[0].rating = sendMlIpc(ML_IPC_GET_FILE_RATINGW, (WPARAM)fn);
+ SAVE_LAST_INT(last_rating, query->item.results.Items[0].rating, disable_rating);
+
+ if (in_get_extended_fileinfoW(fn, L"bpm", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].bpm = _wtoi(pszBuffer);
+ SAVE_LAST_INT(last_bpm, query->item.results.Items[0].bpm, disable_bpm);
+
+ if (in_get_extended_fileinfoW(fn, L"albumartist", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].albumartist = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_albumartist, query->item.results.Items[0].albumartist, disable_albumartist);
+
+ if (in_get_extended_fileinfoW(fn, L"composer", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].composer = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_composer, query->item.results.Items[0].composer, disable_composer);
+
+ if (in_get_extended_fileinfoW(fn, L"publisher", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].publisher = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_publisher, query->item.results.Items[0].publisher, disable_publisher);
+
+ if (in_get_extended_fileinfoW(fn, L"category", pszBuffer, TEXTBUFFER_MAX))
+ query->item.results.Items[0].category = _wcsdup(pszBuffer);
+ SAVE_LAST_STR(last_category, query->item.results.Items[0].category, disable_category);
+
+#define SAVE_LAST_STR_EXTENDED(last, name, disable) if (!disable) { wchar_t *check = getRecordExtendedItem(&query->item.results.Items[0], name); if (check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }};
+
+ if (in_get_extended_fileinfoW(fn, L"director", pszBuffer, TEXTBUFFER_MAX))
+ {
+ setRecordExtendedItem(&query->item.results.Items[0], L"director", pszBuffer);
+ SAVE_LAST_STR_EXTENDED(last_director, L"director", disable_director);
+ }
+
+ if (in_get_extended_fileinfoW(fn, L"producer", pszBuffer, TEXTBUFFER_MAX))
+ {
+ setRecordExtendedItem(&query->item.results.Items[0], L"producer", pszBuffer);
+ SAVE_LAST_STR_EXTENDED(last_producer, L"producer", disable_producer);
+ }
+
+ // not available in non-ml setups
+ /*SAVE_LAST_STR_EXTENDED(last_podcastchannel, L"podcastchannel", disable_podcastchannel);
+ SAVE_LAST_STR_EXTENDED(last_ispodcast, L"ispodcast", disable_ispodcast);*/
+ nb++;
+ query->ml = 0;
+ query->idx = i;
+ }
+ }
+ }
+ }
+ }
+ free(pszBuffer);
+ }
+
+ if (!disable_artist && last_artist) SetDlgItemTextW(hwndDlg, IDC_EDIT_ARTIST, last_artist);
+ if (!disable_title && last_title) SetDlgItemTextW(hwndDlg, IDC_EDIT_TITLE, last_title);
+ if (!disable_album && last_album) SetDlgItemTextW(hwndDlg, IDC_EDIT_ALBUM, last_album);
+ if (!disable_comment && last_comment) SetDlgItemTextW(hwndDlg, IDC_EDIT_COMMENT, last_comment);
+ if (!disable_albumartist && last_albumartist) SetDlgItemTextW(hwndDlg, IDC_EDIT_ALBUMARTIST, last_albumartist);
+ if (!disable_composer && last_composer) SetDlgItemTextW(hwndDlg, IDC_EDIT_COMPOSER, last_composer);
+ if (!disable_publisher && last_publisher) SetDlgItemTextW(hwndDlg, IDC_EDIT_PUBLISHER, last_publisher);
+ if (!disable_genre && last_genre) SetDlgItemTextW(hwndDlg, IDC_EDIT_GENRE, last_genre);
+ if (!disable_category && last_category) SetDlgItemTextW(hwndDlg, IDC_EDIT_CATEGORY, last_category);
+ if (!disable_director && last_director) SetDlgItemTextW(hwndDlg, IDC_EDIT_DIRECTOR, last_director);
+ if (!disable_producer && last_producer) SetDlgItemTextW(hwndDlg, IDC_EDIT_PRODUCER, last_producer);
+ if (!disable_podcastchannel && last_podcastchannel) SetDlgItemTextW(hwndDlg, IDC_EDIT_PODCAST_CHANNEL, last_podcastchannel);
+ if (!disable_ispodcast && last_ispodcast)
+ {
+ CheckDlgButton(hwndDlg, IDC_CHECK_PODCAST, (_wtoi(last_ispodcast) == 1 ? BST_CHECKED : BST_UNCHECKED));
+ }
+ if (!disable_year && last_year > 0)
+ {
+ wchar_t tmp[64] = {0};
+ wsprintfW(tmp, L"%d", last_year);
+ SetDlgItemTextW(hwndDlg, IDC_EDIT_YEAR, tmp);
+ }
+ if (!disable_bpm && last_bpm > 0)
+ {
+ wchar_t tmp[64] = {0};
+ wsprintfW(tmp, L"%d", last_bpm);
+ SetDlgItemTextW(hwndDlg, IDC_EDIT_BPM, tmp);
+ }
+ if (!disable_rating)
+ {
+ if (last_rating > 0 && last_rating <= 5)
+ {
+ SendDlgItemMessage(hwndDlg, IDC_COMBO_RATING, CB_SETCURSEL, 5 - last_rating, 0);
+ }
+ else SendDlgItemMessage(hwndDlg, IDC_COMBO_RATING, CB_SETCURSEL, 5, 0);
+ }
+ if (!disable_track && last_track > 0 && !disable_tracks)
+ {
+ wchar_t tmp[64] = {0};
+ if (!disable_tracks && last_tracks > 0)
+ wsprintfW(tmp, L"%d/%d", last_track, last_tracks);
+ else
+ wsprintfW(tmp, L"%d", last_track);
+ SetDlgItemTextW(hwndDlg, IDC_EDIT_TRACK, tmp);
+ }
+ if (!disable_disc && last_disc > 0
+ && !disable_discs)
+ {
+ wchar_t tmp[64] = {0};
+ if (!disable_discs && last_discs > 0)
+ wsprintfW(tmp, L"%d/%d", last_disc, last_discs);
+ else
+ wsprintfW(tmp, L"%d", last_disc);
+ SetDlgItemTextW(hwndDlg, IDC_EDIT_DISC, tmp);
+ }
+ wchar_t tmp[512] = {0};
+ wsprintfW(tmp, getStringW((nb==1?IDS_X_ITEM_SELECTED:IDS_X_ITEMS_SELECTED), NULL, 0), nb);
+ SetDlgItemTextW(hwndDlg, 1051, tmp);
+
+ if (!nb)
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+ ShowWindow(GetDlgItem(hwndDlg, 1052), SW_HIDE);
+ }
+
+ // show edit info window and restore last position as applicable
+ POINT pt = {editinfo_rect.left, editinfo_rect.top};
+ if (!windowOffScreen(hwndDlg, pt) && !IsWindowVisible(hwndDlg))
+ SetWindowPos(hwndDlg, HWND_TOP, editinfo_rect.left, editinfo_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+ }
+ return 1;
+ case WM_COMMAND:
+#define HANDLE_CONTROL(item, check) { int enabled = IsDlgButtonChecked(hwndDlg, check); EnableWindow(GetDlgItem(hwndDlg, item), enabled); EnableWindow(GetDlgItem(hwndDlg, IDOK), enabled); }
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHECK_ARTIST: HANDLE_CONTROL(IDC_EDIT_ARTIST, IDC_CHECK_ARTIST); break;
+ case IDC_CHECK_TITLE: HANDLE_CONTROL(IDC_EDIT_TITLE, IDC_CHECK_TITLE); break;
+ case IDC_CHECK_ALBUM: HANDLE_CONTROL(IDC_EDIT_ALBUM, IDC_CHECK_ALBUM); break;
+ case IDC_CHECK_COMMENT: HANDLE_CONTROL(IDC_EDIT_COMMENT, IDC_CHECK_COMMENT); break;
+ case IDC_CHECK_ALBUMARTIST: HANDLE_CONTROL(IDC_EDIT_ALBUMARTIST, IDC_CHECK_ALBUMARTIST); break;
+ case IDC_CHECK_COMPOSER: HANDLE_CONTROL(IDC_EDIT_COMPOSER, IDC_CHECK_COMPOSER); break;
+ case IDC_CHECK_PUBLISHER: HANDLE_CONTROL(IDC_EDIT_PUBLISHER, IDC_CHECK_PUBLISHER); break;
+ case IDC_CHECK_TRACK: HANDLE_CONTROL(IDC_EDIT_TRACK, IDC_CHECK_TRACK); break;
+ case IDC_CHECK_DISC: HANDLE_CONTROL(IDC_EDIT_DISC, IDC_CHECK_DISC); break;
+ case IDC_CHECK_GENRE: HANDLE_CONTROL(IDC_EDIT_GENRE, IDC_CHECK_GENRE); break;
+ case IDC_CHECK_YEAR: HANDLE_CONTROL(IDC_EDIT_YEAR, IDC_CHECK_YEAR); break;
+ case IDC_CHECK_CATEGORY: HANDLE_CONTROL(IDC_EDIT_CATEGORY, IDC_CHECK_CATEGORY); break;
+ case IDC_CHECK_DIRECTOR: HANDLE_CONTROL(IDC_EDIT_DIRECTOR, IDC_CHECK_DIRECTOR); break;
+ case IDC_CHECK_PRODUCER: HANDLE_CONTROL(IDC_EDIT_PRODUCER, IDC_CHECK_PRODUCER); break;
+ case IDC_CHECK_PODCAST_CHANNEL: HANDLE_CONTROL(IDC_EDIT_PODCAST_CHANNEL, IDC_CHECK_PODCAST_CHANNEL); break;
+ case IDC_CHECK_BPM: HANDLE_CONTROL(IDC_EDIT_BPM, IDC_CHECK_BPM); break;
+ case IDC_CHECK_RATING: HANDLE_CONTROL(IDC_COMBO_RATING, IDC_CHECK_RATING); break;
+ case IDOK:
+ {
+ if (got_local_ml == 1)
+ {
+ wchar_t str[4] = {0};
+ StringCchPrintfW(str, 4, L"%d", !!IsDlgButtonChecked(hwndDlg, 1052));
+ WritePrivateProfileStringW(L"gen_ml_config", L"upd_tagz", str, ML_INI_FILE);
+ }
+
+ int ret = LPDialogBoxW(IDD_ADDSTUFF, hwndDlg, updateFiles_dialogProc);
+ if (!ret) break;
+ }
+ case IDCANCEL:
+ {
+ FreeQueryList();
+ GetWindowRect(hwndDlg, &editinfo_rect);
+ EndDialog(hwndDlg, 0);
+ break;
+ }
+ }
+ break;
+ case WM_LBUTTONDOWN:
+ {
+ POINTS p = MAKEPOINTS(lParam);
+ POINT p2 = {p.x, p.y};
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_ARTIST, IDC_CHECK_ARTIST)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_TITLE, IDC_CHECK_TITLE)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_ALBUM, IDC_CHECK_ALBUM)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_COMMENT, IDC_CHECK_COMMENT)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_ALBUMARTIST, IDC_CHECK_ALBUMARTIST)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_COMPOSER, IDC_CHECK_COMPOSER)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_PUBLISHER, IDC_CHECK_PUBLISHER)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_TRACK, IDC_CHECK_TRACK)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_GENRE, IDC_CHECK_GENRE)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_YEAR, IDC_CHECK_YEAR)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_DISC, IDC_CHECK_DISC)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_CATEGORY, IDC_CHECK_CATEGORY)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_DIRECTOR, IDC_CHECK_DIRECTOR)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_PRODUCER, IDC_CHECK_PRODUCER)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_PODCAST_CHANNEL, IDC_CHECK_PODCAST_CHANNEL)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_BPM, IDC_CHECK_BPM)) break;
+ if (checkEditInfoClick(hwndDlg, p2, IDC_COMBO_RATING, IDC_CHECK_RATING)) break;
+ }
+ break;
+ }
+ return FALSE;
+} \ No newline at end of file
diff --git a/Src/Winamp/FloatAttribute.cpp b/Src/Winamp/FloatAttribute.cpp
new file mode 100644
index 00000000..1d8ad07c
--- /dev/null
+++ b/Src/Winamp/FloatAttribute.cpp
@@ -0,0 +1,30 @@
+#include "main.h"
+#include "attributes.h"
+
+_float::_float()
+{
+ value = 0;
+}
+
+_float::_float(float defaultValue)
+{
+ value = defaultValue;
+}
+
+intptr_t _float::operator =(intptr_t uintValue)
+{
+ value = static_cast<float>(uintValue);
+ return static_cast<intptr_t>(value);
+}
+
+float _float::operator =(float uintValue)
+{
+ value = uintValue;
+ return value;
+}
+
+#define CBCLASS _float
+START_DISPATCH;
+CB(IFC_CONFIGITEM_GETINT, GetInt)
+CB(IFC_CONFIGITEM_GETFLOAT, GetFloat)
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Winamp/GEN.H b/Src/Winamp/GEN.H
new file mode 100644
index 00000000..29310147
--- /dev/null
+++ b/Src/Winamp/GEN.H
@@ -0,0 +1,86 @@
+#ifndef NULLSOFT_WINAMP_GEN_H
+#define NULLSOFT_WINAMP_GEN_H
+// General Purpose plugin interface
+
+#include <windows.h>
+
+typedef struct {
+ int version;
+ char* description;
+ int(__cdecl* init)();
+ void(__cdecl* config)();
+ void(__cdecl* quit)();
+ HWND hwndParent;
+ HINSTANCE hDllInstance;
+} winampGeneralPurposePlugin;
+
+// return values from the init(..) which determines if Winamp will continue loading
+// and handling the plugin or if it will disregard the load attempt. If GEN_INIT_FAILURE
+// is returned then the plugin will be listed as [NOT LOADED] on the plug-in prefs page.
+#define GEN_INIT_SUCCESS 0
+#define GEN_INIT_FAILURE 1
+
+#define GPPHDR_VER 0x10
+
+// added 5.64+
+#define GPPHDR_VER_U 0x11
+// specify GPPHDR_VER_U if you want to provide a unicode (wchar_t*) description and only work on 5.64+
+// specify GPPHDR_VER to use the original (char*) description as before
+// note: we are using the fact that sizeof(char*) == sizeof(wchar_t*) to be able to allow this
+// so when using GPPHDR_VER_U you will need to cast description to (wchar_t*) to set
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ typedef winampGeneralPurposePlugin* (__cdecl* winampGeneralPurposePluginGetter)();
+#ifdef __cplusplus
+}
+#endif
+
+// These are the return values to be used with the uninstall plugin export function:
+// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
+// which determines if Winamp can uninstall the plugin immediately or on winamp restart.
+// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
+//
+#define GEN_PLUGIN_UNINSTALL_NOW 0x1
+#define GEN_PLUGIN_UNINSTALL_REBOOT 0x0
+//
+// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
+// that it is down to you to ensure that if uninstall now is returned that it will not
+// cause a crash i.e. don't use if you've been subclassing the main window.
+//
+// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
+//
+// The following is a psuedo example of using winampUninstallPlugin(..) which shows its usage:
+//
+//
+// // use this as a control on saving settings as quit(..) will be called afterwards
+// int no_uninstall = 1;
+// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param){
+// // prompt to remove our settings with default as no (just incase)
+// if(MessageBox(hwndDlg,"Do you also want to remove the saved settings for this plugin?",
+// plugin.description,MB_YESNO|MB_DEFBUTTON2) == IDYES)
+// {
+// // PLUGIN_NAME is the name of the section you save settings into
+// // and this call will make the OS remove the setion passed
+// WritePrivateProfileString(PLUGIN_NAME,0,0,ini_file);
+// no_uninstall = 0;
+// }
+// // as we're doing too much in subclasses, etc we cannot allow for on-the-fly removal so need to do a normal reboot
+// return GEN_PLUGIN_UNINSTALL_REBOOT;
+// }
+//
+
+// For a general purpose plugin to be correctly detected by Winamp you need to ensure that
+// the exported winampGetGeneralPurposePlugin(..) is exported as an undecorated function
+// e.g.
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+// __declspec(dllexport) winampGeneralPurposePlugin * __cdecl winampGetGeneralPurposePlugin(){ return &plugin; }
+// #ifdef __cplusplus
+// }
+// #endif
+//
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/GammaFilter.cpp b/Src/Winamp/GammaFilter.cpp
new file mode 100644
index 00000000..66079a3a
--- /dev/null
+++ b/Src/Winamp/GammaFilter.cpp
@@ -0,0 +1,226 @@
+#include "GammaFilter.h"
+#include "api.h"
+
+int GammaFilter::filterBitmap(uint8_t *bits, int w, int h, int bpp, const wchar_t *element_id, const wchar_t *forcegroup)
+{
+ int r = 0, g = 0, b = 0;
+ int gray = 0;
+ int boost = 0;
+
+ const wchar_t *gammagroup;
+
+ if (forcegroup && *forcegroup)
+ gammagroup = forcegroup;
+ else
+ gammagroup = WASABI_API_PALETTE->getGammaGroupFromId(element_id);
+
+ WASABI_API_COLORTHEMES->getGammaForGroup(gammagroup, &r, &g, &b, &gray, &boost);
+
+ if (!r && !g && !b && !gray && !boost) return 1;
+
+ if (bpp != 32) return 0;
+
+ int *p;
+ int l = w * h;
+ int c;
+
+ if (gray == 1)
+ {
+ int r, g, b;
+ p = (int *)bits;
+ while (l--)
+ {
+ r = (*p & 0xff0000) >> 16;
+ g = (*p & 0xff00) >> 8;
+ b = (*p & 0xff);
+ c = MAX(MAX(r, g), b);
+ c = (c << 16) | (c << 8) | c;
+ *p = (*p & 0xff000000) | c;
+ p++;
+ }
+ }
+
+ if (gray == 2)
+ {
+ int r, g, b;
+ p = (int *)bits;
+ while (l--)
+ {
+ r = (*p & 0xff0000) >> 16;
+ g = (*p & 0xff00) >> 8;
+ b = (*p & 0xff);
+ c = (r + g + b) / 3;
+ c = (c << 16) | (c << 8) | c;
+ *p = (*p & 0xff000000) | c;
+ p++;
+ }
+ }
+
+ if (boost)
+ {
+ l = w * h;
+ int r, g, b, a;
+ p = (int *)bits;
+ while (l--)
+ {
+ a = (*p & 0xff000000) >> 25;
+ r = ((*p & 0xff0000) >> 17) + a;
+ g = ((*p & 0xff00) >> 9) + a;
+ b = ((*p & 0xff) >> 1) + a;
+ *p = (*p & 0xff000000) | (r << 16) | (g << 8) | b;
+ p++;
+ }
+ }
+
+ int rm = 65535 + (r << 4);
+ int gm = 65535 + (g << 4);
+ int bm = 65535 + (b << 4);
+
+ l = w * h;
+
+ p = (int *)bits;
+ while (l--)
+ {
+ r = ((((*p & 0xff0000) >> 16) * rm)) & 0xffff0000;
+ c = MAX(0, MIN(r, 0xFF0000));
+ r = ((((*p & 0xff00) >> 8) * gm) >> 8) & 0xffff00;
+ c |= MAX(0, MIN(r, 0xFF00));
+ r = (((*p & 0xff) * bm) >> 16) & 0xffff;
+ c |= MAX(0, MIN(r, 0xFF));
+ c = (c & 0xFFFFFF) | (*p & 0xFF000000);
+ *p = c;
+ p++;
+ }
+
+ return 1;
+}
+
+ARGB32 GammaFilter::filterColor(ARGB32 color, const wchar_t *element_id, const wchar_t *forcegroup)
+{
+ int r = 0, g = 0, b = 0, gray = 0, boost = 0;
+
+ const wchar_t *gammagroup;
+ if (forcegroup && *forcegroup)
+ gammagroup = forcegroup;
+ else
+ gammagroup = WASABI_API_PALETTE->getGammaGroupFromId(element_id);
+
+ WASABI_API_COLORTHEMES->getGammaForGroup(gammagroup, &r, &g, &b, &gray, &boost);
+
+ if (!r && !g && !b && !gray && !boost) return color;
+
+ ARGB32 c;
+
+ if (gray == 1)
+ {
+ int r, g, b;
+ r = (color & 0xff0000) >> 16;
+ g = (color & 0xff00) >> 8;
+ b = (color & 0xff);
+ c = MAX(MAX(r, g), b);
+ c = (c << 16) | (c << 8) | c;
+ color = (color & 0xff000000) | c;
+ }
+
+ if (gray == 2)
+ {
+ int r, g, b;
+ r = (color & 0xff0000) >> 16;
+ g = (color & 0xff00) >> 8;
+ b = (color & 0xff);
+ c = (r + g + b) / 3;
+ c = (c << 16) | (c << 8) | c;
+ color = (color & 0xff000000) | c;
+ }
+
+ if (boost)
+ {
+ int r, g, b;
+ r = ((color & 0xff0000) >> 17) + 0x80;
+ g = ((color & 0xff00) >> 9) + 0x80;
+ b = ((color & 0xff) >> 1) + 0x80;
+ color = (color & 0xff000000) | (r << 16) | (g << 8) | b;
+ }
+
+ int bm = 65536 + (r << 4);
+ int gm = 65536 + (g << 4);
+ int rm = 65536 + (b << 4);
+
+ r = ((((color & 0xff0000) >> 16) * rm)) & 0xffff0000;
+ c = MAX(0, MIN(r, 0xFF0000));
+ r = ((((color & 0xff00) >> 8) * gm) >> 8) & 0xffff00;
+ c |= MAX(0, MIN(r, 0xFF00));
+ r = (((color & 0xff) * bm) >> 16) & 0xffff;
+ c |= MAX(0, MIN(r, 0xFF));
+ c = (c & 0xFFFFFF) | (color & 0xFF000000);
+ return c;
+}
+
+#define CBCLASS GammaFilter
+START_DISPATCH;
+ CB(FILTERBITMAP, filterBitmap);
+ CB(FILTERCOLOR, filterColor);
+END_DISPATCH;
+#undef CBCLASS
+
+
+static GammaFilter gammaFilterService;
+// {B092B4BD-32E1-4c35-B4AE-90B34565D9D6}
+static const GUID gammaFilterGUID =
+{ 0xb092b4bd, 0x32e1, 0x4c35, { 0xb4, 0xae, 0x90, 0xb3, 0x45, 0x65, 0xd9, 0xd6 } };
+
+FOURCC GammaFilterFactory::GetServiceType()
+{
+ return gammaFilterService.getServiceType();
+}
+
+const char *GammaFilterFactory::GetServiceName()
+{
+ return gammaFilterService.getServiceName();
+}
+
+GUID GammaFilterFactory::GetGUID()
+{
+ return gammaFilterGUID;
+}
+
+void *GammaFilterFactory::GetInterface(int global_lock)
+{
+// if (global_lock)
+// WASABI_API_SVC->service_lock(this, (void *)ifc);
+ return &gammaFilterService;
+}
+
+int GammaFilterFactory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int GammaFilterFactory::ReleaseInterface(void *ifc)
+{
+ //WASABI_API_SVC->service_unlock(ifc);
+ return 1;
+}
+
+const char *GammaFilterFactory::GetTestString()
+{
+ return 0;
+}
+
+int GammaFilterFactory::ServiceNotify(int msg, int param1, int param2)
+{
+ return 1;
+}
+
+#define CBCLASS GammaFilterFactory
+START_DISPATCH;
+CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
+CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
+CB(WASERVICEFACTORY_GETGUID, GetGUID)
+CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
+CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
+CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
+CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
+CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/GammaFilter.h b/Src/Winamp/GammaFilter.h
new file mode 100644
index 00000000..113253a1
--- /dev/null
+++ b/Src/Winamp/GammaFilter.h
@@ -0,0 +1,30 @@
+#pragma once
+#include <api/service/svcs/svc_skinfilter.h>
+#include <api/service/waservicefactory.h>
+class GammaFilter : public svc_skinFilter
+{
+public:
+ int filterBitmap(uint8_t *bits, int w, int h, int bpp, const wchar_t *element_id, const wchar_t *forcegroup=NULL);
+ ARGB32 filterColor(ARGB32 color, const wchar_t *element_id, const wchar_t *forcegroup=NULL);
+ static const char *getServiceName() { return "Gamma skin filter"; }
+protected:
+ RECVS_DISPATCH;
+};
+
+class GammaFilterFactory : public waServiceFactory
+{
+public:
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+ void *GetInterface(int global_lock);
+ int SupportNonLockingInterface();
+ int ReleaseInterface(void *ifc);
+ const char *GetTestString();
+ int ServiceNotify(int msg, int param1, int param2);
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
diff --git a/Src/Winamp/GammaManagerAPI.cpp b/Src/Winamp/GammaManagerAPI.cpp
new file mode 100644
index 00000000..7c873115
--- /dev/null
+++ b/Src/Winamp/GammaManagerAPI.cpp
@@ -0,0 +1,361 @@
+#include "GammaManagerAPI.h"
+#include "api.h"
+#include <api/syscb/callbacks/skincb.h>
+
+GammaManagerAPI::GammaManagerAPI()
+{
+ curSetSel = NULL;
+ inTransaction=0;
+}
+
+void GammaManagerAPI::StartTransaction()
+{
+ inTransaction++;
+}
+
+ void GammaManagerAPI::EndTransaction()
+ {
+ inTransaction--;
+ if (inTransaction == 0)
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED);
+ }
+
+size_t GammaManagerAPI::getNumGammaSets()
+{
+ return gammasets.size();
+}
+
+const wchar_t *GammaManagerAPI::enumGammaSet(size_t n)
+{
+ return gammasets[n]->name;
+}
+
+int GammaManagerAPI::getNumGammaGroups(const wchar_t *gammaset)
+{
+ if (gammaset == NULL || !*gammaset) return 0;
+ for (size_t i = 0;i != gammasets.size();i++)
+ {
+ if (IsKeyword(gammasets[i]->name, gammaset))
+ return (int)gammasets[i]->gammagroups.size();
+
+ }
+ return -1;
+}
+
+const wchar_t *GammaManagerAPI::enumGammaGroup(const wchar_t *gammaset, int n)
+{
+ if (gammaset == NULL || !*gammaset) return 0;
+ for (size_t i = 0;i != gammasets.size();i++)
+ {
+ if (IsKeyword(gammaset, gammasets[i]->name))
+ {
+ if (n < 0 || n >= (int)gammasets[i]->gammagroups.size())
+ {
+ return gammasets[i]->generalgroup.getName();
+ }
+ const wchar_t * ret = gammasets[i]->gammagroups[n]->getName();
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+ColorThemeGroup *GammaManagerAPI::enumColorThemeGroup(int colorset, int colorgroup)
+{
+ GammaSet *set = gammasets[colorset];
+ if (set != NULL)
+ {
+ if (colorgroup < 0 || colorgroup >= (int)set->gammagroups.size())
+ {
+ return &set->generalgroup;
+ }
+ ColorThemeGroup *grp = set->gammagroups[colorgroup];
+ return grp;
+ }
+ return NULL;
+}
+
+ColorThemeGroup *GammaManagerAPI::getColorThemeGroup(const wchar_t *colorset, const wchar_t *colorgroup)
+{
+ for (size_t i = 0;i < gammasets.size();i++)
+ {
+ GammaSet *s = gammasets[i];
+ if (IsKeyword(s->name, colorset))
+ {
+ if (IsKeyword(s->generalgroup.getName(), colorgroup))
+ {
+ ColorThemeGroupI *g = &s->generalgroup;
+ return g;
+ }
+ for (size_t j = 0;j < s->gammagroups.size();j++)
+ {
+ ColorThemeGroupI *g = s->gammagroups[j];
+ if (IsKeyword(g->getName(), colorgroup))
+ {
+ return g;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+void GammaManagerAPI::deleteAllGammaSets()
+{
+ //gammasets.deleteAll();
+ for (auto obj : gammasets)
+ {
+ delete obj;
+ }
+ gammasets.clear();
+
+ curSetSel = NULL;
+}
+
+void GammaManagerAPI::deleteGammaSet(const wchar_t *set)
+{
+ for (size_t i = 0;i < gammasets.size();i++)
+ {
+ if (IsKeyword(gammasets[i]->name, set))
+ {
+ GammaSet *s = gammasets[i];
+ delete s;
+ gammasets.erase(gammasets.begin() + i);
+ i--;
+ }
+ }
+ if (!inTransaction)
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED);
+}
+
+void GammaManagerAPI::renameGammaSet( const wchar_t *set, const wchar_t *newname )
+{
+ for ( GammaSet *l_gammaset : gammasets )
+ {
+ if ( IsKeyword( l_gammaset->name, set ) )
+ {
+ l_gammaset->SetName( newname );
+ if ( !inTransaction )
+ WASABI_API_SYSCB->syscb_issueCallback( SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED );
+
+ return;
+ }
+ }
+}
+
+size_t GammaManagerAPI::newGammaSet(const wchar_t *set)
+{
+ for (size_t i = 0;i != gammasets.size();i++)
+ {
+ if (IsKeyword(gammasets[i]->name, set))
+ return i;
+ }
+
+ GammaSet *curset = new GammaSet(set);/*
+ for (size_t i = 0;i < gammasets.size();i++)
+ {
+ for (size_t j = 0;j < gammasets[i]->gammagroups.size();j++)
+ {
+ ColorThemeGroup * g = gammasets[i]->gammagroups[j];
+ if (curset->haveGroup(g->getName()))
+ continue;
+ curset->gammagroups.push_back(new ColorThemeGroupI(g->getName(), 0, 0, 0, 0, 0));
+ }
+ }*/
+ size_t index = gammasets.size();
+ gammasets.push_back(curset); //Martin> better add set after the loop than before
+ if (!inTransaction)
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED);
+ return index;
+}
+
+void GammaManagerAPI::updateGammaSet(const wchar_t *set)
+{
+ for (size_t i = 0;i < gammasets.size();i++)
+ {
+ GammaSet *s = gammasets[i];
+ if (IsKeyword(s->name, set))
+ {
+ for (size_t i = 0;i < gammasets.size();i++)
+ {
+ for (size_t j = 0;j < gammasets[i]->gammagroups.size();j++)
+ {
+ ColorThemeGroup * g = gammasets[i]->gammagroups[j];
+ if (s->haveGroup(g->getName())) continue;
+ s->gammagroups.push_back(new ColorThemeGroupI(g->getName(), 0, 0, 0, 0, 0));
+ }
+ }
+ }
+ }
+}
+
+void GammaManagerAPI::setGammaSet(const wchar_t *set)
+{
+ size_t i;
+ for (i = 0;i != gammasets.size();i++)
+ {
+ if (IsKeyword(gammasets[i]->name, set))
+ {
+ setGammaSetInternal(gammasets[i]);
+ return ;
+ }
+ }
+
+ if (i) // i will still be 0 if getNumItems() was 0
+ setGammaSetInternal(gammasets[0]);
+}
+
+void GammaManagerAPI::setGammaSetInternal(GammaSet *set)
+{
+ //if (curSetSel == set) return;
+ curSetSel = set;
+
+ //PORT
+#ifdef WIN32
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+#endif
+#ifdef LINUX
+ XDefineCursor( Linux::getDisplay(), WASABI_API_WND->main_getRootWnd()->gethWnd(),
+ XCreateFontCursor( Linux::getDisplay(), XC_watch ) );
+#endif
+
+ if (WASABI_API_SKIN)
+ WASABI_API_SKIN->reapplySkinFilters();
+ //PORT
+#ifdef WIN32
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+#endif
+#ifdef LINUX
+ XUndefineCursor( Linux::getDisplay(), WASABI_API_WND->main_getRootWnd()->gethWnd() );
+#endif
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMECHANGED);
+}
+
+int GammaManagerAPI::getGammaForGroup(const wchar_t *group, int *r, int *g, int *b, int *gray, int *boost)
+{
+ if (curSetSel)
+ {
+ size_t l = curSetSel->gammagroups.size();
+ for (size_t i = 0;i < l;i++)
+ {
+ if (group && IsKeyword(group, curSetSel->gammagroups[i]->getName()))
+ {
+ *r = min(4095, max( -4095, curSetSel->gammagroups[i]->getRed() + curSetSel->generalgroup.getRed()));
+ *g = min(4095, max( -4095, curSetSel->gammagroups[i]->getGreen() + curSetSel->generalgroup.getGreen()));
+ *b = min(4095, max( -4095, curSetSel->gammagroups[i]->getBlue() + curSetSel->generalgroup.getBlue()));
+ *gray = curSetSel->gammagroups[i]->getGray() | curSetSel->generalgroup.getGray();
+ *boost = curSetSel->gammagroups[i]->getBoost() || curSetSel->generalgroup.getBoost();
+ return 1;
+ }
+ }
+ *r = min(4095, max( -4095, curSetSel->generalgroup.getRed()));
+ *g = min(4095, max( -4095, curSetSel->generalgroup.getGreen()));
+ *b = min(4095, max( -4095, curSetSel->generalgroup.getBlue()));
+ *gray = curSetSel->generalgroup.getGray();
+ *boost = curSetSel->generalgroup.getBoost();
+ return 1;
+ }
+ return 0;
+}
+
+void GammaManagerAPI::resetGammaSet( const wchar_t *set )
+{
+ for ( GammaSet *l_gammaset : gammasets )
+ {
+ if ( IsKeyword( l_gammaset->name, set ) )
+ {
+ //gammasets[i]->gammagroups.deleteAll();
+ for ( ColorThemeGroupI *obj : l_gammaset->gammagroups )
+ delete obj;
+
+ l_gammaset->gammagroups.clear();
+
+ break;
+ }
+ }
+}
+
+void GammaManagerAPI::addGammaGroup( const wchar_t *set, ColorThemeGroup *group )
+{
+ for ( GammaSet *l_gammaset : gammasets )
+ {
+ if ( IsKeyword( l_gammaset->name, set ) )
+ {
+ for ( size_t j = 0; j < l_gammaset->gammagroups.size(); j++ )
+ {
+ ColorThemeGroupI *g = l_gammaset->gammagroups[ j ];
+ if ( IsKeyword( g->getName(), group->getName() ) )
+ {
+ l_gammaset->gammagroups[ j ] = new ColorThemeGroupI( *group );
+ delete g;
+
+ return;
+ }
+ }
+
+ l_gammaset->gammagroups.push_back( new ColorThemeGroupI( *group ) );
+ break;
+ }
+ }
+}
+
+void GammaManagerAPI::addGammaGroup2(size_t i, ColorThemeGroup *group)
+{
+ for (size_t j = 0;j < gammasets[i]->gammagroups.size();j++)
+ {
+ ColorThemeGroupI * g = gammasets[i]->gammagroups[j];
+ if (IsKeyword(g->getName(), group->getName()))
+ {
+ gammasets[i]->gammagroups[j] = new ColorThemeGroupI(*group);
+ delete g;
+ return;
+ }
+ }
+ gammasets[i]->gammagroups.push_back(new ColorThemeGroupI(*group));
+}
+
+const wchar_t *GammaManagerAPI::getGammaSet()
+{
+ return curSetSel ? curSetSel->name : NULL;
+}
+
+#define CBCLASS ColorThemeGroupI
+START_DISPATCH;
+CB(COLORTHEMEGROUPGETNAME, getName);
+CB(COLORTHEMEGROUPGETRED, getRed);
+CB(COLORTHEMEGROUPGETGREEN, getGreen);
+CB(COLORTHEMEGROUPGETBLUE, getBlue);
+CB(COLORTHEMEGROUPGETGRAY, getGray);
+CB(COLORTHEMEGROUPGETBOOST, getBoost);
+VCB(COLORTHEMEGROUPSETNAME, setName);
+VCB(COLORTHEMEGROUPSETRED, setRed);
+VCB(COLORTHEMEGROUPSETGREEN, setGreen);
+VCB(COLORTHEMEGROUPSETBLUE, setBlue);
+VCB(COLORTHEMEGROUPSETGRAY, setGray);
+VCB(COLORTHEMEGROUPSETBOOST, setBoost);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CBCLASS GammaManagerAPI
+START_DISPATCH;
+CB(API_COLORTHEMES_GETNUMGAMMASETS, getNumGammaSets);
+CB(API_COLORTHEMES_ENUMGAMMASET, enumGammaSet);
+VCB(API_COLORTHEMES_DELETEGAMMASET, deleteGammaSet);
+VCB(API_COLORTHEMES_DELETEALLGAMMASETS, deleteAllGammaSets);
+VCB(API_COLORTHEMES_RESETGAMMASET, resetGammaSet);
+VCB(API_COLORTHEMES_RENAMEGAMMASET, renameGammaSet);
+CB(API_COLORTHEMES_NEWGAMMASET, newGammaSet);
+VCB(API_COLORTHEMES_UPDATEGAMMASET, updateGammaSet);
+CB(API_COLORTHEMES_GETNUMGAMMAGROUPS, getNumGammaGroups);
+CB(API_COLORTHEMES_ENUMGAMMAGROUP, enumGammaGroup);
+CB(API_COLORTHEMES_ENUMCOLORTHEMEGROUP, enumColorThemeGroup);
+CB(API_COLORTHEMES_GETCOLORTHEMEGROUP, getColorThemeGroup);
+CB(API_COLORTHEMES_GETGAMMAFORGROUP, getGammaForGroup);
+VCB(API_COLORTHEMES_ADDGAMMAGROUP, addGammaGroup);
+VCB(API_COLORTHEMES_ADDGAMMAGROUP2, addGammaGroup2);
+CB(API_COLORTHEMES_GETGAMMASET, getGammaSet);
+VCB(API_COLORTHEMES_SETGAMMASET, setGammaSet);
+VCB(API_COLORTHEMES_STARTTRANSACTION, StartTransaction);
+VCB(API_COLORTHEMES_ENDTRANSACTION, EndTransaction);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/GammaManagerAPI.h b/Src/Winamp/GammaManagerAPI.h
new file mode 100644
index 00000000..b60b8d7a
--- /dev/null
+++ b/Src/Winamp/GammaManagerAPI.h
@@ -0,0 +1,145 @@
+#pragma once
+#include <api/skin/colorthemes.h>
+#include <api/service/svcs/svc_skinfilter.h>
+#include <vector>
+#include <api/skin/api_colorthemes.h>
+
+class ColorThemeGroupI : public ColorThemeGroup
+{
+public:
+ ColorThemeGroupI(const wchar_t *pname, int pred, int pgreen, int pblue, int pgray, int pboost)
+ : name(0), red(pred), green(pgreen), blue(pblue), make_grayscale(pgray), boost_levels(pboost)
+ {
+ name = _wcsdup(pname);
+ }
+~ColorThemeGroupI()
+{
+ free(name);
+}
+ ColorThemeGroupI(ColorThemeGroup &copy_group)
+ {
+ name = _wcsdup(copy_group.getName());
+ red = copy_group.getRed();
+ green = copy_group.getGreen();
+ blue = copy_group.getBlue();
+ make_grayscale = copy_group.getGray();
+ boost_levels = copy_group.getBoost();
+ }
+ const wchar_t *getName() { return name; }
+ int getRed() { return red; }
+ int getGreen() { return green; }
+ int getBlue() { return blue; }
+ int getGray() { return make_grayscale; }
+ int getBoost() { return boost_levels; }
+ void setName(const wchar_t *pname) { free(name); name = _wcsdup(pname); }
+ void setRed(int r) { red = r; }
+ void setGreen(int g) { green = g; }
+ void setBlue(int b) { blue = b; }
+ void setGray(int g) { make_grayscale = g; }
+ void setBoost(int b) { boost_levels = b; }
+
+ protected:
+ RECVS_DISPATCH;
+
+ wchar_t *name;
+ int red;
+ int green;
+ int blue;
+ int make_grayscale;
+ int boost_levels;
+};
+
+static bool IsKeyword(const wchar_t *a, const wchar_t *b)
+{
+ return (CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, a, -1, b, -1) == CSTR_EQUAL);
+
+}
+class GammaSet
+{
+ public:
+ GammaSet( const wchar_t *pname ) : name( 0 ), generalgroup( L"General", 0, 0, 0, 0, 0 )
+ {
+ name = _wcsdup( pname );
+ }
+
+ ~GammaSet()
+ {
+ //gammagroups.deleteAll();
+ for ( ColorThemeGroupI *obj : gammagroups )
+ delete obj;
+
+ gammagroups.clear();
+
+ free( name );
+ }
+
+ int haveGroup( const wchar_t *grp )
+ {
+ if ( !grp )
+ return 0;
+
+ for ( ColorThemeGroupI *obj : gammagroups )
+ {
+ if ( IsKeyword( grp, obj->getName() ) )
+ return 1;
+ }
+
+ return 0;
+ }
+
+ void SetName( const wchar_t *newname )
+ {
+ free( name );
+ name = _wcsdup( newname );
+ }
+ wchar_t *name;
+ std::vector<ColorThemeGroupI *> gammagroups;
+ ColorThemeGroupI generalgroup;
+};
+
+
+class GammaManagerAPI : public api_colorthemes
+{
+public:
+ static const char *getServiceName() { return "Color Themes API"; }
+ static const GUID getServiceGuid() { return ColorThemesAPIGUID; }
+ GammaManagerAPI();
+
+ void StartTransaction();
+ void EndTransaction();
+
+ /* Gamma Sets */
+ size_t getNumGammaSets();
+ const wchar_t *enumGammaSet(size_t n);
+ void deleteGammaSet(const wchar_t *set);
+ void deleteAllGammaSets();
+ void resetGammaSet(const wchar_t *set);
+ void renameGammaSet(const wchar_t *set, const wchar_t *newname);
+ size_t newGammaSet(const wchar_t *set); // returns index of your new gamma group
+ void updateGammaSet(const wchar_t *set);
+
+
+ /* Gamma Groups */
+ int getNumGammaGroups(const wchar_t *gammaset);
+ const wchar_t *enumGammaGroup(const wchar_t *gammaset, int n);
+ ColorThemeGroup *enumColorThemeGroup(int colorset, int colorgroup);
+ ColorThemeGroup *getColorThemeGroup(const wchar_t *colorset, const wchar_t *colorgroup);
+ int getGammaForGroup(const wchar_t *group, int *r, int *g, int *b, int *gray, int *boost);
+ void addGammaGroup(const wchar_t *set, ColorThemeGroup *group);
+ void addGammaGroup2(size_t gammaSetIndex, ColorThemeGroup *group);
+
+ /* Active Gamma Set */
+ const wchar_t *getGammaSet();
+ void setGammaSet(const wchar_t *set);
+
+ protected:
+ RECVS_DISPATCH;
+
+private:
+ void setGammaSetInternal(GammaSet *set);
+
+ std::vector<GammaSet*> gammasets;
+ GammaSet *curSetSel; // current color theme
+ size_t inTransaction;
+};
+
diff --git a/Src/Winamp/HTML.cpp b/Src/Winamp/HTML.cpp
new file mode 100644
index 00000000..45b99845
--- /dev/null
+++ b/Src/Winamp/HTML.cpp
@@ -0,0 +1,139 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description: HTML generation from playlist
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include <stdio.h>
+#include "../nu/AutoChar.h"
+#include "resource.h"
+
+void doHtmlPlaylist(void)
+{
+ FILE *fp = 0;
+ wchar_t filename[MAX_PATH] = {0}, tp[MAX_PATH] = {0};
+ if (!GetTempPathW(MAX_PATH,tp)) StringCchCopyW(tp, MAX_PATH, L".");
+ if (GetTempFileNameW(tp, L"WHT", 0, filename)){
+ DeleteFileW(filename);
+ StringCchCatW(filename, MAX_PATH, L".html");
+ }
+ else StringCchCopyW(filename, MAX_PATH, L"wahtml_tmp.html");
+
+ fp = _wfopen(filename, L"wt");
+ if (!fp)
+ {
+ LPMessageBox(hPLWindow, IDS_HTML_ERROR_WRITE, IDS_ERROR, MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ fprintf(fp, "<!DOCTYPE html>\n"
+ "<html lang=\"en\"><head>\n"
+ "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
+ "<meta name=\"generator\" content=\"Winamp 5.9\">\n"
+ "<style>body{background:#000040;font-family:arial,helvetica;font-size:9pt;font-weight:normal;}"
+ ".name{margin-top:-1em;margin-left:15px;font-size:40pt;color:#004080;text-align:left;font-weight:900;}"
+ ".name-small{margin-top:-3em;margin-left:140px;font-size:22pt;color:#E1E1E1;text-align:left;}"
+ "table{font-size:9pt;color:#004080;text-align:left;border-width:0px;padding:0px;letter-spacing:normal;}"
+ "hr{border:0;background-color:#FFBF00;height:1px;}"
+ "ol{color:#FFFFFF;font-size:11pt;}"
+ "table{margin-left:15px;color:#409FFF;border-width:0px;}"
+ ".val{color:#FFBF00;}"
+ ".header{color:#FFBF00;font-size:14pt;}"
+ "</style>\n"
+ "<title>Winamp Generated PlayList</title></head>\n"
+ "<body>"
+ "<div>"
+ "<div class=\"name\"><p>WINAMP</p></div>"
+ "<div class=\"name-small\"><p>playlist</p></div>"
+ "</div>"
+ "<hr><div>\n"
+ "<table><tr><td>\n");
+
+ int x, t = PlayList_getlength(), t_in_pl = 0, n_un = 0;
+ for (x = 0; x < t; x ++)
+ {
+ int a = PlayList_getsonglength(x);
+ if (a >= 0) t_in_pl += a;
+ else n_un++;
+ }
+ if (t != n_un)
+ {
+ int old_t_in_pl=t_in_pl;
+ t_in_pl += (n_un * t_in_pl) / (t - n_un);
+
+ fprintf(fp, "<span class=\"val\">%d</span> track%s in playlist, ", t, t == 1 ? "" : "s");
+ fprintf(fp, "average track length: <span class=\"val\">%d:%02d",
+ old_t_in_pl / (t-n_un) / 60, (old_t_in_pl / (t - n_un)) % 60);
+
+ fprintf(fp, "</span><br>%slaylist length: ",
+ n_un ? "Estimated p" : "P");
+
+ if (t_in_pl / 3600)
+ {
+ fprintf(fp, "<span class=\"val\">%d</span> hour%s ",
+ t_in_pl / 3600, t_in_pl / 3600 == 1 ? "" : "s");
+ t_in_pl %= 3600;
+ }
+
+ if (t_in_pl / 60)
+ {
+ fprintf(fp, "<span class=\"val\">%d</span> minute%s ",
+ t_in_pl / 60, t_in_pl / 60 == 1 ? "" : "s");
+ t_in_pl %= 60;
+ }
+ fprintf(fp, "<span class=\"val\">%d</span> second%s %s",
+ t_in_pl, t_in_pl == 1 ? "" : "s", n_un ? "<br>(" : "");
+ if (n_un) fprintf(fp, "<span class=\"val\">%d</span> track%s of unknown length)",
+ n_un, n_un == 1 ? "" : "s");
+
+ fprintf(fp,
+ "<br>Right-click <a href=\"file://%s\">here</a> to save this HTML file."
+ "</td></tr>",
+ (char *)AutoChar(filename, CP_UTF8));
+ }
+ else
+ {
+ fprintf(fp, "There are no tracks in the current playlist.<br>");
+ }
+
+ fprintf(fp, "</table></div>\n");
+
+ if (t > 0)
+ {
+ fprintf(fp,
+ "<blockquote><span class=\"header\">Playlist files:</span><ol>\n");
+
+ for (x = 0; x < t; x++)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0}, ft[FILETITLE_SIZE] = {0};
+ int l;
+ PlayList_getitem2W(x, fn, ft);
+ AutoChar narrowFt(ft, CP_UTF8);
+ char *p = narrowFt;
+ l = PlayList_getsonglength(x);
+ fprintf(fp, "<li>");
+ while (p && *p)
+ {
+ if (*p == '&') fprintf(fp, "&amp;");
+ else if (*p == '<') fprintf(fp, "&lt;");
+ else if (*p == '>') fprintf(fp, "&gt;");
+ else if (*p == '\'') fprintf(fp, "&#39;");
+ else if (*p == '"') fprintf(fp, "&quot;");
+ else fputc(*p, fp);
+ p++;
+ }
+
+ if(l > 0) fprintf(fp, " (%d:%02d) \n", l / 60, l % 60);
+ else fprintf(fp, " \n");
+ }
+
+ fprintf(fp, "</ol></blockquote>\n");
+ }
+ fprintf(fp, "<hr><br></body></html>");
+ fclose(fp);
+
+ myOpenURL(hPLWindow, filename);
+} \ No newline at end of file
diff --git a/Src/Winamp/HTTPRetrieveFile.cpp b/Src/Winamp/HTTPRetrieveFile.cpp
new file mode 100644
index 00000000..7c655a80
--- /dev/null
+++ b/Src/Winamp/HTTPRetrieveFile.cpp
@@ -0,0 +1,305 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+#include "Main.h"
+#include "api.h"
+#include "..\Components\wac_network\wac_network_http_receiver_api.h"
+
+#include "api/service/waServiceFactory.h"
+
+
+void GetMIMEType(const char *url, char *mimeType, int mimeTypeCch)
+{
+ api_httpreceiver *http = 0;
+ waServiceFactory *sf = 0;
+ if (WASABI_API_SVC)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
+ if (sf)
+ http = (api_httpreceiver *)sf->getInterface();
+ }
+
+ if (!http)
+ return ;
+
+ int ret;
+ http->open(API_DNS_AUTODNS, 2048, config_proxy);
+ http->connect(url, 0, "HEAD");
+
+ do
+ {
+ Sleep(10);
+ ret = http->run();
+ if (ret == -1) // connection failed
+ break;
+
+ // ---- check our reply code ----
+ int replycode = http->getreplycode();
+ switch (replycode)
+ {
+ case 0:
+ case 100:
+ break;
+ case 200:
+ {
+ const char *contentType = http->getheader("Content-Type");
+ if (contentType)
+ lstrcpynA(mimeType, contentType, mimeTypeCch);
+ else
+ mimeType[0] = 0;
+
+ sf->releaseInterface(http);
+ return ;
+ }
+ break;
+ default:
+ sf->releaseInterface(http);
+ return ;
+ }
+ }
+ while (ret == HTTPRECEIVER_RUN_OK);
+
+ sf->releaseInterface(http);
+}
+
+#if 0
+#define WM_HRF_READINGHTTP WM_USER
+#define WM_HRF_DOWNLOADING (WM_USER+1)
+struct RFData
+{
+public:
+ char *url, *file;
+ HWND hwnd;
+};
+
+bool killswitch;
+static DWORD WINAPI rf_ThreadProc(void *p)
+{
+ RFData *rfData = (RFData *)p;
+ char *url = rfData->url, *file = rfData->file;
+ waServiceFactory *sf = 0;
+ api_httpreceiver *http = 0;
+ if (WASABI_API_SVC)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
+ if (sf)
+ http = (api_httpreceiver *)sf->getInterface();
+ }
+
+ if (!http)
+ return 1;
+
+ HANDLE hFile = CreateFile(file, GENERIC_WRITE, 0,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ sf->releaseInterface(http);
+ return 1;
+ }
+
+ http->Open(API_DNS_AUTODNS, 16384);
+ http->AddHeader("User-Agent: Winamp/" APP_VERSION);
+ http->Connect(url);
+ int ret;
+ do
+ {
+ Sleep(50);
+ http->Run();
+ ret = http->GetStatus();
+ if (ret == HTTPRECEIVER_STATUS_ERROR)
+ killswitch = true;
+
+ if (killswitch)
+ break;
+ }
+ while (ret == HTTPRECEIVER_STATUS_CONNECTING);
+
+ if (ret == HTTPRECEIVER_STATUS_READING_HEADERS || ret == HTTPRECEIVER_STATUS_READING_CONTENT)
+ {
+ PostMessageW(rfData->hwnd, WM_HRF_READINGHTTP, 0, 0);
+ int replycode = http->GetReplyCode();
+ switch (replycode)
+ {
+ case 0: case 100: // shouldn't really get here
+ break;
+ case 200:
+ break;
+ default:
+ killswitch = true;
+ break;
+ }
+ }
+ bool error = false;
+ char block[16384] = {0};
+ size_t downloadSize;
+ size_t currentSize = 0, totalSize = 0;
+
+ do
+ {
+ if (killswitch)
+ {
+ error = true;
+ break;
+ }
+ // ---- Pause a bit and then run the http downloader ----
+ Sleep(50);
+ ret = http->Run();
+
+ if (ret == -1) // connection failed
+ {
+ error = true;
+ break;
+ }
+
+ // ---- download ----
+ downloadSize = http->GetBytesAvailable();
+ if (downloadSize)
+ {
+ totalSize = http->GetContentLength();
+
+ downloadSize = http->GetBytes(block, downloadSize);
+ currentSize += downloadSize;
+ PostMessageW(rfData->hwnd, WM_HRF_DOWNLOADING, currentSize, totalSize);
+
+ // ---- write to disk ----
+ if (downloadSize) // WriteFile doesn't like 0 byte writes
+ {
+ DWORD numWritten = 0;
+ WriteFile(hFile, block, downloadSize, &numWritten, FALSE);
+ if (numWritten != downloadSize) // make sure that the block was actually written
+ {
+ error = true;
+ break; // failed writing
+ }
+ }
+ }
+ }
+ while (ret != 1 || downloadSize); // http may be closed, but make sure we get all the data.
+
+ CloseHandle(hFile);
+ if (error)
+ DeleteFile(file);
+ sf->releaseInterface(http);
+ return 0;
+
+}
+
+static LRESULT CALLBACK rf_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemText(hwndDlg, IDC_STATUS, getString(IDS_HTTP_INIT,NULL,0));
+ return FALSE;
+ case WM_HRF_READINGHTTP:
+ SetDlgItemText(hwndDlg, IDC_STATUS, getString(IDS_HTTP_READ_REQUEST,NULL,0));
+ return TRUE;
+ case WM_HRF_DOWNLOADING:
+ {
+ char temp[128] = {0};
+ if (!lParam)
+ StringCchPrintf(temp, 128, getString(IDS_HTTP_RET_FILE,NULL,0), wParam);
+ else
+ StringCchPrintf(temp, 128, getString(IDS_HTTP_RET_FILE_PERCENT,NULL,0), (100*wParam) / lParam, wParam, lParam);
+ SetDlgItemText(hwndDlg, IDC_STATUS, temp);
+ }
+ return TRUE;
+ case WM_DESTROY:
+ if (GetParent(hwndDlg) == hMainWindow)
+ {
+ if (hMainWindow) EnableWindow(hMainWindow, 1);
+ if (hPLWindow) EnableWindow(hPLWindow, 1);
+ if (hEQWindow) EnableWindow(hEQWindow, 1);
+ //if (hMBWindow) EnableWindow(hMBWindow,1);
+ }
+ else
+ EnableWindow(GetParent(hwndDlg), 1);
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+int httpRetrieveFile(HWND hwnd, char *url, char *file, char *dlgtitle)
+{
+ killswitch = false;
+ RECT r;
+ HANDLE hThread = 0;
+ if (!hwnd) hwnd = hMainWindow;
+
+ if (hwnd == hMainWindow && g_dialog_box_parent) hwnd = g_dialog_box_parent;
+
+ GetWindowRect(hwnd, &r);
+ HWND dlgWnd = LPCreateDialog(IDD_HTTPGET, hwnd, rf_DlgProc);
+ SetWindowText(dlgWnd, dlgtitle);
+ SetDlgItemText(dlgWnd, IDC_URL, url);
+
+ RFData data = {url, file, dlgWnd};
+ DWORD id;
+ hThread = CreateThread(NULL, 0, rf_ThreadProc, (void *) & data, CREATE_SUSPENDED, &id);
+ if (NULL)
+ return 1;
+
+ ResumeThread(hThread);
+ if (r.bottom > GetSystemMetrics(SM_CXSCREEN) / 2 && r.bottom - r.top < 100)
+ {
+ RECT r2;
+ GetWindowRect(dlgWnd, &r2);
+ r.top = r.bottom - (r2.bottom - r2.top);
+ }
+ SetWindowPos(dlgWnd, NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+ if (GetForegroundWindow() == hwnd)
+ ShowWindow(dlgWnd, SW_SHOW);
+ else
+ ShowWindow(dlgWnd, SW_SHOWNA);
+
+ if (hwnd == hMainWindow)
+ {
+ if (hMainWindow) EnableWindow(hMainWindow, 0);
+ if (hPLWindow) EnableWindow(hPLWindow, 0);
+ if (hEQWindow) EnableWindow(hEQWindow, 0);
+ //if (hMBWindow) EnableWindow(hMBWindow,0);
+ }
+ else
+ EnableWindow(hwnd, 0);
+
+ while (1)
+ {
+ MSG msg;
+ if (!IsWindow(dlgWnd))
+ {
+ killswitch = true;
+ break;
+ }
+ if (WaitForSingleObject(hThread, 0) == WAIT_OBJECT_0)
+ {
+ DestroyWindow(dlgWnd);
+ break;
+ }
+ GetMessage(&msg, NULL, 0, 0);
+ DispatchMessage(&msg);
+ }
+
+ WaitForSingleObject(hThread, 5000);
+ DWORD exitCode;
+ if (GetExitCodeThread(hThread, &exitCode))
+ return exitCode;
+ else
+ {
+ // CUT: TerminateThread(hThread, 0);
+ return 1;
+ }
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Http.cpp b/Src/Winamp/Http.cpp
new file mode 100644
index 00000000..517ad54f
--- /dev/null
+++ b/Src/Winamp/Http.cpp
@@ -0,0 +1,795 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include <cstdint>
+#if 1
+#include <sys/types.h>
+#include <winsock.h>
+#include "../nu/threadname.h"
+#include "Wa_dlg.h"
+#include "../nu/AutoWide.h"
+
+static void createDirForFileW(wchar_t *str)
+{
+ wchar_t *p = str;
+ if ((p[0] ==L'\\' || p[0] ==L'/') && (p[1] ==L'\\' || p[1] ==L'/'))
+ {
+ p += 2;
+ while (p && *p && *p !=L'\\' && *p !=L'/') p++;
+ if (!*p) return ;
+ p++;
+ while (p && *p && *p !=L'\\' && *p !=L'/') p++;
+ }
+ else
+ {
+ while (p && *p && *p !=L'\\' && *p !=L'/') p++;
+ }
+
+ while (p && *p)
+ {
+ while (p && *p !=L'\\' && *p !=L'/' && *p) p = CharNextW(p);
+ if (*p)
+ {
+ wchar_t lp = *p;
+ *p = 0;
+ CreateDirectoryW(str, NULL);
+ *p++ = lp;
+ }
+ }
+}
+
+static const wchar_t *rf_file, *rf_dlgtitle;
+static const char *rf_url;
+static int rf_in;
+static HWND rf_dlgWnd, rf_statusWnd;
+static volatile int rf_rv=-1;
+static volatile int rf_abort;
+static int g_rv;
+
+static int _rftabort(int r, char *s)
+{
+ if (s) SetWindowTextA(rf_statusWnd,s);
+ if (rf_dlgWnd) SendMessageW(rf_dlgWnd,WM_USER+1,r,0);
+ else rf_rv=r;
+ return r;
+}
+
+#define rfta(s) return _rftabort(!success,s)
+#define sets(s) SetWindowTextA(rf_statusWnd,s)
+
+typedef int (__stdcall *waP_RECV)(SOCKET s, char FAR* buf, int len, int flags);
+waP_RECV p_recv;
+
+static void encodeMimeStr(char *in, char *out)
+{
+ char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int shift = 0;
+ int accum = 0;
+
+ while (in && *in)
+ {
+ if (*in)
+ {
+ accum <<= 8;
+ shift += 8;
+ accum |= *in++;
+ }
+ while ( shift >= 6 )
+ {
+ shift -= 6;
+ *out++ = alphabet[(accum >> shift) & 0x3F];
+ }
+ }
+ if (shift == 4)
+ {
+ *out++ = alphabet[(accum & 0xF)<<2];
+ *out++='=';
+ }
+ else if (shift == 2)
+ {
+ *out++ = alphabet[(accum & 0x3)<<4];
+ *out++='=';
+ *out++='=';
+ }
+
+ *out++=0;
+}
+
+static int recv_string(SOCKET s, char *str, int maxlen)
+{
+ int p=0;
+ do
+ {
+ int t=0;
+ while (t!=1)
+ {
+ t=p_recv(s,str+p,1,0);
+ if (t != 1)
+ {
+ if (rf_abort || !t) { str[0]=0; return -1; }
+ Sleep(100);
+ }
+ if (str[p] == '\r') t=0;
+ }
+ } while (str[p] != '\n' && ++p < maxlen-1);
+ str[p--]=0;
+ while (str[p] == '\n' && p > 0)
+ {
+ str[p--]=0;
+ }
+ if (p < 0) p = 0;
+ return p;
+}
+
+static int g_in_resolve;
+
+static DWORD WINAPI rf_ThreadProc(LPVOID p666)
+{
+ char locbuf[1024]={0};
+ int redirect=0;
+ HINSTANCE hws = LoadLibraryA("wsock32.dll");
+ int total_bytes;
+ uint64_t content_length;
+ SOCKET sock;
+ char proxytmp[256]={0};
+ char *proxy;
+ char connect_host[MAX_PATH]={0};
+ unsigned short connect_port;
+ int success=0;
+
+ typedef int (__stdcall *waSELECT)(int nfds,fd_set FAR * readfds,fd_set FAR * writefds,fd_set FAR * exceptfds,const struct timeval FAR * timeout);
+ typedef int (__stdcall *waWSAGETLASTERROR)(void);
+ typedef int (__stdcall *waWSACLEANUP)(void);
+ typedef int (__stdcall *waWSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData);
+ typedef int (__stdcall *waCLOSESOCKET)(SOCKET s);
+ typedef int (__stdcall *waSEND)(SOCKET s,const char FAR *buf,int len,int flags);
+ typedef SOCKET (__stdcall *waSOCKET)(int af, int type,int protocol);
+ typedef int (__stdcall *waCONNECT)( SOCKET s, const struct sockaddr FAR *name, int namelen );
+ typedef unsigned long (__stdcall *waINET_ADDR)(const char FAR *cp );
+ typedef struct hostent FAR * (__stdcall *waGETHOSTBYNAME)(const char FAR *name);
+ typedef int (__stdcall *waIOCTLSOCKET)(SOCKET s,long cmd,u_long FAR *argp);
+ typedef u_short (__stdcall *waHTONS)(u_short hostshort);
+
+ waSELECT select;
+ waWSAGETLASTERROR WSAGetLastError;
+ waWSACLEANUP WSACleanup;
+ waWSASTARTUP WSAStartup;
+ waCLOSESOCKET closesocket;
+ waSEND send;
+ waSOCKET socket;
+ waCONNECT connect;
+ waINET_ADDR inet_addr;
+ waGETHOSTBYNAME gethostbyname;
+ waIOCTLSOCKET ioctlsocket;
+ waHTONS htons;
+
+ char buf[ 4096 ] = { 0 };
+ char errorStr[ 1024 ] = { 0 };
+ char *p;
+ char url_buf[ 1024 ] = { 0 };
+ char *url_lp = NULL;
+ char *url_host = NULL;
+ int url_port = 80;
+ char *url_url = NULL;
+ char authstr[ 1024 ] = { 0 };
+ char proxy_lp[ 1024 ] = { 0 };
+ const char *t;
+
+ SetThreadName((DWORD)-1, "HTTP Retrieve File");
+ if ( hws )
+ {
+ WSAGetLastError = (waWSAGETLASTERROR)GetProcAddress( hws, "WSAGetLastError" );
+ WSACleanup = (waWSACLEANUP)GetProcAddress( hws, "WSACleanup" );
+ WSAStartup = (waWSASTARTUP)GetProcAddress( hws, "WSAStartup" );
+ closesocket = (waCLOSESOCKET)GetProcAddress( hws, "closesocket" );
+ send = (waSEND)GetProcAddress( hws, "send" );
+ p_recv = (waP_RECV)GetProcAddress( hws, "recv" );
+ select = (waSELECT)GetProcAddress( hws, "select" );
+ connect = (waCONNECT)GetProcAddress( hws, "connect" );
+ socket = (waSOCKET)GetProcAddress( hws, "socket" );
+ inet_addr = (waINET_ADDR)GetProcAddress( hws, "inet_addr" );
+ gethostbyname = (waGETHOSTBYNAME)GetProcAddress( hws, "gethostbyname" );
+ ioctlsocket = (waIOCTLSOCKET)GetProcAddress( hws, "ioctlsocket" );
+ htons = (waHTONS)GetProcAddress( hws, "htons" );
+ }
+
+ if (!hws || !p_recv || !WSACleanup ||
+ !WSAStartup || !closesocket || !send ||
+ !connect || !socket || !inet_addr ||
+ !gethostbyname || !ioctlsocket || !htons || !select || !WSAGetLastError)
+ {
+ if (hws)
+ FreeLibrary(hws);
+
+ rfta(getString(IDS_HTTP_LOAD_ERROR,errorStr,1024));
+ }
+
+ sets(getString(IDS_HTTP_INIT_SOCKET,errorStr,1024));
+ {
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(1, 1), &wsaData))
+ {
+ FreeLibrary(hws);
+ rfta(getString(IDS_HTTP_INIT_SOCKET_ERROR,errorStr,1024));
+ }
+ }
+
+_redirect_goto:
+ total_bytes=0;
+ content_length=0;
+
+ // parse out l/p, host, port, and url from loc
+ authstr[0]=0;
+ url_lp=NULL;
+ url_host=NULL;
+ url_port=80;
+ url_url=NULL;
+
+ t= strstr(rf_url,"://");
+ if (t)
+ {
+ StringCchCopyA(url_buf,1024,t+3);
+ }
+ else
+ {
+ StringCchCopyA(url_buf,1024,rf_url);
+ }
+
+ p=url_buf;
+ while (p && *p != '/' && *p) p++;
+ if (p && *p) *p++=0;
+ url_url=p;
+
+ p=url_buf;
+ while (p && *p) p++;
+ while (p>=url_buf && *p != '@') p--;
+ if (p>=url_buf)
+ {
+ *p++=0;
+ url_host=p;
+ url_lp=url_buf;
+ if (lstrlenA(url_lp)>0)
+ {
+ StringCchCopyA(authstr,1024,"Authorization: Basic ");
+ encodeMimeStr(url_lp,authstr+lstrlenA(authstr));
+ StringCchCatA(authstr,1024,"\r\n");
+ }
+ }
+ else url_host=url_buf;
+
+ p=url_host;
+ while (p && *p != ':' && *p) p++;
+ if (p && *p)
+ {
+ *p++=0;
+ if (*p) url_port=atoi(p);
+ }
+
+ // determine if proxy server used
+ {
+ StringCchCopyA(proxytmp,256,config_proxy);
+ proxy=proxytmp;
+ while (proxy && (*proxy == ' ' || *proxy == '\t')) proxy++;
+
+ if (url_port != 80 && GetPrivateProfileIntW(L"Winamp",L"proxyonly80",0,INI_FILE))
+ proxy="";
+ }
+
+ if (*proxy)
+ {
+ p=proxy;
+ while (p && *p && *p != '@') p++;
+ if (p && *p)
+ {
+ *p++=0;
+ StringCchCopyA(proxy_lp,1024,"Proxy-Authorization: Basic ");
+ encodeMimeStr(proxy,proxy_lp+lstrlenA(proxy_lp));
+ StringCchCatA(proxy_lp,1024,"\r\n");
+ proxy=p;
+ }
+
+ lstrcpynA(connect_host,proxy,sizeof(connect_host)/sizeof(*connect_host));
+ p=connect_host;
+ while (p && *p && *p != ':') p++;
+ if (p && *p)
+ {
+ *p++=0;
+ if (*p) connect_port=(unsigned short)atoi(p);
+ else connect_port=80;
+ }
+ }
+ else
+ {
+ lstrcpynA(connect_host,url_host,sizeof(connect_host)/sizeof(*connect_host));
+ connect_port=(unsigned short)url_port;
+ }
+
+ sets(getString(IDS_HTTP_SOCKET_CREATE,errorStr,1024));
+ if (rf_abort || (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET)
+ {
+ WSACleanup();
+ FreeLibrary(hws);
+ rfta(getString(IDS_HTTP_SOCKET_ERROR,errorStr,1024));
+ }
+
+ {
+ int t;
+ struct sockaddr_in blah;
+ memset((char *)&blah,0,sizeof(blah));
+ blah.sin_family=AF_INET;
+ blah.sin_addr.s_addr=inet_addr(connect_host);
+ blah.sin_port=htons(connect_port);
+
+ if ( blah.sin_addr.s_addr == INADDR_NONE )
+ {
+ struct hostent *he;
+ g_in_resolve = 1;
+ sets( *proxy ? getString( IDS_HTTP_RESOLVE_PROXY, errorStr, 1024 ) : getString( IDS_HTTP_RESOLVE_HOST, errorStr, 1024 ) );
+ if ( ( he = gethostbyname( connect_host ) ) != NULL )
+ memcpy( (char *)&blah.sin_addr, he->h_addr, he->h_length );
+ else if ( ( blah.sin_addr.s_addr = inet_addr( connect_host ) ) == INADDR_NONE )
+ {
+ g_in_resolve = 0;
+ closesocket( sock );
+ WSACleanup();
+ FreeLibrary( hws );
+ rfta( *proxy ? getString( IDS_HTTP_RESOLVE_PROXY_ERROR, errorStr, 1024 ) : getString( IDS_HTTP_RESOLVE_HOST_ERROR, errorStr, 1024 ) );
+ }
+
+ g_in_resolve = 0;
+ }
+
+ sets(*proxy?getString(IDS_HTTP_CONNECT_PROXY,errorStr,1024):getString(IDS_HTTP_CONNECT_HOST,errorStr,1024));
+ {
+ unsigned long arg=1;
+ ioctlsocket(sock,FIONBIO,&arg);
+ }
+
+ t=connect(sock,(struct sockaddr *)&blah,16);
+ if (t == -1 && WSAGetLastError()==WSAEWOULDBLOCK)
+ {
+ int a=0;
+ while (!rf_abort && t==-1)
+ {
+ TIMEVAL to={0,250*1000};
+ fd_set f;
+ FD_ZERO(&f);
+ FD_SET(sock,&f);
+ switch (select(0,NULL,&f,NULL,&to))
+ {
+ case 1: t=0; break;
+ case 0: if (a++ > 40) rf_abort =1; break;
+ case -1: rf_abort =1; break;
+ }
+ }
+ }
+ if (rf_abort || t==-1)
+ {
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ rfta(*proxy?getString(IDS_HTTP_CONNECT_PROXY_ERROR,errorStr,1024):getString(IDS_HTTP_CONNECT_HOST_ERROR,errorStr,1024));
+ }
+ }
+
+ sets(getString(IDS_HTTP_SEND_REQUEST,errorStr,1024));
+ {
+ if ( *proxy )
+ StringCchPrintfA( buf, 4096, "GET http://%s:%d/%s", url_host, url_port, url_url );
+ else
+ StringCchPrintfA( buf, 4096, "GET /%s", url_url );
+
+ if (url_port != 80)
+ StringCchPrintfA( buf + lstrlenA( buf ), 4096 - lstrlenA( buf ), " HTTP/1.0\r\nHost: %s:%d\r\n", url_host, url_port );
+ else
+ StringCchPrintfA( buf + lstrlenA( buf ), 4096 - lstrlenA( buf ), " HTTP/1.0\r\nHost: %s\r\n", url_host );
+
+ StringCchPrintfA( buf + lstrlenA( buf ), 4096 - lstrlenA( buf ),
+ "User-Agent: Winamp/%s%s\r\n"
+ "%s%s"
+ "Accept: */*\r\n\r\n",
+ app_version,
+ ( redirect == 2 ? " (Mozilla)" : "" ),
+ proxy_lp, authstr );
+
+ //MessageBox(NULL,buf,"SENDING:",0);
+ {
+ unsigned long arg = 0;
+ ioctlsocket( sock, FIONBIO, &arg );
+ }
+
+ send(sock,buf,lstrlenA(buf),0);
+
+ {
+ unsigned long arg = 1;
+ ioctlsocket( sock, FIONBIO, &arg );
+ }
+ }
+
+ sets( getString( IDS_HTTP_READ_REQUEST, errorStr, 1024 ) );
+
+ { // get the standard HTTP 1.0 200 OK
+ char buf[1024] = {0};
+ int x = recv_string(sock,buf,sizeof(buf));
+ //MessageBox(0, buf, "RECEIVING:", 0);
+ if (x < 0 || rf_abort)
+ {
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ rfta(getString(IDS_HTTP_CONNECTION_LOST,errorStr,1024));
+ }
+
+ if (strstr(buf," 302") || strstr(buf,"301"))
+ {
+ redirect=1;
+ }
+ else
+ {
+ // this is a very specific handling to allow for /listen.m3u with v1.x DNAS to work correctly
+ // as we need alter the user-agent so it will provide us with the needed response (a DNAS bug)
+ if ((redirect != 2) && strstr(buf,"ICY 404 Resource Not Found") && strstr(url_url,"listen.m3u")) {
+ redirect=2;
+ closesocket(sock);
+ goto _redirect_goto;
+ }
+ else
+ {
+ redirect=0;
+ }
+ }
+
+ if (!strstr(buf,"OK") && !redirect)
+ {
+ StringCchCatA(buf,1024,getString(IDS_HTTP_CONNECTION_CLOSED,errorStr,1024));
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ rfta(buf);
+ }
+
+ sets(buf);
+ }
+
+ while (1)
+ {
+ char buf[1024] = {0}, *p;
+ int x = recv_string(sock,buf,sizeof(buf));
+ if (x < 0 || rf_abort)
+ {
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ rfta(getString(IDS_HTTP_CONNECTION_LOST,errorStr,1024));
+ }
+
+ if (buf[0] == '\r' || !buf[0])
+ break;
+
+ {
+ p=buf;
+ while (p && *p && *p != ':') p++;
+ if (p && *p == ':')
+ {
+ *p++=0;
+ while (p && (*p == ' ' || *p == '\t'))
+ p++;
+ }
+ else
+ p=NULL;
+ }
+
+ if (!lstrcmpiA(buf,"Content-Length") && (*p >= '0' && *p <= '9'))
+ {
+ content_length=0;
+ while (p && *p >= '0' && *p <= '9')
+ {
+ content_length *= 10;
+ content_length += *p++-'0';
+ }
+ }
+
+ if (!lstrcmpiA(buf,"Location") && redirect)
+ {
+ StringCchCopyA(locbuf,1024,p);
+ rf_url=locbuf;
+ closesocket(sock);
+
+ //blah
+ goto _redirect_goto;
+ }
+ }
+
+ {
+ createDirForFileW((wchar_t *)rf_file);
+ HANDLE h = CreateFileW(rf_file,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ rfta(getString(IDS_HTTP_ERROR_OPEN_FILE,errorStr,1024));
+ }
+
+ {
+ unsigned int start_time=GetTickCount();
+ char buf[4096] = {0};
+ while (1)
+ {
+ int x=p_recv(sock,buf,sizeof(buf),0);
+ if (x == 0 || rf_abort)
+ break;
+ else if (x < 0)
+ {
+ if (WSAGetLastError()!=WSAEWOULDBLOCK) break;
+ Sleep(50);
+ }
+ else // x > 0
+ {
+ DWORD t = 0;
+ int lb=total_bytes;
+ WriteFile(h,buf,x,&t,NULL);
+
+ total_bytes += x;
+ if ( lb / 16384 != total_bytes / 16384 )
+ {
+ int bps;
+ int t = ( GetTickCount() - start_time );
+ if ( t < 1000 ) t = 1000;
+ bps = total_bytes / ( ( t + 999 ) / 1000 );
+
+ if ( content_length )
+ StringCchPrintfA( buf, 4096, getString( IDS_HTTP_RETRIEVE_FILE_LENGTH, errorStr, 1024 ), ( total_bytes * 100 ) / content_length, total_bytes, content_length, bps / 1000, ( bps / 10 ) % 100 );
+ else
+ StringCchPrintfA( buf, 4096, getString( IDS_HTTP_RETRIEVE_FILE, errorStr, 1024 ), total_bytes, bps / 1000, ( bps / 10 ) % 100 );
+
+ sets( buf );
+ }
+ }
+ }
+ }
+ CloseHandle(h);
+ }
+
+ if (!content_length || total_bytes == content_length)
+ success=1;
+ else
+ sets(getString(IDS_HTTP_FILE_INCOMPLETE,errorStr,1024));
+
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ rfta(success?getString(IDS_HTTP_SUCCESS,errorStr,1024):NULL);
+}
+
+#undef rfta
+#undef sets
+
+static BOOL CALLBACK rf_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static HANDLE hThread;
+ static int r;
+
+ if (WADlg_initted())
+ {
+ INT_PTR a = WADlg_handleDialogMsgs(hwndDlg, uMsg, wParam, lParam);
+ if (a)
+ return a;
+ }
+
+ switch (uMsg)
+ {
+ case WM_USER+1:
+ if (hThread != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hThread);
+ hThread=INVALID_HANDLE_VALUE;
+ }
+
+ if (!wParam)
+ {
+ g_rv=0;
+ PostMessageW(hwndDlg,WM_USER,0,0); // make it go quick
+ }
+ else
+ {
+ SetDlgItemTextA(hwndDlg,IDCANCEL,getString(IDS_HTTP_CLOSE,NULL,0));
+ r=5;
+ SetTimer(hwndDlg,123,1000,NULL);
+ }
+
+ return 0;
+ case WM_TIMER:
+ if (wParam == 123)
+ {
+ if ( r == 0 )
+ {
+ KillTimer( hwndDlg, wParam );
+ g_rv = 1;
+ }
+ else
+ {
+ char s[ 32 ] = { 0 };
+ StringCchPrintfA( s, 32, getString( IDS_CLOSE_COUNTDOWN, NULL, 0 ), r-- );
+ SetDlgItemTextA( hwndDlg, IDCANCEL, s );
+ }
+ }
+ return 0;
+ case WM_ERASEBKGND:
+ if (WADlg_initted())
+ return 1; //handled by WADlg_DrawChildWindowBorders in WM_PAINT
+ break;
+ case WM_PAINT:
+ {
+ if (WADlg_initted())
+ {
+ int tab[] = { IDC_STATUS | DCW_SUNKENBORDER};
+ WADlg_DrawChildWindowBorders(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
+ return 0;
+ }
+ }
+ break;
+ case WM_INITDIALOG:
+ {
+ DWORD id;
+ char errorStr[ 1024 ] = { 0 };
+
+ if ( WADlg_initted() )
+ SetWindowLong( GetDlgItem( hwndDlg, IDCANCEL ), GWL_STYLE, GetWindowLongW( GetDlgItem( hwndDlg, IDCANCEL ), GWL_STYLE ) | BS_OWNERDRAW );
+
+ rf_dlgWnd = hwndDlg;
+ rf_statusWnd = GetDlgItem( hwndDlg, IDC_STATUS );
+ SetWindowTextW( hwndDlg, rf_dlgtitle );
+
+ if ( strstr( rf_url, "client.winamp.com/update" ) )
+ SetDlgItemTextA( hwndDlg, IDC_URL, getString( IDS_HTTP_WINAMP_UPDATE_SITE, errorStr, 1024 ) );
+ else
+ SetDlgItemTextA( hwndDlg, IDC_URL, rf_url );
+
+ SetDlgItemTextA( hwndDlg, IDC_STATUS, getString( IDS_HTTP_INIT, errorStr, 1024 ) );
+ rf_abort = 0;
+ hThread = CreateThread( NULL, 0, rf_ThreadProc, 0, 0, &id );
+ }
+ return FALSE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+ if (hThread!=INVALID_HANDLE_VALUE)
+ {
+ char errorStr[1024] = {0};
+ rf_abort=1;
+#if 0
+ if (g_in_resolve) g_in_resolve++;
+ if (0 && g_in_resolve==3) // lame terminatethread shouldnt be used
+ {
+ TerminateThread(hThread,0);
+ CloseHandle(hThread);
+ hThread=INVALID_HANDLE_VALUE;
+ g_rv=1;
+ }
+ else
+#endif
+ SetDlgItemTextA(hwndDlg,IDCANCEL,getString(IDS_HTTP_ABORT,errorStr,1024));
+ }
+ else
+ {
+ g_rv=1;
+ }
+
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+int httpRetrieveFileW(HWND hwnd, const char *url, const wchar_t *file, const wchar_t *dlgtitle)
+{
+ int i;
+ int activated=0;
+ RECT r;
+ HWND dlgWnd;
+ if (rf_in) return 1;
+ rf_in=1;
+ g_rv=-1;
+ rf_url=url;
+ rf_file=file;
+ rf_dlgtitle=dlgtitle;
+ g_in_resolve=0;
+ if (!hwnd) hwnd=hMainWindow;
+
+ if (hwnd == hMainWindow && g_dialog_box_parent)
+ hwnd=g_dialog_box_parent;
+
+ {
+ if (_strnicmp(url,"http://",7))
+ {
+// MessageBox(hwnd,getString(IDS_ONLYHTTP,NULL,0),"Winamp",MB_OK|MB_ICONSTOP);
+ rf_in=0;
+ return 1;
+ }
+ }
+
+ GetWindowRect(hwnd,&r);
+ dlgWnd=LPCreateDialogW(IDD_HTTPGET, hwnd, (WNDPROC)rf_DlgProc);
+ if (r.bottom > GetSystemMetrics(SM_CXSCREEN)/2 && r.bottom-r.top < 100)
+ {
+ RECT r2;
+ GetWindowRect(dlgWnd,&r2);
+ r.top=r.bottom-(r2.bottom-r2.top);
+ }
+
+ SetWindowPos(dlgWnd,NULL,r.left,r.top,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+
+ if (GetForegroundWindow()==hwnd)
+ {
+ activated=1;
+ ShowWindow(dlgWnd,SW_SHOW);
+ }
+ else
+ ShowWindow(dlgWnd,SW_SHOWNA);
+
+ if (hwnd == hMainWindow)
+ {
+ if (hMainWindow) EnableWindow(hMainWindow,0);
+ if (hPLWindow) EnableWindow(hPLWindow,0);
+ if (hEQWindow) EnableWindow(hEQWindow,0);
+ //if (hMBWindow) EnableWindow(hMBWindow,0);
+ }
+ else
+ EnableWindow(hwnd,0);
+
+ while (1)
+ {
+ MSG msg;
+ if (g_rv != -1) break;
+ GetMessage(&msg,NULL,0,0);
+ DispatchMessage(&msg);
+ }
+
+ if ( activated && GetForegroundWindow() == dlgWnd )
+ {
+ }
+ else
+ activated = 0;
+
+ if ( hwnd == hMainWindow )
+ {
+ if ( hMainWindow )
+ EnableWindow( hMainWindow, 1 );
+
+ if ( hPLWindow )
+ EnableWindow( hPLWindow, 1 );
+
+ if ( hEQWindow )
+ EnableWindow( hEQWindow, 1 );
+ //if (hMBWindow) EnableWindow(hMBWindow,1);
+ }
+ else
+ EnableWindow( hwnd, 1 );
+
+ DestroyWindow(dlgWnd);
+ if (activated)
+ SetForegroundWindow(hwnd);
+
+ i = g_rv;
+ rf_in=0;
+
+ return i;
+}
+
+int httpRetrieveFile(HWND hwnd, const char *url, char *file, char *dlgtitle)
+{
+ return httpRetrieveFileW(hwnd, url, AutoWide(file), AutoWide(dlgtitle));
+}
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/IN2.H b/Src/Winamp/IN2.H
new file mode 100644
index 00000000..f38e2be1
--- /dev/null
+++ b/Src/Winamp/IN2.H
@@ -0,0 +1,191 @@
+#ifndef NULLSOFT_WINAMP_IN2H
+#define NULLSOFT_WINAMP_IN2H
+// Input plugin interface
+
+#include "out.h"
+#ifdef __cplusplus
+class api_service;
+#endif
+
+// If you want your input plugin to support unicode then define the following which will then
+// adjust required functions to their unicode variants. This is supported from Winamp 5.3+.
+#define IN_UNICODE 0x0F000000
+#define IN_INIT_RET 0xF0000000
+
+#ifdef UNICODE_INPUT_PLUGIN
+#define in_char wchar_t
+#define IN_VER_OLD (IN_UNICODE | 0x100)
+#define IN_VER (IN_UNICODE | 0x101)
+#define IN_VER_RET (IN_INIT_RET | IN_VER)
+#else
+#define in_char char
+#define IN_VER_OLD 0x100
+#define IN_VER 0x101
+#define IN_VER_RET (IN_INIT_RET | IN_VER)
+#endif
+
+// added 5.64+ & updated 5.66+
+//
+// specify IN_VER if you want to provide a unicode (wchar_t*) description and only work on 5.64+
+// specify IN_VER_OLD to use the original (char*) description as before
+// note: we are using the fact that sizeof(char*) == sizeof(wchar_t*) to be able to allow this
+// so now when using IN_VER you will need to cast description to (wchar_t*) to set this.
+
+// added 5.66+
+// specify IN_VER_RET to allow for the init(..) member to return an int status value as either
+// IN_INIT_SUCCESS or IN_INIT_FAILURE to allow for better support with loading failures or if
+// needing to specifically prevent loading if required e.g. OS incompatibility or access issues.
+//
+// Also added is the 'service' member which saves sending a IPC_GET_API_SERVICE call on loading
+// which will be filled in if IN_VER_RET is specified in the 'version' member of the plug-in.
+
+#define IN_MODULE_FLAG_USES_OUTPUT_PLUGIN 1
+
+// By default Winamp assumes your input plugin wants to use Winamp's EQ, and doesn't do replay gain
+// if you handle any of these yourself (EQ, Replay Gain adjustments), then set these flags accordingly
+
+// Set this if you want to implement your own EQ inplace of using Winamp's native implementation.
+#define IN_MODULE_FLAG_EQ 2
+
+// Set this if you adjusted volume for replay gain. For tracks with no replay gain metadata then you
+// should clear this flag UNLESS you handle "non_replaygain" gain adjustment yourself then keep it.
+#define IN_MODULE_FLAG_REPLAYGAIN 8
+
+// Use this if you queried for the replay gain preamp parameter and used it. This is new to 5.54 clients.
+#define IN_MODULE_FLAG_REPLAYGAIN_PREAMP 16
+typedef struct
+{
+ int version; // module type (IN_VER)
+ char* description; // description of module, with version string
+
+ HWND hMainWindow; // Winamp's main window (filled in by Winamp - is a valid HWND on 5.1+ clients)
+ HINSTANCE hDllInstance; // DLL instance handle (Also filled in by Winamp)
+
+ char* FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
+ // May be altered from Config, so the user can select what they want
+
+ int is_seekable; // is this stream seekable?
+ int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :)
+ // note that this has turned into a "flags" field see IN_MODULE_FLAG_*
+
+ void(__cdecl* Config)(HWND hwndParent); // configuration dialog
+ void(__cdecl* About)(HWND hwndParent); // about dialog
+
+ // 5.66 - changed from void (__cdecl *Init)(); if using IN_VER_RET or IN_VER_RET_OLD
+ int(__cdecl* Init)(); // called at program init
+ void(__cdecl* Quit)(); // called at program quit
+
+#define GETFILEINFO_TITLE_LENGTH 2048
+// If file == NULL then the currently playing file is used (assumes you've cached it as required)
+ void (*GetFileInfo)(const in_char* file, in_char* title, int* length_in_ms);
+
+#define INFOBOX_EDITED 0
+#define INFOBOX_UNCHANGED 1
+ int(__cdecl* InfoBox)(const in_char* file, HWND hwndParent);
+
+ int(__cdecl* IsOurFile)(const in_char* fn); // called before extension checks, to allow detection of mms://, etc
+
+ // playback stuff
+ int(__cdecl* Play)(const in_char* fn); // return zero on success, -1 on file-not-found, some other value on other (stopping Winamp) error
+ void(__cdecl* Pause)(); // pause stream
+ void(__cdecl* UnPause)(); // unpause stream
+ int(__cdecl* IsPaused)(); // ispaused? return 1 if paused, 0 if not
+ void(__cdecl* Stop)(); // stop (unload) stream
+
+ // time stuff
+ int(__cdecl* GetLength)(); // get length in ms
+ int(__cdecl* GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
+ void(__cdecl* SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal your thread to seek, which seeks and calls outMod->Flush()..
+
+ // volume stuff
+ void(__cdecl* SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume
+ void(__cdecl* SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan
+
+ // in-window builtin vis stuff
+ void(__cdecl* SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
+ // call after opening audio device with max latency in ms and samplerate
+ void(__cdecl* SAVSADeInit)(); // call in Stop()
+
+ // simple vis supplying mode
+ void(__cdecl* SAAddPCMData)(void* PCMData, int nch, int bps, int timestamp); // sets the spec data directly from PCM data quick and easy way
+ // to get vis working :) needs at least 576 samples :)
+
+ // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
+ int(__cdecl* SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec)) use when calling SAAdd()
+ int(__cdecl* SAAdd)(void* data, int timestamp, int csa); // sets the spec data, filled in by Winamp
+
+ // vis stuff (plug-in)
+ // simple vis supplying mode
+ void(__cdecl* VSAAddPCMData)(void* PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data quick and easy way
+ // to get vis working :) needs at least 576 samples :)
+
+ // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
+ int(__cdecl* VSAGetMode)(int* specNch, int* waveNch); // use to figure out what to give to VSAAdd
+ int(__cdecl* VSAAdd)(void* data, int timestamp); // filled in by Winamp, called by plug-in
+
+ // call this in Play() to tell the vis plug-ins the current output params.
+ void(__cdecl* VSASetInfo)(int srate, int nch); // <-- Correct (benski, dec 2005).. old declaration had the params backwards
+
+ // dsp plug-in processing:
+ // (filled in by Winamp, calld by input plug)
+
+ // returns 1 if active (which means that the number of samples returned by dsp_dosamples could be
+ // greater than went in.. Use it to estimate if you'll have enough room in the output buffer
+ int(__cdecl* dsp_isactive)();
+
+ // returns number of samples to output. This can be as much as twice numsamples.
+ // be sure to allocate enough buffer for samples, then.
+ int(__cdecl* dsp_dosamples)(short int* samples, int numsamples, int bps, int nch, int srate);
+
+ // eq stuff
+ void(__cdecl* EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
+
+ // info setting (filled in by Winamp)
+ void(__cdecl* SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
+
+ Out_Module* outMod; // filled in by Winamp, optionally used :)
+
+ // filled in by Winamp (added 5.66+ to replace need to call IPC_GET_API_SERVICE on loading)
+#ifdef __cplusplus
+ api_service* service;
+#else
+ void* service;
+#endif
+} In_Module;
+
+// added 5.66+
+// return values from the init(..) which determines if Winamp will continue loading
+// and handling the plugin or if it will disregard the load attempt. If GEN_INIT_FAILURE
+// is returned then the plugin will be listed as [NOT LOADED] on the plug-in prefs page.
+#define IN_INIT_SUCCESS 0
+#define IN_INIT_FAILURE 1
+
+
+// These are the return values to be used with the uninstall plugin export function:
+// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
+// which determines if Winamp can uninstall the plugin immediately or on Winamp restart.
+// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
+//
+#define IN_PLUGIN_UNINSTALL_NOW 0x1
+#define IN_PLUGIN_UNINSTALL_REBOOT 0x0
+//
+// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
+// that it is down to you to ensure that if uninstall now is returned that it will not
+// cause a crash i.e. don't use if you've been subclassing the main window.
+//
+// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
+//
+
+// For a input plugin to be correctly detected by Winamp you need to ensure that
+// the exported winampGetInModule2(..) is exported as an undecorated function
+// e.g.
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+// __declspec(dllexport) In_Module * __cdecl winampGetInModule2(){ return &plugin; }
+// #ifdef __cplusplus
+// }
+// #endif
+//
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/IVideoD3DOSD.cpp b/Src/Winamp/IVideoD3DOSD.cpp
new file mode 100644
index 00000000..1804a742
--- /dev/null
+++ b/Src/Winamp/IVideoD3DOSD.cpp
@@ -0,0 +1,966 @@
+#include "main.h"
+#include "IVideoD3DOSD.h"
+#include "resource.h"
+
+extern wchar_t FileTitle[];
+static HMODULE d3dx_lib = 0;
+
+// For non-debug builds, comment out DXTraceW debug statements to
+// remove them completely
+//#ifndef _DEBUG
+#define DXTraceW //
+//#endif
+
+typedef HRESULT (WINAPI *D3DXCREATESPRITE)(LPDIRECT3DDEVICE9, LPD3DXSPRITE *);
+typedef HRESULT (WINAPI *D3DXCREATEFONTW)(LPDIRECT3DDEVICE9, INT, UINT, UINT, UINT, BOOL, DWORD, DWORD, DWORD, DWORD, LPCWSTR, LPD3DXFONT *);
+typedef HRESULT (WINAPI *D3DXCREATETEXTUREFROMRESOURCEEXW)(LPDIRECT3DDEVICE9, HMODULE, LPCWSTR, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, DWORD, DWORD, D3DCOLOR, D3DXIMAGE_INFO *, PALETTEENTRY *, LPDIRECT3DTEXTURE9 *);
+D3DXCREATESPRITE pCreateSprite = NULL;
+D3DXCREATEFONTW pCreateFontW = NULL;
+D3DXCREATETEXTUREFROMRESOURCEEXW pCreateTextureFromResourceExW = NULL;
+
+HMODULE FindD3DX9()
+{
+ if (d3dx_lib)
+ return d3dx_lib;
+
+ HMODULE d3dx9 = NULL;
+ HANDLE hFind;
+ WIN32_FIND_DATAW pfiledata;
+ wchar_t systemDir[MAX_PATH] = {0};
+ wchar_t libPath[MAX_PATH] = {0};
+ GetSystemDirectoryW(systemDir, MAX_PATH);
+ StringCchCatW(systemDir, MAX_PATH,L"\\d3dx9_");
+ StringCchCopyW(libPath, MAX_PATH, systemDir);
+ StringCchCatW(systemDir, MAX_PATH,L"*.dll");
+
+ hFind = FindFirstFileW(systemDir,&pfiledata);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ BOOL more = true;
+ int iHighVersion = 0;
+ while (more)
+ {
+ wchar_t *start = wcsrchr(pfiledata.cFileName,L'_') + 1;
+ int version = _wtoi(start);
+ if (version <= 42 && version > iHighVersion)
+ iHighVersion = version;
+ more = FindNextFileW(hFind,&pfiledata);
+ }
+
+ FindClose(hFind);
+ if (iHighVersion >= 24)
+ {
+ wchar_t finalD3DX9LibPath[MAX_PATH] = {0};
+ StringCchPrintfW(finalD3DX9LibPath,MAX_PATH,L"%s%d%s",libPath,iHighVersion,L".dll");
+
+ d3dx9 = LoadLibraryW(finalD3DX9LibPath);
+ }
+ }
+
+ return d3dx9;
+}
+
+IVideoD3DOSD::IVideoD3DOSD(void)
+{
+ osdSprite = NULL;
+ osdAtlasTexture = NULL;
+ osdTimeFont = NULL;
+ osdTitleFont = NULL;
+ streaming = 0;
+ titleFits = false;
+
+ // Texture Src Coordinates for sprite images
+ // Right and Bottom (last two) excluded from image
+ SetRect(&osdBkgrndTextSrcCoords, 38, 534, 647, 635);
+
+ SetRect(&osdPrevButtonNormalSrcCoords, 41, 17, 63, 31);
+ SetRect(&osdPlayButtonNormalSrcCoords, 145, 14, 161, 35);
+ SetRect(&osdPauseButtonNormalSrcCoords, 95, 16, 110, 33);
+ SetRect(&osdStopButtonNormalSrcCoords, 195, 16, 210, 33);
+ SetRect(&osdNextButtonNormalSrcCoords, 242, 17, 264, 31);
+ SetRect(&osdProgressFrameNormalSrcCoords, 41, 226, 606, 235);
+ SetRect(&osdVolumeFrameNormalSrcCoords, 41, 294, 111, 302);
+ SetRect(&osdEndFSButtonNormalSrcCoords, 41, 140, 59, 158);
+ SetRect(&osdMuteButtonNormalSrcCoords, 41, 416, 51, 428);
+ SetRect(&osdProgressSliderNormalSrcCoords, 41, 343, 57, 361);
+ SetRect(&osdVolumeSliderNormalSrcCoords, 41, 343, 57, 361);
+ SetRect(&osdProgressProgressSrcCoords, 41, 274, 606, 282); //hilited progress indicator
+ SetRect(&osdVolumeProgressSrcCoords, 41, 314, 111, 322); //hilited volume indicator
+
+ SetRect(&osdPrevButtonClickSrcCoords, 41, 76, 63, 90);
+ SetRect(&osdPlayButtonClickSrcCoords, 145, 73, 161, 94);
+ SetRect(&osdPauseButtonClickSrcCoords, 95, 75, 110, 92);
+ SetRect(&osdStopButtonClickSrcCoords, 195, 75, 210, 92);
+ SetRect(&osdNextButtonClickSrcCoords, 242, 76, 264, 90);
+ SetRect(&osdEndFSButtonClickSrcCoords, 41, 192, 59, 210);
+ SetRect(&osdProgressSliderClickSrcCoords, 41, 385, 57, 403);
+ SetRect(&osdVolumeSliderClickSrcCoords, 41, 385, 57, 403);
+
+ SetRect(&osdPrevButtonDisabledSrcCoords, 41, 106, 63, 120);
+ SetRect(&osdNextButtonDisabledSrcCoords, 242, 106, 264, 120);
+
+ SetRect(&osdPrevButtonHiliteSrcCoords, 41, 46, 63, 60);
+ SetRect(&osdPlayButtonHiliteSrcCoords, 145, 43, 161, 64);
+ SetRect(&osdPauseButtonHiliteSrcCoords, 95, 45, 110, 62);
+ SetRect(&osdStopButtonHiliteSrcCoords, 195, 45, 210, 62);
+ SetRect(&osdNextButtonHiliteSrcCoords, 242, 46, 264, 60);
+ SetRect(&osdEndFSButtonHiliteSrcCoords, 41, 166, 59, 184);
+ SetRect(&osdProgressSliderHiliteSrcCoords, 41, 363, 57, 381);
+ SetRect(&osdVolumeSliderHiliteSrcCoords, 41, 363, 57, 381);
+
+ xScalingFactor = 1.0f;
+ yScalingFactor = 1.0f;
+
+ for (int i = 0; i < 12; i++)
+ {
+ bState[i] = NORMAL;
+ }
+
+ mouseOver = NO_BUTTON;
+ mouseLastOver = NO_BUTTON;
+ mousePressed = NO_BUTTON;
+ mouseLastPressed = NO_BUTTON;
+ mouseDragging = false;
+
+ displayTitle = NULL;
+ marqueeTitleSrc = NULL;
+ titleRestart = 0;
+ dtFormat = 0;
+
+ isInited = false;
+ isReadyToDraw = false;
+}
+
+RECT IVideoD3DOSD::BuildHitRect(D3DXVECTOR3 position, RECT size)
+{
+ RECT hitRect;
+ // casting float to long since I know the position vector will not be too big.
+ hitRect.left = (long)position.x;
+ hitRect.top = (long)position.y;
+ hitRect.right = (long)position.x + size.right - size.left;
+ hitRect.bottom = (long)position.y + size.bottom - size.top;
+ return hitRect;
+}
+
+IVideoD3DOSD::~IVideoD3DOSD(void)
+{
+ if (osdSprite)
+ {
+ osdSprite->Release();
+ osdSprite = NULL;
+ }
+ if (osdAtlasTexture)
+ {
+ osdAtlasTexture->Release();
+ osdAtlasTexture = NULL;
+ }
+ if (marqueeTitleSrc)
+ {
+ delete [] marqueeTitleSrc;
+ marqueeTitleSrc = NULL;
+ }
+
+ if (displayTitle)
+ {
+ delete [] displayTitle;
+ displayTitle = NULL;
+ }
+
+ //if (d3dx_lib)
+ //{
+ // FreeLibrary(d3dx_lib);
+ // d3dx_lib = NULL;
+ //}
+}
+
+void IVideoD3DOSD::SetScalingFactor(float fx, float fy)
+{
+ xScalingFactor = fx;
+ yScalingFactor = fy;
+}
+
+void IVideoD3DOSD::CreateOSD(IDirect3DDevice9 * device)
+{
+ HRESULT hr;
+
+ d3dx_lib = FindD3DX9();
+ if (!d3dx_lib)
+ return;
+
+ pCreateFontW = (D3DXCREATEFONTW) GetProcAddress(d3dx_lib,"D3DXCreateFontW");
+ pCreateSprite = (D3DXCREATESPRITE) GetProcAddress(d3dx_lib,"D3DXCreateSprite");
+ pCreateTextureFromResourceExW = (D3DXCREATETEXTUREFROMRESOURCEEXW) GetProcAddress(d3dx_lib,"D3DXCreateTextureFromResourceExW");
+
+ if (!pCreateFontW || !pCreateSprite || !pCreateTextureFromResourceExW)
+ return;
+
+ hr = pCreateSprite(device,&osdSprite);
+ if (FAILED(hr))
+ {
+ DXTraceW(__FILE__, __LINE__, hr, L"CreateSprite Error", TRUE);
+ return;
+ }
+
+ int font_size = -12 ;
+ hr = pCreateFontW(
+ device,
+ font_size,
+ 0,
+ FW_NORMAL,
+ 1,
+ 0,
+ DEFAULT_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY, //DEFAULT_QUALITY,
+ DEFAULT_PITCH,
+ L"Arial",
+ &osdTimeFont);
+ if (FAILED(hr))
+ {
+ DXTraceW(__FILE__, __LINE__, hr, L"CreateFont (Time) Error", TRUE);
+ return;
+ }
+
+ font_size = -16 ;
+ hr = pCreateFontW(
+ device,
+ font_size,
+ 0,
+ FW_NORMAL,
+ 1,
+ 0,
+ DEFAULT_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,//DEFAULT_QUALITY,
+ DEFAULT_PITCH,
+ L"Trebuchet MS",
+ &osdTitleFont);
+ if (FAILED(hr))
+ {
+ DXTraceW(__FILE__, __LINE__, hr, L"CreateFont (Title) Error", TRUE);
+ return;
+ }
+
+ ResetOSD(device);
+
+ isInited = true;
+}
+
+void IVideoD3DOSD::UpdateOSD(HWND hWnd, VideoOutput *adjuster)
+{
+ // Position of sprites in screen coordinates
+ // Center of sprite (where the position is mapped) is left to default to upper left corner
+ // Note the Bkgrnd is positioned and then all other sprites are relative to that
+ RECT clientRect;
+ GetClientRect(hWnd,&clientRect);
+ // Need to adjust the client rect to match the video aspect ration to fit the osd on the video.
+ // adjuster->adjustAspect(clientRect);
+ // width of the client area - width of the bkgrnd / 2 gives the space on each side
+ // add that space to the offset of the left side of the client area.
+ float xPosBkg = clientRect.left +
+ (((clientRect.right - clientRect.left) - (osdBkgrndTextSrcCoords.right - osdBkgrndTextSrcCoords.left))/2.0f);
+ // width of the client area * .95 give the location of the bottom of the osd (i.e. 5% from bottom)
+ // that minus the height of the bkgrnd gives the location of the upper left of background
+ // add that space to the offset of the top of the client area.
+ float yPosBkg = clientRect.top +
+ (((clientRect.bottom - clientRect.top) * 1.0f) - (osdBkgrndTextSrcCoords.bottom - osdBkgrndTextSrcCoords.top));
+ osdBkgrndPosition = D3DXVECTOR3(floor(xPosBkg), floor(yPosBkg), 0.0f);
+
+ osdPrevButtonPosition = osdBkgrndPosition + D3DXVECTOR3(191.0f, 75.0f, 0.0f);
+ osdPlayButtonPosition = osdBkgrndPosition + D3DXVECTOR3(246.0f, 72.0f, 0.0f);
+ osdPauseButtonPosition = osdBkgrndPosition + D3DXVECTOR3(296.0f, 74.0f, 0.0f);
+ osdStopButtonPosition = osdBkgrndPosition + D3DXVECTOR3(345.5f, 74.0f, 0.0f);
+ osdNextButtonPosition = osdBkgrndPosition + D3DXVECTOR3(392.5f, 75.0f, 0.0f);
+ osdProgressFramePosition = osdBkgrndPosition + D3DXVECTOR3(22.0f, 49.0f, 0.0f);
+ osdVolumeFramePosition = osdBkgrndPosition + D3DXVECTOR3(518.0f, 76.0f, 0.0f);
+ osdEndFSButtonPosition = osdBkgrndPosition + D3DXVECTOR3(583.0f, 19.0f, 0.0f);
+ osdMuteButtonPosition = osdVolumeFramePosition + D3DXVECTOR3(-15.0f, -1.0f, 0.0f);
+ osdProgressSliderPosition = osdProgressFramePosition + D3DXVECTOR3(0.0f, 0.0f, 0.0f);
+ osdVolumeSliderPosition = osdVolumeFramePosition + D3DXVECTOR3(0.0f, 0.0f, 0.0f);
+
+ SetRect(&osdTimeRect,
+ (long)osdBkgrndPosition.x + 26,
+ (long)osdBkgrndPosition.y + 76,
+ (long)osdBkgrndPosition.x + 98,
+ (long)osdBkgrndPosition.y + 85);
+
+ SetRect(&osdTitleRect,
+ (long)osdBkgrndPosition.x + 26,
+ (long)osdBkgrndPosition.y + 17,
+ (long)osdBkgrndPosition.x + 503,
+ (long)osdBkgrndPosition.y + 37);
+
+ // Create Hit Test Rects for ui elements that don't move
+ osdPrevButtonHit = BuildHitRect(osdPrevButtonPosition, osdPrevButtonNormalSrcCoords );
+ osdPlayButtonHit = BuildHitRect(osdPlayButtonPosition, osdPlayButtonNormalSrcCoords );
+ osdPauseButtonHit = BuildHitRect(osdPauseButtonPosition, osdPauseButtonNormalSrcCoords );
+ osdStopButtonHit = BuildHitRect(osdStopButtonPosition, osdStopButtonNormalSrcCoords );
+ osdNextButtonHit = BuildHitRect(osdNextButtonPosition, osdNextButtonNormalSrcCoords );
+ osdEndFSButtonHit = BuildHitRect(osdEndFSButtonPosition, osdEndFSButtonNormalSrcCoords);
+ osdProgressFrameHit = BuildHitRect(osdProgressFramePosition, osdProgressFrameNormalSrcCoords);
+ osdVolumeFrameHit = BuildHitRect(osdVolumeFramePosition, osdVolumeFrameNormalSrcCoords);
+
+ streaming = (in_getlength() < 0) || !in_mod || !in_mod->is_seekable;
+ if (streaming)
+ {
+ bState[PREV_BUTTON] = DISABLED;
+ bState[NEXT_BUTTON] = DISABLED;
+ bState[PROGRESS_FRAME] = DISABLED;
+ bState[PROGRESS_SLIDER] = DISABLED;
+ }
+
+ // Find out if the title will fit in the UI space for it
+ RECT tempTitleRect = osdTitleRect;
+ osdTitleFont->DrawTextW(NULL, FileTitle, -1, &tempTitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP | DT_CALCRECT, D3DCOLOR_XRGB(255,255,255));
+ if (tempTitleRect.right <= osdTitleRect.right)
+ {
+ // The title fits, just use it
+ titleFits = true;
+ displayTitle = FileTitle;
+ dtFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP;
+ } else
+ {
+ // title will not fit, we need to set up a marquee.
+ //
+ // a string with two copies of the title makes it easier to process
+ // sizeNeeded, in chars, includes one space, five dots,
+ // one space and 1 extra for null.
+ size_t sizeNeeded = (lstrlenW(FileTitle)*2) + 8;
+ marqueeTitleSrc = new wchar_t[sizeNeeded];
+ displayTitle = new wchar_t[sizeNeeded];
+ titleRestart = lstrlenW(FileTitle);
+ StringCchPrintfW(marqueeTitleSrc, sizeNeeded, L"%s ..... %s", FileTitle, FileTitle);
+ titleFits = false;
+ dtFormat = DT_RIGHT | DT_TOP | DT_SINGLELINE;
+ }
+
+ isReadyToDraw = true;
+}
+#ifdef _DEBUG
+#define DRAW_OSD_SET_ERROR(x) draw_osd_error=x
+#else
+#define DRAW_OSD_SET_ERROR(x)
+#endif
+
+void IVideoD3DOSD::DrawOSD(IDirect3DDevice9 * device)
+{
+ HRESULT hr;
+ D3DXVECTOR3 sliderCenter(8.0f, 8.0f, 0.0f);
+
+ const wchar_t *draw_osd_error;
+ hr = osdSprite->Begin(D3DXSPRITE_ALPHABLEND);
+ if (FAILED(hr))
+ {
+
+ DXTraceW(__FILE__, __LINE__, hr, L"Sprite Begin Error", TRUE);
+ return ;
+ }
+
+ // Doing Scaling of sprites here
+ // If we do translations and/or rotations we'll have to do a more
+ // robust hit test (picking) since the current one assumes a rectangular
+ // shape based on screen coordinates. Only scaling is currently handled
+ // in the hit test.
+ //D3DXMATRIX scalingMatrix;
+ //osdSprite->SetTransform(D3DXMatrixScaling(&scalingMatrix, 1.0f /*xScalingFactor*/, 1.0f /*yScalingFactor*/, 0.0f));
+
+ hr = osdSprite->Draw(osdAtlasTexture, &osdBkgrndTextSrcCoords, NULL, &osdBkgrndPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Background Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PREV_BUTTON), NULL, &osdPrevButtonPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Prev Button Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PLAY_BUTTON), NULL, &osdPlayButtonPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Play Button Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PAUSE_BUTTON), NULL, &osdPauseButtonPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Pause Button Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(STOP_BUTTON), NULL, &osdStopButtonPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Stop Button Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(NEXT_BUTTON), NULL, &osdNextButtonPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Next Button Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PROGRESS_FRAME), NULL, &osdProgressFramePosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Progress Frame Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(VOLUME_FRAME), NULL, &osdVolumeFramePosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Volume Frame Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(ENDFS_BUTTON), NULL, &osdEndFSButtonPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"EndFS Button Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(MUTE_BUTTON), NULL, &osdMuteButtonPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Mute Button Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+
+ if (playing && !streaming && !mouseDragging) // if mouseDragging we may be repositioning the slider, don't set it back till Lmouseup
+ {
+ // calculate the relative position of the slider
+ float ppercent = (in_getouttime() / 1000.0f) / in_getlength();
+ float sizeOfProgFrame = (float)osdProgressFrameHit.right - osdProgressFrameHit.left - 0;
+ // position the progress slider
+ osdProgressSliderPosition.x = osdProgressFramePosition.x + (sizeOfProgFrame * ppercent);
+ // Now build the hit rect based on the new position.
+ osdProgressSliderHit = BuildHitRect(osdProgressSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f), osdProgressSliderNormalSrcCoords);
+ }
+
+
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PROGRESS_SLIDER), &sliderCenter, &osdProgressSliderPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Progress Slider Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+
+ // Build the progress hilite line by drawing only a certain amount (width) of the texture.
+ RECT seekProgress;
+ // The progress hilite line goes on top of progress frame
+ seekProgress = osdProgressProgressSrcCoords;
+ // The width of the progress hilite line is determined by the location of the slider
+ seekProgress.right = seekProgress.left + (osdProgressSliderHit.left - osdProgressFrameHit.left + 0);
+
+ hr = osdSprite->Draw(osdAtlasTexture,
+ &seekProgress,
+ NULL,
+ &osdProgressFramePosition,
+ D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Seek Progress Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+
+ if (!mouseDragging) // if mouseDragging we may be repositioning the slider, don't set it back till Lmouseup
+ {
+ // calculate the relative position of the slider
+ float vpercent = config_volume / 255.0f;
+ float sizeOfVolFrame = (float)osdVolumeFrameHit.right - osdVolumeFrameHit.left - 0;
+ // position the volume slider
+ osdVolumeSliderPosition.x = (osdVolumeFramePosition.x) + (sizeOfVolFrame * vpercent);
+ // Now build the hit rect based on the new position.
+ osdVolumeSliderHit = BuildHitRect(osdVolumeSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f), osdVolumeSliderNormalSrcCoords);
+ }
+ hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(VOLUME_SLIDER), &sliderCenter, &osdVolumeSliderPosition, D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Volume SLider Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+
+ // Build the volume hilite line by drawing only a certain amount (width) of the texture.
+ RECT volProgress;
+ // The volume hilite line goes on top of volume frame
+ volProgress = osdVolumeProgressSrcCoords;
+ // The width of the volume hilite line is determined by the location of the slider
+ volProgress.right = volProgress.left + (osdVolumeSliderHit.left - osdVolumeFrameHit.left + 0);
+
+ hr = osdSprite->Draw(osdAtlasTexture,
+ &volProgress,
+ NULL,
+ &osdVolumeFramePosition,
+ D3DCOLOR_XRGB(255,255,255));
+ if (FAILED(hr))
+ {
+ DRAW_OSD_SET_ERROR(L"Volume Progress Sprite Draw Error");
+ goto DrawOSD_Error;
+ }
+
+
+ if (osdTimeFont)
+ {
+ int seconds_in = in_getouttime() / 1000;
+ int time_to_go = in_getlength();
+
+ wchar_t timerText[256] = {0};
+ if (streaming)
+ StringCbPrintfW(timerText,sizeof(timerText),L"%.2u:%.2u",seconds_in /60,seconds_in % 60);
+ else
+ StringCbPrintfW(timerText,sizeof(timerText),L"%.2u:%.2u / %.2u:%.2u",seconds_in /60,seconds_in % 60,time_to_go / 60, time_to_go % 60);
+ osdTimeFont->DrawTextW(osdSprite, timerText, -1, &osdTimeRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP, D3DCOLOR_XRGB(163,164,167)); // #A3A4A7
+ }
+
+ if (osdTitleFont)
+ {
+ // found possibility that user can pause in full screen and remove items from playlist
+ // This prevents a crash by not trying to display a title.
+ if (lstrlenW(FileTitle) > 0)
+ {
+ if (!titleFits)
+ {
+ // title does not fit, build marquee
+ DWORD now = GetTickCount();
+ static DWORD then;
+ if (now - then > 250) // slow it down so people can read it.
+ {
+ static int charCount = 2; // start with the first char + 1 for null
+ lstrcpynW(displayTitle,marqueeTitleSrc,charCount);
+ charCount++;
+ if (charCount > lstrlenW(marqueeTitleSrc))
+ charCount = lstrlenW(FileTitle);
+ then = now;
+ }
+ }
+
+ osdTitleFont->DrawTextW(osdSprite, displayTitle, -1, &osdTitleRect, dtFormat, D3DCOLOR_XRGB(204,204,204)); // #cccccc
+ }
+ }
+
+ hr = osdSprite->End();
+ if (FAILED(hr))
+ {
+ DXTraceW(__FILE__, __LINE__, hr, L"Sprite End Error", TRUE);
+ return;
+ }
+
+ return;
+DrawOSD_Error:
+ DXTraceW(__FILE__, __LINE__, hr, draw_osd_error, TRUE);
+ osdSprite->End();
+}
+
+RECT *IVideoD3DOSD::GetTextCoords(UI_ELEM item)
+{
+ switch (item)
+ {
+ case PREV_BUTTON :
+ switch (bState[item])
+ {
+ case NORMAL :
+ return &osdPrevButtonNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdPrevButtonClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdPrevButtonHiliteSrcCoords;
+ break;
+ case DISABLED :
+ return &osdPrevButtonDisabledSrcCoords;
+ break;
+ }
+
+ break;
+ case PLAY_BUTTON :
+ switch (bState[item])
+ {
+ case NORMAL :
+ case DISABLED :
+ return &osdPlayButtonNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdPlayButtonClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdPlayButtonHiliteSrcCoords;
+ break;
+ }
+
+ break;
+ case PAUSE_BUTTON :
+ switch (bState[item])
+ {
+ case NORMAL :
+ case DISABLED :
+ return &osdPauseButtonNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdPauseButtonClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdPauseButtonHiliteSrcCoords;
+ break;
+ }
+
+ break;
+ case STOP_BUTTON :
+ switch (bState[item])
+ {
+ case NORMAL :
+ case DISABLED :
+ return &osdStopButtonNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdStopButtonClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdStopButtonHiliteSrcCoords;
+ break;
+ }
+
+ break;
+ case NEXT_BUTTON :
+ switch (bState[item])
+ {
+ case NORMAL :
+ return &osdNextButtonNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdNextButtonClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdNextButtonHiliteSrcCoords;
+ break;
+ case DISABLED :
+ return &osdNextButtonDisabledSrcCoords;
+ break;
+ }
+
+ break;
+ case ENDFS_BUTTON :
+ switch (bState[item])
+ {
+ case NORMAL :
+ case DISABLED :
+ return &osdEndFSButtonNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdEndFSButtonClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdEndFSButtonHiliteSrcCoords;
+ break;
+ }
+
+ break;
+ case MUTE_BUTTON :
+ return &osdMuteButtonNormalSrcCoords;
+ //switch (bState[item])
+ //{
+ //case NORMAL :
+ //case DISABLED :
+ // return &osdMuteButtonNormalSrcCoords;
+ // break;
+ //case CLICKED :
+ // return &osdMuteButtonClickSrcCoords;
+ // break;
+ //case HILITE :
+ // return &osdMuteButtonHiliteSrcCoords;
+ // break;
+ //}
+
+ break;
+ case PROGRESS_FRAME :
+ return &osdProgressFrameNormalSrcCoords;
+
+ break;
+ case VOLUME_FRAME :
+ return &osdVolumeFrameNormalSrcCoords;
+
+ break;
+ case PROGRESS_SLIDER :
+ switch (bState[item])
+ {
+ case NORMAL :
+ case DISABLED :
+ return &osdProgressSliderNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdProgressSliderClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdProgressSliderHiliteSrcCoords;
+ break;
+ }
+
+ break;
+ case VOLUME_SLIDER :
+ switch (bState[item])
+ {
+ case NORMAL :
+ case DISABLED :
+ return &osdVolumeSliderNormalSrcCoords;
+ break;
+ case CLICKED :
+ return &osdVolumeSliderClickSrcCoords;
+ break;
+ case HILITE :
+ return &osdVolumeSliderHiliteSrcCoords;
+ break;
+ }
+
+ break;
+ }
+
+ return NULL;
+}
+
+void IVideoD3DOSD::LostOSD()
+{
+ if (osdSprite)
+ osdSprite->OnLostDevice();
+ if (osdTimeFont)
+ osdTimeFont->OnLostDevice();
+ if (osdTitleFont)
+ osdTitleFont->OnLostDevice();
+ if (osdAtlasTexture)
+ {
+ osdAtlasTexture->Release();
+ osdAtlasTexture = 0;
+ }
+}
+
+void IVideoD3DOSD::ResetOSD(IDirect3DDevice9 * device)
+{
+ if (osdSprite)
+ osdSprite->OnResetDevice();
+ if (osdTimeFont)
+ osdTimeFont->OnResetDevice();
+ if (osdTitleFont)
+ osdTitleFont->OnResetDevice();
+
+ if (device)
+ {
+ HRESULT hr;
+ hr = pCreateTextureFromResourceExW(
+ device,
+ NULL, // HMODULE
+ MAKEINTRESOURCEW(IDB_OSD), // Our texture image atlas
+ D3DX_DEFAULT, // width
+ D3DX_DEFAULT, // height
+ 1, // MIP levels
+ 0, // usage
+ D3DFMT_UNKNOWN, // get format from file
+ D3DPOOL_DEFAULT, // mem pool
+ D3DX_DEFAULT, // filter
+ D3DX_DEFAULT, // MIP filter
+ 0, // transparent color key
+ NULL, // image info struct
+ NULL, // palette
+ &osdAtlasTexture); // the returned texture, if success
+ if (FAILED(hr))
+ {
+ DXTraceW(__FILE__, __LINE__, hr, L"CreateTextureFromFileEx Error", TRUE);
+ return;
+ }
+ }
+
+}
+
+bool IVideoD3DOSD::MouseDown(int xpt, int ypt, WPARAM wParam)
+{
+ Show();
+ // mouseLastPressed is used during mouse up to verify that the up is on the
+ // same UI element as the mouse down.
+ mouseLastPressed = HitTest((float)xpt, (float)ypt);
+ bState[mouseLastPressed] = CLICKED;
+ return false;
+}
+bool IVideoD3DOSD::MouseMove(int ixpt, int iypt, WPARAM wParam)
+{
+ static int saved_ixpt;
+ static int saved_iypt;
+
+ // Need to check whether the mouse cursor is still in the same place.
+ // Evidently, WM_MOUSEMOVE can get triggered for other reasons than
+ // actually moving the mouse, per Microsoft blogs
+ // This code was triggering with IM and EMAIL notifications without
+ // moving the mouse.
+ if (ixpt == saved_ixpt && iypt == saved_iypt)
+ return false;
+
+ saved_ixpt = ixpt;
+ saved_iypt = iypt;
+
+ Show();
+
+ // Change input ints to floats so later calculations are more precise.
+ float xpt = (float)ixpt;
+ float ypt = (float)iypt;
+
+ mouseOver = HitTest((float)xpt, (float)ypt);
+ if (wParam & MK_LBUTTON) //dragging
+ {
+ mouseDragging = true;
+ if (mouseLastPressed == VOLUME_SLIDER)
+ {
+ if (xpt < (osdVolumeFrameHit.left)) xpt = (float) osdVolumeFrameHit.left;
+ else if (xpt > (osdVolumeFrameHit.right) - 0) xpt = (float) osdVolumeFrameHit.right - 0;
+
+ //move the volume slider
+ osdVolumeSliderPosition.x = xpt;
+ // slider uses center as center
+ osdVolumeSliderHit = BuildHitRect(osdVolumeSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f),osdVolumeSliderNormalSrcCoords);
+ }
+ else if (mouseLastPressed == PROGRESS_SLIDER)
+ {
+ if (xpt < osdProgressFrameHit.left) xpt = (float)osdProgressFrameHit.left;
+ else if (xpt > (osdProgressFrameHit.right)) xpt = (float)osdProgressFrameHit.right;
+
+ //move the progress slider
+ osdProgressSliderPosition.x = xpt;
+ osdProgressSliderHit = BuildHitRect(osdProgressSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f),osdProgressSliderNormalSrcCoords);
+ }
+ } else // no click, just mousemove
+ {
+ mouseDragging = false;
+ if (mouseLastOver != mouseOver)
+ {
+ if (bState[mouseLastOver] == HILITE)
+ bState[mouseLastOver] = NORMAL;
+ if (bState[mouseOver] == NORMAL)
+ bState[mouseOver] = HILITE;
+ mouseLastOver = mouseOver;
+ }
+ }
+
+ return false;
+}
+
+bool IVideoD3DOSD::MouseUp(int xpt, int ypt, WPARAM wParam)
+{
+ mousePressed = HitTest((float)xpt, (float)ypt);
+
+ bState[mouseLastPressed] = NORMAL;
+
+ if (bState[mousePressed] == HILITE)
+ bState[mousePressed] = NORMAL;
+
+ mouseDragging = false;
+
+ switch (mousePressed)
+ {
+ case ENDFS_BUTTON :
+ if (mouseLastPressed == ENDFS_BUTTON)
+ return true; // end full screen
+ break;
+ case PREV_BUTTON :
+ if (mouseLastPressed == PREV_BUTTON)
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON1, 0);
+ break;
+ case PLAY_BUTTON :
+ if (mouseLastPressed == PLAY_BUTTON)
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0);
+ break;
+ case PAUSE_BUTTON :
+ if (mouseLastPressed == PAUSE_BUTTON)
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0);
+ break;
+ case STOP_BUTTON :
+ if (mouseLastPressed == STOP_BUTTON)
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);
+ break;
+ case NEXT_BUTTON :
+ if (mouseLastPressed == NEXT_BUTTON)
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON5, 0);
+ break;
+ default :
+ {
+ // If not a button, check the sliders
+ // The successful use of the sliders should not depend on
+ // releasing the mouse inside the frame, which may be very small.
+ switch (mouseLastPressed)
+ {
+ case PROGRESS_SLIDER :
+ case PROGRESS_FRAME :
+ {
+ float xIntoFrame = (float)xpt - osdProgressFrameHit.left;
+ // -8 is half the width of the slider
+ float rightMaxOfFrame = (float)osdProgressFrameHit.right - 0;
+ float leftMinOfFrame = (float)osdProgressFrameHit.left;
+ float sizeOfFrame = rightMaxOfFrame - leftMinOfFrame;
+ float t = xIntoFrame / sizeOfFrame;
+ if (t < 0)
+ t = 0;
+ if (t > 1)
+ t = 1;
+
+ int len = in_getlength();
+ in_seek((int)(t*len*1000));
+ }
+ break;
+ case VOLUME_SLIDER :
+ case VOLUME_FRAME :
+ {
+ float xIntoFrame = (float)xpt - (osdVolumeFrameHit.left);
+ // -8 is half the width of the slider
+ float rightMaxOfFrame = (float)osdVolumeFrameHit.right - 0;
+ float leftMinOfFrame = (float)osdVolumeFrameHit.left;
+ float sizeOfFrame = rightMaxOfFrame - leftMinOfFrame;
+ float t = xIntoFrame / sizeOfFrame;
+
+ if (t < 0)
+ t = 0;
+ if (t > 1)
+ t = 1;
+
+ unsigned char v = (unsigned char)(t * 255);
+
+ config_volume = v;
+
+ in_setvol(v);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ mouseLastPressed = NO_BUTTON;
+ return false;
+}
+
+IVideoD3DOSD::UI_ELEM IVideoD3DOSD::HitTest(float xpt, float ypt)
+{
+ if (PointInRect(xpt, ypt, osdPrevButtonHit))
+ return PREV_BUTTON;
+ else if (PointInRect(xpt, ypt, osdPlayButtonHit))
+ return PLAY_BUTTON;
+ else if (PointInRect(xpt, ypt, osdPauseButtonHit))
+ return PAUSE_BUTTON;
+ else if (PointInRect(xpt, ypt, osdStopButtonHit))
+ return STOP_BUTTON;
+ else if (PointInRect(xpt, ypt, osdNextButtonHit))
+ return NEXT_BUTTON;
+ else if (PointInRect(xpt, ypt, osdEndFSButtonHit))
+ return ENDFS_BUTTON;
+ else if (PointInRect(xpt, ypt, osdVolumeSliderHit))
+ return VOLUME_SLIDER;
+ else if (PointInRect(xpt, ypt, osdProgressSliderHit))
+ return PROGRESS_SLIDER;
+ else if (PointInRect(xpt, ypt, osdProgressFrameHit))
+ return PROGRESS_FRAME;
+ else if (PointInRect(xpt, ypt, osdVolumeFrameHit))
+ return VOLUME_FRAME;
+ else
+ return NO_BUTTON;
+}
+
+bool IVideoD3DOSD::PointInRect(float x, float y, RECT testRect)
+{
+ if ((x >= testRect.left) && (x <= testRect.right) &&
+ (y >= testRect.top) && (y <= testRect.bottom))
+ return true;
+ else
+ return false;
+}
diff --git a/Src/Winamp/IVideoD3DOSD.h b/Src/Winamp/IVideoD3DOSD.h
new file mode 100644
index 00000000..6a91fbbc
--- /dev/null
+++ b/Src/Winamp/IVideoD3DOSD.h
@@ -0,0 +1,158 @@
+#pragma once
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <dxerr.h>
+#include "videoosd.h"
+#include "videooutput.h"
+#include "resource.h"
+
+extern HWND hMainWindow;
+
+
+class IVideoD3DOSD :
+ public IVideoOSD
+{
+public:
+ IVideoD3DOSD(void);
+ ~IVideoD3DOSD(void);
+
+ enum UI_ELEM
+ {
+ NO_BUTTON,
+ PREV_BUTTON,
+ PLAY_BUTTON,
+ PAUSE_BUTTON,
+ STOP_BUTTON,
+ NEXT_BUTTON,
+ ENDFS_BUTTON,
+ MUTE_BUTTON,
+ PROGRESS_FRAME,
+ VOLUME_FRAME,
+ PROGRESS_SLIDER,
+ VOLUME_SLIDER
+ };
+
+ enum BUTTON_STATE
+ {
+ NORMAL,
+ CLICKED,
+ HILITE,
+ DISABLED
+ };
+
+ void CreateOSD(IDirect3DDevice9 * device);
+ void UpdateOSD(HWND hWnd, VideoOutput *adjuster);
+ void DrawOSD(IDirect3DDevice9 * device);
+ void LostOSD();
+ void ResetOSD(IDirect3DDevice9 *device);
+ UI_ELEM HitTest(float x, float y);
+ bool MouseDown(int xpt, int ypt, WPARAM wParam);
+ bool MouseMove(int xpt, int ypt, WPARAM wParam);
+ bool MouseUp(int xpt, int ypt, WPARAM wParam);
+ void SetScalingFactor(float x, float y);
+ bool isOSDInited(){return isInited;}
+ bool isOSDReadyToDraw(){return isReadyToDraw;};
+
+protected:
+ ID3DXSprite *osdSprite;
+ IDirect3DTexture9 *osdAtlasTexture;
+ ID3DXFont *osdTimeFont;
+ ID3DXFont *osdTitleFont;
+
+ // Texture Src Coordinates for sprite images
+ // Right and Bottom (last two) excluded from image
+ RECT osdPrevButtonNormalSrcCoords;
+ RECT osdPlayButtonNormalSrcCoords;
+ RECT osdPauseButtonNormalSrcCoords;
+ RECT osdStopButtonNormalSrcCoords;
+ RECT osdNextButtonNormalSrcCoords;
+ RECT osdProgressFrameNormalSrcCoords;
+ RECT osdVolumeFrameNormalSrcCoords;
+ RECT osdEndFSButtonNormalSrcCoords;
+ RECT osdMuteButtonNormalSrcCoords;
+ RECT osdProgressSliderNormalSrcCoords;
+ RECT osdVolumeSliderNormalSrcCoords;
+ RECT osdProgressProgressSrcCoords;
+ RECT osdVolumeProgressSrcCoords;
+
+ RECT osdPrevButtonClickSrcCoords;
+ RECT osdPlayButtonClickSrcCoords;
+ RECT osdPauseButtonClickSrcCoords;
+ RECT osdStopButtonClickSrcCoords;
+ RECT osdNextButtonClickSrcCoords;
+ RECT osdEndFSButtonClickSrcCoords;
+ RECT osdProgressSliderClickSrcCoords;
+ RECT osdVolumeSliderClickSrcCoords;
+
+ RECT osdPrevButtonDisabledSrcCoords;
+ RECT osdNextButtonDisabledSrcCoords;
+// RECT osdProgressFrameDisabledSrcCoords;
+// RECT osdProgressSliderDisabledSrcCoords;
+
+ RECT osdPrevButtonHiliteSrcCoords;
+ RECT osdPlayButtonHiliteSrcCoords;
+ RECT osdPauseButtonHiliteSrcCoords;
+ RECT osdStopButtonHiliteSrcCoords;
+ RECT osdNextButtonHiliteSrcCoords;
+// RECT osdProgressFrameHiliteSrcCoords;
+// RECT osdVolumeFrameHiliteSrcCoords;
+ RECT osdEndFSButtonHiliteSrcCoords;
+ RECT osdProgressSliderHiliteSrcCoords;
+ RECT osdVolumeSliderHiliteSrcCoords;
+
+ RECT osdBkgrndTextSrcCoords;
+ RECT osdTimeRect;
+ RECT osdTitleRect;
+
+ // Position of sprites in screen coordinates
+ // Center of sprite (where the position is mapped) is left to default to upper left corner
+ // except for progress and volume sliders, which are mapped to their center
+ // Note the Bkgrnd is positioned and then all other sprites are relative to that
+ D3DXVECTOR3 osdBkgrndPosition;
+ D3DXVECTOR3 osdPrevButtonPosition;
+ D3DXVECTOR3 osdPlayButtonPosition;
+ D3DXVECTOR3 osdPauseButtonPosition;
+ D3DXVECTOR3 osdStopButtonPosition;
+ D3DXVECTOR3 osdNextButtonPosition;
+ D3DXVECTOR3 osdProgressFramePosition;
+ D3DXVECTOR3 osdVolumeFramePosition;
+ D3DXVECTOR3 osdEndFSButtonPosition;
+ D3DXVECTOR3 osdMuteButtonPosition;
+ D3DXVECTOR3 osdProgressSliderPosition;
+ D3DXVECTOR3 osdVolumeSliderPosition;
+
+ // Hit test rects for buttons
+ RECT osdPrevButtonHit;
+ RECT osdPlayButtonHit;
+ RECT osdPauseButtonHit;
+ RECT osdStopButtonHit;
+ RECT osdNextButtonHit;
+ RECT osdEndFSButtonHit;
+ RECT osdProgressFrameHit;
+ RECT osdVolumeFrameHit;
+ RECT osdProgressSliderHit;
+ RECT osdVolumeSliderHit;
+
+ float xScalingFactor;
+ float yScalingFactor;
+ BUTTON_STATE bState[12]; // bState[0] is for NO_BUTTON
+ bool streaming;
+ wchar_t *displayTitle; // title displayed in osd UI
+ wchar_t *marqueeTitleSrc; // temp string used to create displayTitle if title does not fit.
+ size_t titleRestart; // location in title to loop back to for marquee effect
+ bool titleFits; // indicates whether the title will fit in the UI title field
+ DWORD dtFormat; // format of title text rect based on title size, i.e., center or left justified
+
+ UI_ELEM mouseOver;
+ UI_ELEM mouseLastOver;
+ UI_ELEM mousePressed;
+ UI_ELEM mouseLastPressed; // used to verify that the LMouse up event matches the LMouse down
+ bool mouseDragging; // whether dragging is in progress to decide to update from winamp info
+
+ bool isInited; // has run CreateOSD to create all the d3d objects
+ bool isReadyToDraw; // has run UpdateOSD to init OSD for drawing, i.e., positioning the UI elements
+
+ bool PointInRect(float x, float y, RECT testRect);
+ RECT BuildHitRect(D3DXVECTOR3 position, RECT size);
+ RECT * GetTextCoords(UI_ELEM item);
+};
diff --git a/Src/Winamp/IWasabiDispatchable.h b/Src/Winamp/IWasabiDispatchable.h
new file mode 100644
index 00000000..e524d614
--- /dev/null
+++ b/Src/Winamp/IWasabiDispatchable.h
@@ -0,0 +1,13 @@
+#pragma once
+#include <unknwn.h>
+#include <bfc/dispatch.h>
+// {6BB64D00-F2E1-4c43-B9AA-A762506B8BB6}
+static const GUID IID_IWasabiDispatchable =
+{ 0x6bb64d00, 0xf2e1, 0x4c43, { 0xb9, 0xaa, 0xa7, 0x62, 0x50, 0x6b, 0x8b, 0xb6 } };
+
+
+class IWasabiDispatchable : public IUnknown
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable) = 0;
+}; \ No newline at end of file
diff --git a/Src/Winamp/In.cpp b/Src/Winamp/In.cpp
new file mode 100644
index 00000000..ab83f820
--- /dev/null
+++ b/Src/Winamp/In.cpp
@@ -0,0 +1,1293 @@
+#include "Main.h"
+
+#include "resource.h"
+#include <math.h>
+#include "api.h"
+//#define PROFILE_PLUGINS_LOAD_TIME
+#include "timing.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+#include "WinampAttributes.h"
+#include "eq10dsp.h"
+#include "../nsutil/pcm.h"
+
+
+int filter_srate = 0, filter_enabled = 1, filter_top = 0, filter_top2 = 10;
+static In_Module* dsp_init_mod = 0;
+static int dsp_in_init = 0;
+std::vector<In_Module*> in_modules;
+In_Module* in_mod = 0;
+float preamp_val = 1.0f;
+
+eq10_t* eq = 0;
+
+extern "C" volatile int sa_override;
+
+static void setinfo(int bitrate, int srate, int stereo, int synched);
+static void vissa_init(int maxlatency_in_ms, int srate);
+static void vissa_deinit();
+static int sa_getmode();
+static int eq_dosamples_4front(short* samples, int numsamples, int bps, int nch, int srate);
+static int eq_dosamples(short* samples, int numsamples, int bps, int nch, int srate);
+int benskiQ_eq_dosamples(short* samples, int numsamples, int bps, int nch, int srate);
+static int eq_isactive();
+
+static int myisourfile(const char* filename) // mjf bullshit
+{
+ return 0;
+}
+
+typedef struct _PLUGINORDER
+{
+ LPCWSTR name;
+ bool found;
+} PLUGINORDER;
+
+static PLUGINORDER preload[] =
+{
+ // the one plug-in to rule all
+ { L"in_mp3.dll", false },
+
+ // no extension configuration
+ { L"in_avi.dll", false },
+ { L"in_cdda.dll", false },
+ { L"in_linein.dll", false },
+ { L"in_mkv.dll", false },
+ { L"in_nsv.dll", false },
+ { L"in_swf.dll", false },
+ { L"in_vorbis.dll", false },
+
+ // extension configuration
+ { L"in_mp4.dll", false },
+ { L"in_dshow.dll", false }, // load after in_avi and in_mkv as often those extensions are associated with this one as well
+ { L"in_flac.dll", false },
+ { L"in_flv.dll", false },
+ { L"in_wm.dll", false },
+
+ // tend to have a lot of extensions so do later
+ { L"in_wave.dll", false },
+ { L"in_midi.dll", false },
+ { L"in_mod.dll", false }
+};
+
+static void LoadInputPlugin(const wchar_t* filename)
+{
+ wchar_t file[MAX_PATH] = { 0 };
+ PathCombineW(file, PLUGINDIR, filename);
+
+ HINSTANCE hLib = LoadLibraryW(file);
+ if ( hLib == NULL )
+ return;
+
+
+ In_Module* (*pr)();
+ pr = (In_Module * (__cdecl*)(void)) GetProcAddress(hLib, "winampGetInModule2");
+ if ( pr == NULL )
+ return;
+
+
+ In_Module* mod = pr();
+ if ( mod == NULL )
+ {
+ FreeModule(hLib);
+ return;
+ }
+
+
+ int ver = ((mod->version & ~IN_UNICODE) & ~IN_INIT_RET);
+ if ( !(ver == IN_VER || ver == IN_VER_OLD) )
+ {
+ FreeModule(hLib);
+ return;
+ }
+
+
+ if ( g_safeMode )
+ {
+ char desc[128] = { 0 };
+ lstrcpynA(desc, mod->description, sizeof(desc));
+ if ( desc[0] && !memcmp(desc, "nullsoft(", 9) )
+ {
+ char* p = strrchr(desc, ')');
+ if ( p )
+ {
+ *p = 0;
+ if ( _wcsicmp(filename, AutoWide(desc + 9)) )
+ {
+ FreeModule(hLib);
+ return;
+ }
+ }
+ }
+ else
+ {
+ FreeModule(hLib);
+ return;
+ }
+ }
+
+ mod->hDllInstance = hLib;
+ mod->dsp_dosamples = eq_dosamples;
+ mod->dsp_isactive = eq_isactive;
+ mod->SAGetMode = sa_getmode;
+ mod->SAAdd = (int(__cdecl*)(void*, int, int))sa_add;
+ mod->SAVSAInit = vissa_init;
+ mod->SAVSADeInit = vissa_deinit;
+ mod->VSASetInfo = vis_setinfo;
+ mod->VSAAdd = vsa_add;
+ mod->VSAGetMode = vsa_getmode;
+ mod->SAAddPCMData = sa_addpcmdata;
+ mod->VSAAddPCMData = vsa_addpcmdata;
+ mod->hMainWindow = hMainWindow;
+ mod->SetInfo = NULL;
+ mod->UsesOutputPlug &= ~(2 | 4 | 8 | 16);
+
+ if ( !_wcsicmp(filename, L"in_mjf.dll") )
+ {
+ mod->IsOurFile = myisourfile;
+ }
+
+ // add 5.66+ to do better error handling on issues, etc
+ if ( mod->version & IN_INIT_RET )
+ {
+ mod->service = WASABI_API_SVC;
+ }
+ int ret = mod->Init();
+ if ( (mod->version & IN_INIT_RET) && (ret == IN_INIT_FAILURE) )
+ {
+ FreeModule(hLib);
+ return;
+ }
+
+ in_modules.push_back(mod);
+
+ if ( mod->SetInfo )
+ {
+ char* p = (char*)mod->SetInfo;
+ if ( p && *p )
+ {
+ StringCchCatA(metric_plugin_list, 512, ":");
+ StringCchCatA(metric_plugin_list, 512, p);
+ }
+ }
+
+ mod->SetInfo = setinfo;
+
+ if ( !g_has_video_plugin )
+ {
+ int (*gefiW)(const wchar_t* fn, const char* data, wchar_t* dest, int destlen);
+ gefiW = (int(__cdecl*)(const wchar_t*, const char*, wchar_t*, int))GetProcAddress(hLib, "winampGetExtendedFileInfoW");
+ if ( gefiW )
+ {
+ wchar_t dest[16] = { 0 };
+ gefiW(L"", "type", dest, 16);
+ if ( _wtoi(dest) == 1 ) g_has_video_plugin = 1;
+ }
+
+ int (*gefi)(const char* fn, const char* data, char* dest, int destlen);
+ gefi = (int(__cdecl*)(const char*, const char*, char*, int))GetProcAddress(hLib, "winampGetExtendedFileInfo");
+ if ( gefi )
+ {
+ char dest[16] = { 0 };
+ gefi("", "type", dest, 16);
+ if ( atoi(dest) == 1 ) g_has_video_plugin = 1;
+ }
+ }
+}
+
+int in_init()
+{
+ // input plugins require the main window, at least for IPC calls
+ if ( !CreateMainWindow() )
+ return FALSE;
+
+ int i = 0, count = sizeof(preload) / sizeof(PLUGINORDER);
+
+ for ( ; i < count; i++ )
+ LoadInputPlugin(preload[i].name);
+
+ WIN32_FIND_DATAW d = { 0 };
+ wchar_t dirstr[MAX_PATH] = { 0 };
+
+ PathCombineW(dirstr, PLUGINDIR, L"IN_*.DLL");
+ HANDLE h = FindFirstFileW(dirstr, &d);
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ for ( i = 0; i < count && (preload[i].found || lstrcmpiW(preload[i].name, d.cFileName)); i++ );
+ if ( i == count ) LoadInputPlugin(d.cFileName);
+ else preload[i].found = true;
+ } while ( FindNextFileW(h, &d) );
+ FindClose(h);
+ }
+
+ if ( (g_no_video_loaded = _r_i("no_video", 0)) ) g_has_video_plugin = 0;
+
+ return TRUE;
+}
+
+In_Module* g_in_infobox = 0;
+
+void in_deinit()
+{
+ size_t x = in_modules.size();
+ while ( x-- )
+ {
+ In_Module*& mod = in_modules[x];
+ // make sure there's something valid due to the dynamic unload changes in 5.5+
+ if ( mod != g_in_infobox && mod )
+ {
+ //HINSTANCE hLib = mod->hDllInstance;
+ mod->Quit();
+
+ //FreeLibrary(hLib); // benski> we're just going to let it leak because it might be subclassing
+ mod = 0;
+ }
+ }
+ in_modules.clear();
+}
+
+In_Module* in_setmod_noplay(const wchar_t* filename, int* start_offs)
+{
+ size_t x;
+ char ext[128] = { 0 };
+ extension_ex(AutoChar(filename), ext, sizeof(ext));
+ for ( x = start_offs ? *start_offs : 0; x < in_modules.size(); x++ )
+ {
+ if ( InW_IsOurFile(in_modules[x], filename) )
+ {
+ if ( start_offs )
+ *start_offs = (int)x;
+
+ if ( !in_modules[x]->hMainWindow )
+ in_modules[x]->hMainWindow = hMainWindow;
+
+ return in_modules[x];
+ }
+ }
+ for ( x = start_offs ? *start_offs : 0; x < in_modules.size(); x++ )
+ {
+ if ( in_modules[x] )
+ {
+ char* allExtension = in_modules[x]->FileExtensions;
+ while ( allExtension && *allExtension )
+ {
+ char* splitterBuffer = allExtension;
+ char* extensionBuffer;
+ do
+ {
+ // string split on ';'
+ char currentExtension[20] = { 0 };
+ lstrcpynA(currentExtension, splitterBuffer, 20);
+ if ( (extensionBuffer = strstr(splitterBuffer, ";")) )
+ {
+ if ( (extensionBuffer - splitterBuffer) < 15 )
+ currentExtension[extensionBuffer - splitterBuffer] = 0;
+ }
+ //else
+ //d[lstrlen(splitterBuffer)] = 0;
+
+ if ( !lstrcmpiA(ext, currentExtension) )
+ {
+ if ( start_offs )
+ *start_offs = (int)x;
+ if ( !in_modules[x]->hMainWindow )
+ in_modules[x]->hMainWindow = hMainWindow;
+
+ return in_modules[x];
+ }
+ splitterBuffer = extensionBuffer + 1;
+ } while ( extensionBuffer );
+
+ allExtension += lstrlenA(allExtension) + 1;
+
+ if ( !*allExtension )
+ break;
+
+ allExtension += lstrlenA(allExtension) + 1;
+ }
+ }
+ }
+
+ if ( start_offs )
+ {
+ *start_offs = -1;
+ return 0;
+ }
+
+ {
+ static int r;
+ const wchar_t* p;
+
+ if ( PathFindExtensionW(filename)[0] && (p = wcsstr(filename, L"://")) && (p = wcsstr(p, L"?")) )
+ {
+ wchar_t* d = _wcsdup(filename);
+ In_Module* v;
+ d[p - filename] = 0;
+ v = in_setmod_noplay(d, 0);
+ free(d);
+ return v;
+ }
+
+ if ( !config_defext[0] || config_defext[0] == ' ' )
+ StringCchCopyA(config_defext, 32, "mp3");
+
+ if ( !r )
+ {
+ wchar_t a[128] = L"hi.";
+ In_Module* v;
+ MultiByteToWideCharSZ(CP_ACP, 0, config_defext, -1, a + 3, 120);
+ r = 1;
+ v = in_setmod_noplay(a, 0);
+ r = 0;
+ return v;
+ }
+ else
+ return 0;
+ }
+}
+
+In_Module* in_setmod(const wchar_t* filename)
+{
+ In_Module* i = in_setmod_noplay(filename, 0);
+ if ( !i ) return 0;
+ if ( i->UsesOutputPlug & IN_MODULE_FLAG_USES_OUTPUT_PLUGIN )
+ {
+ int t;
+ for ( t = 0; out_modules[t] && _stricmp(config_outname, (char*)out_modules[t]->id); t++ );
+ if ( !out_modules[t] )
+ {
+ for ( t = 0; out_modules[t]; t++ )
+ {
+ if ( !_stricmp("out_ds.dll", (char*)out_modules[t]->id) )
+ {
+ break;
+ }
+ else if ( !_stricmp("out_wave.dll", (char*)out_modules[t]->id) )
+ {
+ break;
+ }
+ }
+
+ if ( !out_modules[t] )
+ {
+ LPMessageBox(DIALOG_PARENT(hMainWindow), IDS_NOOUTPUT, IDS_ERROR, MB_OK | MB_ICONERROR);
+ return (In_Module*)-31337;
+ }
+ }
+
+ // TODO only call out_changed(..) if we are different from before
+ // though currently changing the output prefs and playing a
+ // new track will generate a change (which is expected but
+ // it might be assumed to be wrong so may need to document)
+ int changed = 0;
+ if ( !i->outMod || i->outMod && i->outMod->hDllInstance != out_modules[t]->hDllInstance )
+ {
+ changed = 1;
+ if ( i->outMod ) out_changed(i->outMod->hDllInstance, OUT_UNSET | OUT_PLAYBACK);
+ }
+ i->outMod = out_modules[t];
+ i->outMod->hMainWindow = hMainWindow;
+ if ( changed ) out_changed(i->outMod->hDllInstance, OUT_SET | OUT_PLAYBACK);
+ }
+ else
+ {
+ if ( i->outMod ) out_changed(i->outMod->hDllInstance, OUT_UNSET | OUT_PLAYBACK);
+ i->outMod = NULL;
+ }
+ return i;
+}
+
+void in_flush(int ms)
+{
+ if ( in_mod && in_mod->outMod )
+ {
+ in_mod->outMod->Flush(ms);
+ }
+}
+
+int in_getouttime(void)
+{
+ if ( in_mod ) return in_mod->GetOutputTime();
+ return 0;
+}
+
+int in_getlength(void)
+{
+ if ( in_mod )
+ {
+ int t = in_mod->GetLength() / 1000;
+ if ( t < 1 && t != -1 )
+ t = 1;
+
+ return t;
+ }
+
+ return -1;
+}
+
+void in_pause(int p)
+{
+ if ( in_mod )
+ {
+ if ( p )
+ in_mod->Pause();
+ else
+ in_mod->UnPause();
+ }
+}
+
+void in_setvol(int v)
+{
+ if ( in_mod )
+ in_mod->SetVolume(v);
+
+ if ( config_eq_ws && config_eq_open )
+ draw_eq_tbar(GetForegroundWindow() == hEQWindow ? 1 : (config_hilite ? 0 : 1));
+
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_VOLUME, IPC_CB_MISC);
+
+
+ //////CefRefPtr<wa_Cef_App> l_CefApp = wa_Cef_App::GetInstance();
+
+ //////if ( l_CefApp.get() != nullptr )
+ //////{
+ ////// l_CefApp.get()->setVolume( v );
+ //////}
+
+}
+
+void in_setpan(int p)
+{
+ if ( in_mod )
+ in_mod->SetPan(p);
+
+ if ( config_eq_ws && config_eq_open )
+ draw_eq_tbar(GetForegroundWindow() == hEQWindow ? 1 : (config_hilite ? 0 : 1));
+
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_VOLUME, IPC_CB_MISC);
+}
+
+int in_seek(int time_in_ms)
+{
+ if ( in_mod )
+ in_mod->SetOutputTime(time_in_ms);
+
+ return 0;
+}
+
+extern "C" int g_need_trusted_dsp = 0;
+
+int in_open(const wchar_t* fn)
+{
+ in_mod = in_setmod(fn);
+ if ( (int)in_mod <= 0 ) return (!in_mod ? 1 : *(int*)in_mod);
+ sa_setthread(config_sa);
+ in_setvol(config_volume);
+ in_setpan(config_pan);
+
+ dsp_in_init = 0;
+ dsp_init_mod = in_mod;
+ filter_srate = 0;
+
+ int r = InW_Play(in_mod, fn);
+ return r;
+}
+
+void in_close(void)
+{
+ if ( in_mod )
+ in_mod->Stop();
+
+ if ( NULL != eq )
+ {
+ free(eq);
+ eq = NULL;
+ }
+
+ timingPrint();
+}
+
+enum FileInfoMode
+{
+ FILEINFO_MODE_0,
+ FILEINFO_MODE_1,
+};
+
+int ModernInfoBox(In_Module* in, FileInfoMode mode, const wchar_t* filename, HWND parent);
+typedef int(__cdecl* UseUnifiedFileInfoDlg)(const wchar_t* fn);
+
+int in_infobox(HWND hwnd, const wchar_t* fn)
+{
+ const wchar_t* p = wcsstr(fn, L"aol.com/uvox");
+ if ( p ) return 0;
+
+ if ( g_in_infobox ) return 0;
+
+ In_Module* mod = in_setmod_noplay(fn, 0);
+ if ( !mod ) return 0;
+
+ g_in_infobox = mod;
+
+ UseUnifiedFileInfoDlg uufid = (UseUnifiedFileInfoDlg)GetProcAddress(mod->hDllInstance, "winampUseUnifiedFileInfoDlg");
+
+ // focus often gets reverted back to the main window after this dialog
+ // so we will remember what window used to have focus
+ HWND oldFocus = GetFocus();
+ int a = 0;
+
+ int ret = 0;
+ if ( uufid ) {
+ ret = uufid(fn);
+ if ( ret == 1 ) {
+ a = ModernInfoBox(mod, FILEINFO_MODE_0, fn, hwnd);
+ }
+ else if ( ret == 2 )
+ a = ModernInfoBox(mod, FILEINFO_MODE_1, fn, hwnd);
+ }
+
+ if ( ret == 0 ) {
+ // added 5.66 so plug-ins can get a hint that something may change...
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)fn, IPC_FILE_TAG_MAY_UPDATEW);
+ a = InW_InfoBox(mod, fn, hwnd);
+ }
+
+ SetFocus(oldFocus);
+
+ if ( !a )
+ {
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)fn, IPC_FILE_TAG_MAY_HAVE_UPDATEDW);
+ }
+
+ g_in_infobox = 0;
+
+ return a;
+}
+
+static void AddFilterString(char* p, size_t size, const char* a)
+{
+ while ( a && *a )
+ {
+ char* t = 0;
+ StringCchCatExA(p, size, ";*.", &t, &size, 0);
+ t = p + lstrlenA(p);
+ while ( a && *a && *a != ';' ) *t++ = *a++;
+ *t = 0;
+ if ( a ) a++;
+
+ if ( a && a[-1] ) continue;
+ if ( !*a ) break;
+ if ( a ) a += lstrlenA(a) + 1;
+ }
+}
+
+char* in_getfltstr()
+{
+ int in_mod = -1;
+ int in_wave = -1;
+ size_t size = 256 * 1024;
+ char* buf = (char*)GlobalAlloc(GPTR, size); // this is gay, should have a growing buffer or somethin.
+ char* p = buf;
+ size_t x;
+ getString(IDS_ALLTYPES, p, size);
+ p = p + lstrlenA(p) + 1;
+ wchar_t playlistString[1024] = { 0 };
+ playlistManager->GetFilterList(playlistString, 1024);
+ WideCharToMultiByteSZ(CP_ACP, 0, playlistString, -1, p, (int)size, 0, 0);
+ for ( x = 0; x < in_modules.size(); x++ )
+ {
+ char* a = in_modules[x]->FileExtensions;
+ if ( a && *a )
+ {
+ /* we want to skip in_mod and in_wave because they have TOO MANY extensions and we are limited to MAX_PATH (260)
+ we'll tack them at the end just in case we have enough room for 'em */
+ if ( in_mod < 0 && !strncmp(a, "mod;", 4) )
+ in_mod = (int)x;
+ else if ( in_wave < 0 && strstr(a, "aiff") ) // detection for in_wave. not the best but should work
+ in_wave = (int)x;
+ else AddFilterString(p, size, a);
+ }
+ }
+
+ /* add in_wave and in_mod last */
+ if ( in_wave >= 0 )
+ AddFilterString(p, size, in_modules[in_wave]->FileExtensions);
+
+ if ( in_mod >= 0 ) // fuck you in_mod :)
+ AddFilterString(p, size, in_modules[in_mod]->FileExtensions);
+
+ p = p + lstrlenA(p) + 1;
+ getString(IDS_PLAYLISTSTRING, p, size - (p - buf));
+ p += lstrlenA(p) + 1;
+ playlistManager->GetFilterList(playlistString, 1024);
+ WideCharToMultiByteSZ(CP_ACP, 0, playlistString, -1, p, (int)size, 0, 0);
+ p += lstrlenA(p) + 1;
+ for ( x = 0; x < in_modules.size(); x++ )
+ {
+ char* a = in_modules[x]->FileExtensions;
+ while ( a && *a )
+ {
+ char* b = a;
+ a += lstrlenA(a) + 1;
+ if ( !*a ) break;
+ StringCchCopyExA(p, size, a, &p, &size, 0);
+ p++;
+ {
+ do
+ {
+ char* c;
+ StringCchCopyA(p, size, "*.");
+ StringCchCatA(p, size, b);
+ if ( (b = strstr(b, ";")) ) b++;
+ if ( (c = strstr(p, ";")) ) c[1] = 0;
+
+ p += lstrlenA(p);
+ } while ( b );
+ p++;
+ a += lstrlenA(a) + 1;
+ }
+ }
+ }
+ StringCchCopyExA(p, size, getString(IDS_OFD_ALL_FILES, NULL, 0), &p, &size, 0);
+ p++; size--;
+ lstrcpynA(p, "*.*", (int)size);
+ p += 3;
+ *p = 0;
+
+ {
+ char* newbuf;
+ size = p + 5 - buf;
+ newbuf = (char*)GlobalAlloc(GPTR, size);
+ memcpy(newbuf, buf, size);
+ GlobalFree(buf);
+ return newbuf;
+ }
+}
+
+static void AddFilterStringW(wchar_t* p, size_t& size, const char* a, BOOL skip)
+{
+ while ( a && *a )
+ {
+ wchar_t* t = 0;
+ StringCchCatExW(p, size, ((*p) ? L";*." : L"*."), &t, &size, 0);
+ size_t extsize = 0;
+ while ( a[extsize] && a[extsize] != ';' )
+ extsize++;
+
+ *(t += MultiByteToWideCharSZ(CP_ACP, 0, a, (int)extsize, t, (int)size) - 1);
+ a += extsize + 1;
+
+ if ( a[-1] ) continue;
+ if ( !*a ) break;
+ a += lstrlenA(a) + 1;
+
+ // limit the length of the filter to fit into MAX_PATH otherwise
+ // if things go past this then mainly for the all supported type
+ // it can sometimes act like *.* due to where the filter is cut
+ if ( !skip && lstrlenW(p) >= MAX_PATH )
+ {
+ // if we end with a . then need to fake things to act like a new
+ // filter since windows will interpret the . as a *.* which is bad
+ if ( *(p + MAX_PATH) == L'.' )
+ {
+ *(p + MAX_PATH - 1) = 0;
+ *(p + MAX_PATH) = 0;
+ }
+ }
+ }
+}
+
+static wchar_t* inc(wchar_t* p, size_t& size, int extra = 0)
+{
+ int len = lstrlenW(p) + extra;
+ size -= len;
+ p += len;
+ return p;
+}
+
+wchar_t* in_getfltstrW(BOOL skip)
+{
+ int in_mod = -1;
+ int in_wave = -1;
+ size_t size = 256 * 1024;
+ wchar_t* buf = (wchar_t*)GlobalAlloc(GPTR, size * sizeof(wchar_t)); // this is gay, should have a growing buffer or somethin.
+ wchar_t* p = buf, * ps;
+ *p = 0;
+ size_t x = 0;
+
+ {
+ int cnt = lstrlenW(getStringW(IDS_ALLTYPES, buf, size)) + 1;
+ p += cnt; size -= cnt;
+ if ( playlistManager )
+ {
+ playlistManager->GetExtensionList(p, size);
+ size -= lstrlenW(p);
+ }
+ }
+ ps = p;
+
+ for ( x = 0; x < in_modules.size(); x++ )
+ {
+ char* a = in_modules[x]->FileExtensions;
+ if ( a && *a )
+ {
+ /* we want to skip in_mod and in_wave because they have TOO MANY extensions and we are limited to MAX_PATH (260)
+ we'll tack them at the end just in case we have enough room for 'em */
+ if ( in_mod < 0 && !strncmp(a, "mod;", 4) )
+ in_mod = (int)x;
+ else if ( in_wave < 0 && strstr(a, "aiff") ) // detection for in_wave. not the best but should work
+ in_wave = (int)x;
+ else AddFilterStringW(p, size, a, skip);
+ }
+ }
+
+ /* add in_wave and in_mod last */
+ if ( in_wave >= 0 )
+ AddFilterStringW(p, size, in_modules[in_wave]->FileExtensions, skip);
+
+ if ( in_mod >= 0 ) // fuck you in_mod :)
+ AddFilterStringW(p, size, in_modules[in_mod]->FileExtensions, skip);
+
+ if ( *p )
+ p += lstrlenW(p) + 1; // don't decrement size here cause it was done already
+
+ // uppercase the extensions so is consistent as can be
+ CharUpperBuffW(ps, 256 * 1024 - (p - ps));
+
+ if ( playlistManager )
+ {
+ wchar_t ext[512] = { 0 };
+ playlistManager->GetExtensionList(ext, 512);
+ StringCchPrintfW(p, size, getStringW(IDS_PLAYLISTSTRING_NEW, NULL, 0), ext);
+ int cnt = lstrlenW(p) + 1;
+ p += cnt; size -= cnt;
+ StringCchCatW(p, size, ext);
+ p = inc(p, size, 1);
+ }
+
+ for ( x = 0; x < in_modules.size(); x++ )
+ {
+ char* a = in_modules[x]->FileExtensions;
+ while ( a && *a )
+ {
+ char* b = a;
+ a += lstrlenA(a) + 1;
+ if ( !*a ) break;
+ // adjust down by 1 so that we have the actual string length exluding null termination
+ int cnt = MultiByteToWideCharSZ(CP_ACP, 0, a, -1, p, (int)size) - 1;
+ p += cnt; size -= cnt;
+ {
+ do
+ {
+ wchar_t* c = 0;
+ StringCchCopyW(p, size, L"*.");
+ StringCchCatW(p, size, AutoWide(b));
+ if ( (b = strstr(b, ";")) ) b++;
+ if ( (c = wcsstr(p, L";")) ) c[1] = 0;
+
+ p = inc(p, size);
+ } while ( b );
+ p++;
+ size--;
+ a += lstrlenA(a) + 1;
+ }
+ }
+ }
+ StringCchCopyExW(p, size, getStringW(IDS_OFD_ALL_FILES, NULL, 0), &p, &size, 0);
+ p++; size--;
+ lstrcpynW(p, L"*.*", (int)size);
+ p += 3;
+ *p = 0;
+
+ {
+ wchar_t* newbuf = 0;
+ size = p + 5 - buf;
+ newbuf = (wchar_t*)GlobalAlloc(GPTR, size * sizeof(wchar_t));
+ memcpy(newbuf, buf, size * sizeof(wchar_t));
+ GlobalFree(buf);
+ return newbuf;
+ }
+}
+
+char* in_getextlist()
+{
+ size_t x;
+ char* mem = NULL, * p;
+ int size = 1024;
+ std::vector<LPSTR> exts;
+
+ for ( x = 0; x != in_modules.size(); x++ )
+ {
+ char* a = in_modules[x]->FileExtensions;
+ while ( a && *a )
+ {
+ char* b = a, * c = 0;
+ do
+ {
+ c = strstr(b, ";");
+ if ( c )
+ {
+ char temp[32] = { 0 };
+ lstrcpynA(temp, b, c - b + 1);
+ int count = CharUpperBuffA(temp, ARRAYSIZE(temp));
+
+ bool skip = false;
+ for ( size_t i = 0; i < exts.size(); i++ )
+ {
+ if ( !stricmp(exts[i], temp) )
+ {
+ skip = true;
+ break;
+ }
+ }
+ if ( !skip )
+ {
+ exts.push_back(_strdup(temp));
+ size += count + 2;
+ }
+ }
+ else
+ {
+ char temp[32] = { 0 };
+ lstrcpynA(temp, b, c - b + 1);
+ int count = CharUpperBuffA(temp, ARRAYSIZE(temp));
+
+ bool skip = false;
+ for ( size_t i = 0; i < exts.size(); i++ )
+ {
+ if ( !stricmp(exts[i], temp) )
+ {
+ skip = true;
+ break;
+ }
+ }
+ if ( !skip )
+ {
+ exts.push_back(_strdup(temp));
+ size += count + 2;
+ }
+ }
+ b = c + 1;
+ } while ( c && *c );
+
+ a += lstrlenA(a) + 1;
+ if ( !*a ) break;
+ a += lstrlenA(a) + 1;
+ }
+ }
+
+
+ if ( size > 0 )
+ {
+ p = mem = (char*)GlobalAlloc(GPTR, size);
+
+ for ( x = 0; x != exts.size(); x++ )
+ {
+ char* e = exts[x];
+ if ( e && *e )
+ {
+ lstrcpynA(p, e, 32);
+ p += lstrlenA(p) + 1;
+ free(e);
+ }
+ }
+
+ *p = 0;
+ }
+
+ return mem;
+}
+
+wchar_t* in_getextlistW()
+{
+ size_t x = 0;
+ wchar_t* mem = NULL, * p = 0;
+ int size = 0;
+ std::vector<LPWSTR> exts;
+
+ for ( x = 0; x != in_modules.size(); x++ )
+ {
+ char* a = in_modules[x]->FileExtensions;
+ while ( a && *a )
+ {
+ char* b = a, * c;
+ do
+ {
+ wchar_t temp[32] = { 0 };
+ c = strstr(b, ";");
+ if ( c )
+ {
+ int count = MultiByteToWideChar(CP_ACP, 0, b, c - b, 0, 0);
+ MultiByteToWideChar(CP_ACP, 0, b, c - b, temp, count);
+ CharUpperBuffW(temp, ARRAYSIZE(temp));
+
+ bool skip = false;
+ for ( size_t i = 0; i < exts.size(); i++ )
+ {
+ if ( !wcsicmp(exts[i], temp) )
+ {
+ skip = true;
+ break;
+ }
+ }
+ if ( !skip )
+ {
+ exts.push_back(_wcsdup(temp));
+ size += count + 2;
+ }
+ }
+ else
+ {
+ int count = MultiByteToWideChar(CP_ACP, 0, b, -1, 0, 0);
+ MultiByteToWideChar(CP_ACP, 0, b, -1, temp, count);
+ CharUpperBuffW(temp, ARRAYSIZE(temp));
+
+ bool skip = false;
+ for ( size_t i = 0; i < exts.size(); i++ )
+ {
+ if ( !wcsicmp(exts[i], temp) )
+ {
+ skip = true;
+ break;
+ }
+ }
+ if ( !skip )
+ {
+ exts.push_back(_wcsdup(temp));
+ size += count + 2;
+ }
+ }
+ b = c + 1;
+ } while ( c && *c );
+
+ a += lstrlenA(a) + 1;
+ if ( !*a ) break;
+ a += lstrlenA(a) + 1;
+ }
+ }
+
+ if ( size > 0 )
+ {
+ p = mem = (wchar_t*)GlobalAlloc(GPTR, size * sizeof(wchar_t));
+
+ for ( x = 0; x != exts.size(); x++ )
+ {
+ wchar_t* e = exts[x];
+ if ( e && *e )
+ {
+ lstrcpynW(p, e, 32);
+ p += lstrlenW(p) + 1;
+ free(e);
+ }
+ }
+ *p = 0;
+ }
+
+ return mem;
+}
+
+static void vissa_init(int maxlatency_in_ms, int srate)
+{
+ g_srate_exact = srate;
+ int nf = MulDiv(maxlatency_in_ms * 4, srate, 450000);
+ //int nf = maxlatency_in_ms/5;
+ sa_init(nf);
+ vsa_init(nf);
+ vu_init(nf, srate);
+}
+
+static void vissa_deinit()
+{
+ sa_deinit();
+ vsa_deinit();
+ vu_deinit();
+}
+
+static void setinfo(int bitrate, int srate, int stereo, int synched)
+{
+ int last_brate = g_brate, last_srate = g_srate, last_nch = g_nch;
+
+ if ( stereo != -1 )
+ {
+ g_nch = stereo;
+ // dynamic channels
+ if ( g_nch > 0 )
+ {
+ if ( NULL != eq ) { free(eq); eq = NULL; }
+ eq = (eq10_t*)calloc(g_nch, sizeof(eq10_t));
+ if ( NULL == eq )
+ {
+ // bad. Need to handle this.
+ g_nch = 0;
+ }
+ eq_set(config_use_eq, (char*)eq_tab, config_preamp);
+ }
+ }
+
+ if ( bitrate != -1 && srate != -1 )
+ {
+ g_need_titleupd = 1;
+ }
+
+ if ( bitrate != -1 )
+ g_brate = bitrate;
+ if ( srate != -1 )
+ {
+ g_srate = srate;
+ switch ( srate )
+ {
+ case 11:
+ g_srate_exact = 11025; break;
+ case 22:
+ g_srate_exact = 22050; break;
+ case 44:
+ g_srate_exact = 44100; break;
+ case 88:
+ g_srate_exact = 88200; break;
+ default:
+ g_srate_exact = srate * 1000; break;
+ }
+ }
+
+ if ( bitrate != -1 || srate != -1 || stereo != -1 )
+ {
+ static unsigned int last_t;
+ unsigned int now = GetTickCount();
+
+ //detect wrap with the first one
+ if ( now < last_t || now > last_t + 500 || last_brate != g_brate || last_srate != g_srate || last_nch != g_nch )
+ {
+ last_t = now;
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC);
+ }
+ }
+
+ if ( synched != -1 || stereo != -1 )
+ {
+ g_need_infoupd = synched | (stereo != -1 ? 8 : 4) | (g_need_infoupd & 8);
+ }
+}
+
+static int sa_getmode()
+{
+ if ( sa_override ) return 3;
+
+ if ( sa_curmode == 4 && !config_mw_open && config_pe_open )
+ return 1;
+ return sa_curmode;
+}
+
+static int eq_isactive()
+{
+ int r = dsp_isactive();
+ if ( r ) return 1;
+ if ( in_mod && !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool() && (config_replaygain_non_rg_gain.GetFloat() != 0) ) return 1;
+ if ( in_mod && !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool() && (config_replaygain_preamp.GetFloat() != 0) ) return 1;
+ if ( filter_enabled ) return 2;
+ return 0;
+}
+
+static float eq_lookup1[64] = {
+ 4.000000f, 3.610166f, 3.320019f, 3.088821f, 2.896617f,
+ 2.732131f, 2.588368f, 2.460685f, 2.345845f, 2.241498f,
+ 2.145887f, 2.057660f, 1.975760f, 1.899338f, 1.827707f,
+ 1.760303f, 1.696653f, 1.636363f, 1.579094f, 1.524558f,
+ 1.472507f, 1.422724f, 1.375019f, 1.329225f, 1.285197f,
+ 1.242801f, 1.201923f, 1.162456f, 1.124306f, 1.087389f,
+ 1.051628f, 1.000000f, 0.983296f, 0.950604f, 0.918821f,
+ 0.887898f, 0.857789f, 0.828454f, 0.799853f, 0.771950f,
+ 0.744712f, 0.718108f, 0.692110f, 0.666689f, 0.641822f,
+ 0.617485f, 0.593655f, 0.570311f, 0.547435f, 0.525008f,
+ 0.503013f, 0.481433f, 0.460253f, 0.439458f, 0.419035f,
+ 0.398970f, 0.379252f, 0.359868f, 0.340807f, 0.322060f,
+ 0.303614f, 0.285462f, 0.267593f, 0.250000f
+};
+
+///////////////// EQ CODE /////////////////////////
+
+static int __inline float_to_int(double a)
+{
+ a += ((((65536.0 * 65536.0 * 16) + (65536.0 * 0.5)) * 65536.0));
+ return ((*(int*)&a) - 0x80000000);
+}
+
+float* splbuf = 0;
+int splbuf_alloc = 0;
+float eqt[10] = { 0 };
+
+static void FillFloat(float* floatBuf, void* samples, size_t bps, size_t numSamples, size_t numChannels, float preamp)
+{
+ nsutil_pcm_IntToFloat_Interleaved_Gain(floatBuf, samples, (int)bps, numSamples * numChannels, preamp);
+}
+
+static void FillSamples(void* samples, float* floatBuf, size_t bps, size_t numSamples, size_t numChannels)
+{
+ nsutil_pcm_FloatToInt_Interleaved(samples, floatBuf, (int)bps, numSamples * numChannels);
+}
+
+static float NonReplayGainAdjust()
+{
+ if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool() )
+ return pow(10.0f, (float)config_replaygain_non_rg_gain / 20.0f);
+ else
+ return 1.0f;
+}
+
+static float ReplayGainPreamp()
+{
+ if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool() )
+ return pow(10.0f, (float)config_replaygain_preamp / 20.0f);
+ else
+ return 1.0f;
+}
+
+static int eq_dosamples_4front(short* samples, int numsamples, int bps, int nch, int srate)
+{
+ g_srate_exact = srate;
+ //char *csamples = (char *)samples;
+ short* oldsamples = samples;
+
+ if ( filter_enabled && in_mod && !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_EQ) )
+ {
+ if ( !eq || filter_srate != srate )
+ {
+ if ( !eq ) eq = (eq10_t*)calloc(nch, sizeof(eq10_t));
+ eq10_setup(eq, nch, (float)srate); // initialize
+ for ( int x = 0; x < 10; x++ )
+ eq10_setgain(eq, nch, x, eqt[x]);
+ filter_srate = srate;
+ }
+ if ( splbuf_alloc < numsamples * nch )
+ {
+ int new_splbuf_alloc = numsamples * nch;
+ float* new_splbuf = (float*)realloc(splbuf, 2 * sizeof(float) * new_splbuf_alloc);
+ if ( new_splbuf )
+ {
+ splbuf_alloc = new_splbuf_alloc;
+ splbuf = new_splbuf;
+ }
+ }
+ if ( splbuf && eq )
+ {
+ int y = nch * numsamples;
+ FillFloat(splbuf, samples, bps, numsamples, nch, preamp_val * NonReplayGainAdjust() * ReplayGainPreamp());
+ for ( int x = 0; x < nch; x++ )
+ {
+ eq10_processf(eq + x, splbuf, splbuf + y, numsamples, x, nch);
+ }
+ FillSamples(samples, splbuf + y, bps, numsamples, nch);
+ }
+ }
+ else if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool() && (config_replaygain_non_rg_gain.GetFloat() != 0) )
+ {
+ if ( splbuf_alloc < numsamples * nch )
+ {
+ int new_splbuf_alloc = numsamples * nch;
+ float* new_splbuf = (float*)realloc(splbuf, 2 * sizeof(float) * new_splbuf_alloc);
+ if ( new_splbuf )
+ {
+ splbuf_alloc = new_splbuf_alloc;
+ splbuf = new_splbuf;
+ }
+ }
+ if ( splbuf )
+ {
+ FillFloat(splbuf, samples, bps, numsamples, nch, NonReplayGainAdjust() * ReplayGainPreamp());
+ FillSamples(samples, splbuf, bps, numsamples, nch);
+ }
+ }
+ else if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool() && (config_replaygain_preamp.GetFloat() != 0) )
+ {
+ if ( splbuf_alloc < numsamples * nch )
+ {
+ int new_splbuf_alloc = numsamples * nch;
+ float* new_splbuf = (float*)realloc(splbuf, 2 * sizeof(float) * new_splbuf_alloc);
+ if ( new_splbuf )
+ {
+ splbuf_alloc = new_splbuf_alloc;
+ splbuf = new_splbuf;
+ }
+ }
+ if ( splbuf )
+ {
+ FillFloat(splbuf, samples, bps, numsamples, nch, ReplayGainPreamp());
+ FillSamples(samples, splbuf, bps, numsamples, nch);
+ }
+ }
+ else
+ filter_srate = 0;
+ return dsp_dosamples(oldsamples, numsamples, bps, nch, srate);
+}
+
+static __inline double VALTODB(int v)
+{
+ v -= 31;
+ if ( v < -31 ) v = -31;
+ if ( v > 32 ) v = 32;
+
+ if ( v > 0 ) return -12.0 * (v / 32.0);
+ else if ( v < 0 )
+ {
+ return -12.0 * (v / 31.0);
+ }
+ return 0.0f;
+}
+
+static void eq_set_4front(char data[10])
+{
+ if ( !eq )
+ return;
+
+ for ( int x = 0; x < 10; x++ )
+ {
+ eqt[x] = (float)VALTODB(data[x]);
+ if ( filter_srate ) eq10_setgain(eq, g_nch, x, eqt[x]);
+ }
+}
+
+static bool eq_do_first = true;
+static int startup_config_eq_type = EQ_TYPE_4FRONT;
+void benskiQ_eq_set(char data[10]);
+void eq_set(int on, char data[10], int preamp)
+{
+ if ( eq_do_first )
+ {
+ startup_config_eq_type = config_eq_type;
+ eq_do_first = false;
+ }
+
+ int x;
+ if ( in_mod && in_mod->EQSet ) in_mod->EQSet(on, data, preamp);
+
+ for ( x = 9; x >= 0 && data[x] == 31; x++ );
+ if ( x >= 0 )
+ filter_top2 = x;
+
+ for ( x = 0; x < 10 && data[x] == 31; x++ );
+ if ( !on || (preamp == 31 && x == 10) )
+ {
+ filter_enabled = 0;
+ }
+ else filter_enabled = 1;
+ preamp_val = (float)eq_lookup1[preamp];
+
+ if ( startup_config_eq_type == EQ_TYPE_4FRONT )
+ eq_set_4front(data);
+ if ( startup_config_eq_type == EQ_TYPE_CONSTANT_Q )
+ benskiQ_eq_set(data);
+}
+
+static int eq_dosamples(short* samples, int numsamples, int bps, int nch, int srate)
+{
+ if ( eq_do_first )
+ {
+ startup_config_eq_type = config_eq_type;
+ eq_do_first = false;
+ }
+ if ( startup_config_eq_type == EQ_TYPE_4FRONT )
+ return eq_dosamples_4front(samples, numsamples, bps, nch, srate);
+ else
+ return benskiQ_eq_dosamples(samples, numsamples, bps, nch, srate);
+} \ No newline at end of file
diff --git a/Src/Winamp/InW.cpp b/Src/Winamp/InW.cpp
new file mode 100644
index 00000000..16cf0d2a
--- /dev/null
+++ b/Src/Winamp/InW.cpp
@@ -0,0 +1,52 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description: Unicode<->ANSI conversion layer for input plugins
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+#include "main.h"
+#include "../nu/AutoCharFn.h"
+#include "../nu/ns_wc.h"
+
+
+int InW_IsOurFile(In_Module *mod, const wchar_t *filename)
+{
+ if(mod)
+ {
+ if (mod->version & IN_UNICODE)
+ return mod->IsOurFile((in_char *)filename);
+ else
+ return mod->IsOurFile((in_char *)(char *)AutoCharFn(filename));
+ }
+ return 0;
+}
+
+int InW_Play(In_Module *mod, const wchar_t *filename)
+{
+ if (mod->version & IN_UNICODE)
+ return mod->Play((in_char *)filename);
+ else
+ return mod->Play((in_char *)(char *)AutoCharFn(filename));
+}
+
+int InW_InfoBox(In_Module *mod, const wchar_t *filename, HWND parent)
+{
+ if (mod->version & IN_UNICODE)
+ return mod->InfoBox((in_char *)filename, parent);
+ else
+ return mod->InfoBox((in_char *)(char *)AutoCharFn(filename), parent);
+}
+
+void InW_GetFileInfo(In_Module *mod, const wchar_t *filename, wchar_t *title, int *length)
+{
+ if (mod->version & IN_UNICODE)
+ mod->GetFileInfo((in_char *)filename, (in_char *)title, length);
+ else
+ {
+ char tempTitle[GETFILEINFO_TITLE_LENGTH]="";
+ mod->GetFileInfo((in_char *)(char *)AutoCharFn(filename), tempTitle, length);
+ MultiByteToWideCharSZ(CP_ACP, 0, tempTitle, -1, title, GETFILEINFO_TITLE_LENGTH);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/InflateObject.cpp b/Src/Winamp/InflateObject.cpp
new file mode 100644
index 00000000..34ab4947
--- /dev/null
+++ b/Src/Winamp/InflateObject.cpp
@@ -0,0 +1,72 @@
+#include "main.h"
+#include "InflateObject.h"
+#include "zlib/unzip.h"
+
+int ZLIBInflate::Reset(void *strm)
+{
+ return ::inflateReset((z_streamp)strm);
+}
+
+int ZLIBInflate::Init(void *strm,const char *version, int stream_size)
+{
+ return ::inflateInit_((z_streamp)strm, version, stream_size);
+}
+
+int ZLIBInflate::Init2(void *strm,int windowBits,const char *version, int stream_size)
+{
+ return ::inflateInit2_((z_streamp)strm, windowBits,version, stream_size);
+}
+
+int ZLIBInflate::Inflate(void *strm, int flush)
+{
+ return ::inflate((z_streamp)strm, flush);
+}
+
+int ZLIBInflate::End(void *strm)
+{
+return ::inflateEnd((z_streamp)strm);
+}
+
+unsigned long ZLIBInflate::CRC32(unsigned long crc, const unsigned char *buf, unsigned int len)
+{
+ return ::crc32(crc, buf, len);
+}
+
+int ZLIBInflate::deflateReset(void *strm)
+{
+ return ::deflateReset((z_streamp)strm);
+}
+
+int ZLIBInflate::deflateInit2_(void *strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)
+{
+ return ::deflateInit2_((z_streamp)strm, level, method, windowBits, memLevel, strategy, version, stream_size);
+}
+
+int ZLIBInflate::deflateEnd(void *strm)
+{
+ return ::deflateEnd((z_streamp)strm);
+}
+
+int ZLIBInflate::deflate(void *strm, int flush)
+{
+ return ::deflate((z_streamp)strm, flush);
+}
+
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS ZLIBInflate
+START_DISPATCH;
+ CB(API_INFLATE_INFLATERESET, Reset);
+ CB(API_INFLATE_INFLATEINIT, Init);
+ CB(API_INFLATE_INFLATEINIT2, Init2);
+ CB(API_INFLATE_INFLATE, Inflate);
+ CB(API_INFLATE_INFLATEEND, End);
+ CB(API_INFLATE_CRC32, CRC32);
+ CB(API_INFLATE_DEFLATERESET, deflateReset);
+ CB(API_INFLATE_DEFLATEINIT2, deflateInit2_);
+ CB(API_INFLATE_DEFLATEEND, deflateEnd);
+ CB(API_INFLATE_DEFLATE, deflate);
+END_DISPATCH;
diff --git a/Src/Winamp/InflateObject.h b/Src/Winamp/InflateObject.h
new file mode 100644
index 00000000..bda99898
--- /dev/null
+++ b/Src/Winamp/InflateObject.h
@@ -0,0 +1,28 @@
+#ifndef NULLSOFT_WINAMP_INFLATEOBJECT_H
+#define NULLSOFT_WINAMP_INFLATEOBJECT_H
+
+#include "api_inflate.h"
+
+class ZLIBInflate : public api_inflate
+{
+public:
+ static const char *getServiceName() { return "zlib inflate"; }
+ static const GUID getServiceGuid() { return inflateGUID; }
+public:
+ int Reset(void *strm);
+ int Init(void *strm, const char *version, int stream_size);
+ int Init2(void *strm, int windowBits, const char *version, int stream_size);
+ int Inflate(void *strm, int flush);
+ int End(void *strm);
+ unsigned long CRC32(unsigned long crc, const unsigned char *buf, unsigned int len);
+
+ int deflateReset(void *strm);
+ int deflateInit2_(void *strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size);
+ int deflate(void *strm, int flush);
+ int deflateEnd(void *strm);
+protected:
+ RECVS_DISPATCH;
+};
+
+extern ZLIBInflate *zlibInflate;
+#endif \ No newline at end of file
diff --git a/Src/Winamp/IntAttribute.cpp b/Src/Winamp/IntAttribute.cpp
new file mode 100644
index 00000000..0ea225d4
--- /dev/null
+++ b/Src/Winamp/IntAttribute.cpp
@@ -0,0 +1,24 @@
+#include "main.h"
+#include "attributes.h"
+
+_int::_int()
+{
+ value = 0;
+}
+
+_int::_int(intptr_t defaultValue)
+{
+ value = defaultValue;
+}
+
+intptr_t _int::operator =(intptr_t uintValue)
+{
+ value = uintValue;
+ return value;
+}
+
+#define CBCLASS _int
+START_DISPATCH;
+CB(IFC_CONFIGITEM_GETINT, GetInt)
+CB(IFC_CONFIGITEM_GETFLOAT, GetFloat)
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Winamp/InternetConfigGroup.cpp b/Src/Winamp/InternetConfigGroup.cpp
new file mode 100644
index 00000000..0a625525
--- /dev/null
+++ b/Src/Winamp/InternetConfigGroup.cpp
@@ -0,0 +1,56 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "InternetConfigGroup.h"
+
+#include "../Agave/Config/ifc_configitem.h"
+#include "WinampAttributes.h"
+#include "../nu/ns_wc.h"
+
+class ProxyConfigItem : public ifc_configitem
+{
+public:
+ const wchar_t *GetString()
+ {
+ static wchar_t blah[256];
+ if (config_proxy[0])
+ MultiByteToWideCharSZ(CP_ACP, 0, config_proxy, -1, blah, 256);
+ else
+ return 0;
+ return blah;
+ }
+protected:
+ RECVS_DISPATCH;
+};
+
+#define CBCLASS ProxyConfigItem
+START_DISPATCH;
+CB(IFC_CONFIGITEM_GETSTRING, GetString)
+END_DISPATCH;
+#undef CBCLASS
+
+static ProxyConfigItem proxyConfigItem;
+
+ifc_configitem *InternetConfigGroup::GetItem(const wchar_t *name)
+{
+ if (!wcscmp(name, L"proxy"))
+ return &proxyConfigItem;
+ else if (!wcscmp(name, L"proxy80"))
+ return &config_proxy80;
+
+ return 0;
+}
+
+
+
+#define CBCLASS InternetConfigGroup
+START_DISPATCH;
+CB(IFC_CONFIGGROUP_GETITEM, GetItem)
+CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/InternetConfigGroup.h b/Src/Winamp/InternetConfigGroup.h
new file mode 100644
index 00000000..60b892d6
--- /dev/null
+++ b/Src/Winamp/InternetConfigGroup.h
@@ -0,0 +1,22 @@
+#ifndef NULLSOFT_WINAMP_INTERNETCONFIGGROUP_H
+#define NULLSOFT_WINAMP_INTERNETCONFIGGROUP_H
+
+#include "main.h"
+#include "../Agave/Config/ifc_configgroup.h"
+
+// {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C}
+static const GUID internetConfigGroupGUID =
+{ 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } };
+
+class InternetConfigGroup : public ifc_configgroup
+{
+public:
+ ifc_configitem *GetItem(const wchar_t *name);
+ GUID GetGUID() { return internetConfigGroupGUID; }
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern InternetConfigGroup internetConfigGroup;
+#endif \ No newline at end of file
diff --git a/Src/Winamp/JSAPI.h b/Src/Winamp/JSAPI.h
new file mode 100644
index 00000000..a870f081
--- /dev/null
+++ b/Src/Winamp/JSAPI.h
@@ -0,0 +1,36 @@
+#pragma once
+
+// helper functions for IDispatch
+#define JSAPI_PARAM_INDEX(paramInfo, paramNumber) (paramInfo->cArgs - paramNumber)
+#define JSAPI_PARAM_EXISTS(paramInfo, paramNumber) (paramInfo->cArgs >= paramNumber)
+#define JSAPI_NUM_PARAMS(paramInfo) (paramInfo->cArgs)
+#define JSAPI_VERIFY_PARAMCOUNT(paramInfo, count) if (paramInfo->cArgs != count) return DISP_E_BADPARAMCOUNT
+#define JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(paramInfo, minParams, maxParams) if (paramInfo->cArgs < minParams || paramInfo->cArgs > maxParams) return DISP_E_BADPARAMCOUNT
+#define JSAPI_VERIFY_PARAMTYPE(paramInfo, paramNumber, paramType, argErr) if (paramInfo->rgvarg[paramInfo->cArgs - paramNumber].vt != paramType) { *argErr = paramInfo->cArgs - paramNumber; return DISP_E_TYPEMISMATCH; }
+#define JSAPI_VERIFY_PARAMTYPE_OPTIONAL(paramInfo, paramNumber, paramType, argErr) if (JSAPI_PARAM_EXISTS(paramInfo, paramNumber) && paramInfo->rgvarg[paramInfo->cArgs - paramNumber].vt != paramType) { *argErr = paramInfo->cArgs - paramNumber; return DISP_E_TYPEMISMATCH; }
+#define JSAPI_GETSTRING(str, paramInfo, paramNumber, argErr) switch(paramInfo->rgvarg[paramInfo->cArgs - paramNumber].vt) { case VT_BSTR: str = paramInfo->rgvarg[paramInfo->cArgs - paramNumber].bstrVal; break; default: *argErr = paramInfo->cArgs - paramNumber; return DISP_E_TYPEMISMATCH; }
+#define JSAPI_GETNUMBER_AS_STRING(str, buffer, paramInfo, paramNumber, argErr) \
+ if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_I4) {\
+ int val_int = JSAPI_PARAM(paramInfo, paramNumber).lVal;\
+ StringCbPrintfW(buffer, sizeof(buffer), L"%d", val_int);\
+ str = buffer;\
+ } else if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_BSTR)\
+ str = JSAPI_PARAM(paramInfo, paramNumber).bstrVal;\
+ else {\
+ if (argErr) *argErr = paramInfo->cArgs - paramNumber;\
+ return DISP_E_TYPEMISMATCH;\
+ }
+#define JSAPI_GETUNSIGNED_AS_NUMBER(num, paramInfo, paramNumber, argErr) \
+ if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_I4) num = (UINT)JSAPI_PARAM(paramInfo, paramNumber).lVal;\
+ else if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_BSTR) num = wcstoul(JSAPI_PARAM(paramInfo, paramNumber).bstrVal,0, 10); \
+ else return DISP_E_TYPEMISMATCH;
+
+
+#define JSAPI_PARAM(paramInfo, paramNumber) (paramInfo->rgvarg[paramInfo->cArgs - paramNumber])
+#define JSAPI_PARAM_OPTIONAL(paramInfo, paramNumber, dispID, opt) (JSAPI_PARAM_EXISTS(paramInfo, paramNumber)?paramInfo->rgvarg[paramInfo->cArgs - paramNumber].##dispID:(opt))
+#define JSAPI_VERIFY_METHOD(flags) if (!(wFlags & DISPATCH_METHOD)) return DISP_E_MEMBERNOTFOUND
+#define JSAPI_INIT_RESULT(result, type) if (result) { VariantInit(result); V_VT(result) = type; }
+#define JSAPI_SET_RESULT(result, field, value) if (result) { (result)->field = value; }
+#define JSAPI_EMPTY_RESULT(result) if (result) { V_VT(result) = VT_EMPTY; }
+#define JSAPI_SET_VARIANT(result, macro, value) if (result) { macro(result) = value; }
+#define JSAPI_DISP_ENUMIFY(x) __jsapi__enum__ ## x
diff --git a/Src/Winamp/JSAPI2_Application.cpp b/Src/Winamp/JSAPI2_Application.cpp
new file mode 100644
index 00000000..ef067c4f
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Application.cpp
@@ -0,0 +1,197 @@
+#include "JSAPI2_Application.h"
+#include "main.h"
+#include "api.h"
+#include "language.h"
+#include "JSAPI.h"
+#include "JSAPI2_Security.h"
+
+JSAPI2::ApplicationAPI::ApplicationAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
+{
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+#define DISP_TABLE \
+ CHECK_ID(LaunchURL)\
+ CHECK_ID(version)\
+ CHECK_ID(versionstring)\
+ CHECK_ID(language)\
+ CHECK_ID(languagepack)\
+ CHECK_ID(settingspath)\
+
+#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
+enum {
+ DISP_TABLE
+};
+
+#undef CHECK_ID
+#define CHECK_ID(str)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
+
+HRESULT JSAPI2::ApplicationAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::ApplicationAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ApplicationAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+void CALLBACK OpenURLAPC(ULONG_PTR param);
+HRESULT JSAPI2::ApplicationAPI::LaunchURL(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BOOL, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+
+ if (security.GetActionAuthorization(L"application", L"launchurl", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ wchar_t scheme[16]=L"";
+ DWORD size = 16;
+ // make sure it's an HTTP url
+ if (PathIsURLW(url) && !UrlIsFileUrlW(url) && UrlGetPartW(url, scheme, &size, URL_PART_SCHEME, 0) == S_OK
+ && (!_wcsicmp(scheme, L"http") || !_wcsicmp(scheme, L"https")))
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ if (JSAPI_PARAM_OPTIONAL(pdispparams, 2, boolVal, VARIANT_FALSE) == VARIANT_TRUE)
+ ShellExecuteW(NULL, L"open", url, NULL, L".", 0);
+ else
+ QueueUserAPC(OpenURLAPC, hMainThread, (ULONG_PTR)_wcsdup(url));
+ }
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::ApplicationAPI::version(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_INIT_RESULT(pvarResult, VT_I4);
+ JSAPI_SET_RESULT(pvarResult, lVal, ((APP_VERSION_NUM&0xf000)>>12) * 100 + ((APP_VERSION_NUM&0xf0)>>4) * 10 + (APP_VERSION_NUM&0xf));
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+HRESULT JSAPI2::ApplicationAPI::versionstring(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = SysAllocString(WIDEN(APP_VERSION));
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::ApplicationAPI::language(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = SysAllocString(WASABI_API_LNG->GetLanguageIdentifier(LANG_LANG_CODE));
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::ApplicationAPI::languagepack(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = SysAllocString(WASABI_API_LNG->GetLanguageIdentifier(LANG_IDENT_STR));
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::ApplicationAPI::settingspath(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = SysAllocString(WASABI_API_APP->path_getUserSettingsPath());
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::ApplicationAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::ApplicationAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::ApplicationAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::ApplicationAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
diff --git a/Src/Winamp/JSAPI2_Application.h b/Src/Winamp/JSAPI2_Application.h
new file mode 100644
index 00000000..8aa11213
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Application.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <ocidl.h>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class ApplicationAPI : public IDispatch
+ {
+ public:
+ ApplicationAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ private:
+ const wchar_t *key;
+ JSAPI::ifc_info *info;
+ volatile LONG refCount;
+
+ STDMETHOD (LaunchURL)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (version)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (versionstring)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (language)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (languagepack)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (settingspath)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_AsyncDownloader.cpp b/Src/Winamp/JSAPI2_AsyncDownloader.cpp
new file mode 100644
index 00000000..fc9ee1b9
--- /dev/null
+++ b/Src/Winamp/JSAPI2_AsyncDownloader.cpp
@@ -0,0 +1,732 @@
+#include "JSAPI2_AsyncDownloader.h"
+#include "JSAPI2_Security.h"
+#include "main.h"
+#include "../Agave/Language/api_language.h"
+#include "JSAPI.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoLock.h"
+#include "api.h"
+#include "..\Components\wac_network\wac_network_http_receiver_api.h"
+#include "resource.h"
+#include "../Plugins/General/gen_ml/ml.h"
+#include <api/service/svcs/svc_imgload.h>
+#include "JSAPI2_CallbackManager.h"
+
+#define SCRIPT_E_REPORTED 0x80020101
+
+#define SIMULTANEOUS_ASYNCDOWNLOADS 2
+std::vector<DownloadToken> asyncDownloads;
+Nullsoft::Utility::LockGuard asyncDownloadsLock;
+
+
+bool IsImage(const wchar_t *filename)
+{
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ if (l->isMine(filename))
+ {
+ sf->releaseInterface(l);
+ return true;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return false;
+}
+
+bool IsPlaylist(const wchar_t *filename)
+{
+ if (!AGAVE_API_PLAYLISTMANAGER || !AGAVE_API_PLAYLISTMANAGER->CanLoad(filename))
+ return false;
+ return true;
+}
+
+bool IsMedia( const wchar_t *filename )
+{
+ int a = 0;
+ if ( !in_setmod_noplay( filename, &a ) )
+ {
+ return false;
+ }
+ return true;
+}
+
+namespace JSAPI2
+{
+ class AsyncDownloaderAPICallback : public ifc_downloadManagerCallback
+ {
+ public:
+ AsyncDownloaderAPICallback( const wchar_t *url, const wchar_t *destination_filepath, const wchar_t *onlineServiceId, const wchar_t *onlineServiceName )
+ {
+ this->hFile = INVALID_HANDLE_VALUE;
+ this->url = _wcsdup( url );
+ this->destination_filepath = _wcsdup( destination_filepath );
+ this->onlineServiceId = _wcsdup( onlineServiceId );
+ if ( onlineServiceName )
+ this->onlineServiceName = _wcsdup( onlineServiceName );
+ else
+ this->onlineServiceName = NULL;
+ this->totalSize = 0;
+ this->downloaded = 0;
+ ref_count = 1;
+ }
+
+ void OnInit(DownloadToken token)
+ {
+ callbackManager.OnInit(this->url, this->onlineServiceId);
+ }
+
+ void OnConnect(DownloadToken token)
+ {
+ // ---- retrieve total size
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (http)
+ {
+ this->totalSize = http->content_length();
+ }
+
+ // ---- create file handle
+ hFile = CreateFileW(destination_filepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ }
+
+ callbackManager.OnConnect(this->url, this->onlineServiceId);
+ }
+
+ void OnData(DownloadToken token, void *data, size_t datalen)
+ {
+ // ---- OnConnect copied here due to dlmgr OnData called first
+ // ---- retrieve total size
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if ( !this->totalSize && http )
+ {
+ this->totalSize = http->content_length();
+ }
+
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ // ---- create file handle
+ hFile = CreateFileW(destination_filepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ return;
+ }
+ }
+ // ---- OnConnect to be removed once dlmgr is fixed
+
+ // ---- OnData
+ // ---- if file handle is invalid, then cancel download
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ return;
+ }
+
+ this->downloaded = (size_t)WAC_API_DOWNLOADMANAGER->GetBytesDownloaded(token);
+
+ if ( datalen > 0 )
+ {
+ // ---- hFile is valid handle, and write to disk
+ DWORD numWritten = 0;
+ WriteFile(hFile, data, (DWORD)datalen, &numWritten, FALSE);
+
+ // ---- failed writing the number of datalen characters, cancel download
+ if (numWritten != datalen)
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ return;
+ }
+ }
+
+ // TODO: if killswitch is turned on, then cancel download
+ //if ( downloadStatus.UpdateStatus(p_token, this->downloaded, this->totalSize) )
+ //{
+ // WAC_API_DOWNLOADMANAGER->CancelDownload(p_token);
+ //}
+
+ callbackManager.OnData(url, this->downloaded, this->totalSize, this->onlineServiceId);
+ }
+
+ void OnCancel( DownloadToken p_token )
+ {
+ if ( hFile != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle( hFile );
+ DeleteFileW( destination_filepath );
+ }
+
+ this->resumeNextPendingDownload( p_token );
+
+ callbackManager.OnCancel( url, this->onlineServiceId );
+
+ this->Release();
+ }
+
+ void OnError(DownloadToken p_token, int error)
+ {
+ if ( hFile != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle(hFile);
+ DeleteFileW(destination_filepath);
+ }
+
+ this->resumeNextPendingDownload( p_token );
+
+ callbackManager.OnError(url, error, this->onlineServiceId);
+
+ this->Release();
+ }
+
+ void OnFinish( DownloadToken p_token )
+ {
+ if ( hFile != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle( hFile );
+
+ if ( IsMedia( PathFindFileNameW( destination_filepath ) ) )
+ {
+ LMDB_FILE_ADD_INFOW fi = { const_cast<wchar_t *>( destination_filepath ), -1, -1 };
+ sendMlIpc( ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi );
+ sendMlIpc( ML_IPC_DB_SYNCDB, 0 );
+ }
+ }
+
+ this->resumeNextPendingDownload( p_token );
+
+
+ callbackManager.OnFinish( url, destination_filepath, this->onlineServiceId );
+
+ this->Release();
+ }
+
+
+ int GetSource( wchar_t *source, size_t source_cch )
+ {
+ if ( this->onlineServiceName )
+ return wcscpy_s( source, source_cch, this->onlineServiceName );
+ else
+ return 1;
+ }
+
+ int GetTitle( wchar_t *title, size_t title_cch )
+ {
+ return wcscpy_s( title, title_cch, PathFindFileNameW( this->destination_filepath ) );
+ }
+
+ int GetLocation( wchar_t *location, size_t location_cch )
+ {
+ return wcscpy_s( location, location_cch, this->destination_filepath );
+ }
+
+
+ size_t AddRef()
+ {
+ return InterlockedIncrement( (LONG *)&ref_count );
+ }
+
+ size_t Release()
+ {
+ if ( ref_count == 0 )
+ return ref_count;
+
+ LONG r = InterlockedDecrement( (LONG *)&ref_count );
+ if ( r == 0 )
+ delete( this );
+
+ return r;
+ }
+
+ private: // private destructor so no one accidentally calls delete directly on this reference counted object
+ ~AsyncDownloaderAPICallback()
+ {
+ if ( url )
+ free( url );
+
+ if ( destination_filepath )
+ free( destination_filepath );
+
+ if ( onlineServiceId )
+ free( onlineServiceId );
+
+ if ( onlineServiceName )
+ free( onlineServiceName );
+ }
+
+ inline void resumeNextPendingDownload( DownloadToken p_token )
+ {
+ {
+ Nullsoft::Utility::AutoLock lock( asyncDownloadsLock );
+
+ size_t l_index = 0;
+ for ( DownloadToken &l_download_token : asyncDownloads )
+ {
+ if ( l_download_token == p_token )
+ {
+ asyncDownloads.erase( asyncDownloads.begin() + l_index );
+ break;
+ }
+
+ ++l_index;
+ }
+ }
+
+ for ( DownloadToken &l_download_token : asyncDownloads )
+ {
+ if ( WAC_API_DOWNLOADMANAGER->IsPending( l_download_token ) )
+ {
+ WAC_API_DOWNLOADMANAGER->ResumePendingDownload( l_download_token );
+ break;
+ }
+ }
+ }
+
+ protected:
+ RECVS_DISPATCH;
+
+ private:
+ HANDLE hFile;
+ wchar_t *url;
+ wchar_t *destination_filepath;
+ wchar_t *onlineServiceId;
+ wchar_t *onlineServiceName;
+ size_t totalSize;
+ size_t downloaded;
+ LONG ref_count;
+ };
+}
+
+#define CBCLASS JSAPI2::AsyncDownloaderAPICallback
+START_DISPATCH;
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONDATA, OnData )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
+CB( IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE, GetSource )
+CB( IFC_DOWNLOADMANAGERCALLBACK_GETTITLE, GetTitle )
+CB( IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION, GetLocation )
+CB( ADDREF, AddRef )
+CB( RELEASE, Release )
+END_DISPATCH;
+ #undef CBCLASS
+
+JSAPI2::AsyncDownloaderAPI::AsyncDownloaderAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
+{
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+JSAPI2::AsyncDownloaderAPI::~AsyncDownloaderAPI()
+{
+ // just in case someone forgot
+ JSAPI2::callbackManager.Deregister(this);
+
+ size_t index = events.size();
+ while(index--)
+ {
+ IDispatch *pEvent = events[index];
+ if (NULL != pEvent)
+ pEvent->Release();
+ }
+}
+
+
+#define DISP_TABLE \
+ CHECK_ID(DownloadMedia)\
+ CHECK_ID(RegisterForEvents)\
+ CHECK_ID(UnregisterFromEvents)\
+
+#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
+enum {
+ DISP_TABLE
+};
+
+#undef CHECK_ID
+#define CHECK_ID(str)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
+
+HRESULT JSAPI2::AsyncDownloaderAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE;
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::AsyncDownloaderAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::AsyncDownloaderAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+int CALLBACK WINAPI BrowseCallbackProc_Download(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ if (uMsg == BFFM_INITIALIZED)
+ {
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)lpData);
+
+ // this is not nice but it fixes the selection not working correctly on all OSes
+ EnumChildWindows(hwnd, browseEnumProc, 0);
+ }
+ if (uMsg == WM_CREATE) SetWindowTextW(hwnd,getStringW(IDS_SELDOWNLOADDIR,NULL,0));
+ return 0;
+}
+
+void GetPathToStore(wchar_t path_to_store[MAX_PATH]);
+bool GetOnlineDownloadPath(const wchar_t *key, const wchar_t *svcname, wchar_t path_to_store[MAX_PATH])
+{
+ //retrieve online service specific download path
+ GetPrivateProfileStringW(key,L"downloadpath",NULL,path_to_store,MAX_PATH,JSAPI2_INIFILE);
+
+ //if found then return, otherwise allow user to specify
+ if (path_to_store && path_to_store[0]) return true;
+
+ //default music folder
+ GetPathToStore(path_to_store);
+
+ //popup dialog to allow user select and specify online service download path
+ BROWSEINFOW bi={0};
+ wchar_t name[MAX_PATH] = {0};
+ wchar_t title[256] = {0};
+ bi.hwndOwner = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
+ bi.pszDisplayName = name;
+ StringCchPrintfW(title,256,getStringW(IDS_ONLINESERVICE_SELDOWNLOADDIR, 0, 0),svcname);
+ bi.lpszTitle = title;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc_Download;
+ bi.lParam = (LPARAM)path_to_store;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist)
+ {
+ SHGetPathFromIDListW(idlist, path_to_store);
+ Shell_Free(idlist);
+ WritePrivateProfileStringW(key,L"downloadpath",path_to_store,JSAPI2_INIFILE);
+ return true;
+ }
+
+ return false;
+}
+
+void CleanNameForPath(wchar_t *name)
+{
+
+ while (name && *name)
+ {
+ switch(*name)
+ {
+ case L'?':
+ case L'*':
+ case L'|':
+ *name = L'_';
+ break;
+ case '/':
+ case L'\\':
+ case L':':
+ *name = L'-';
+ break;
+ case L'\"':
+ *name = L'\'';
+ break;
+ case L'<':
+ *name = L'(';
+ break;
+ case L'>': *name = L')';
+ break;
+ }
+ name++;
+ }
+}
+
+HRESULT JSAPI2::AsyncDownloaderAPI::DownloadMedia(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr); //url
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr); //destination file
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_BOOL, puArgErr); //add to media library or not
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"downloader", L"downloadmedia", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+
+ const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ wchar_t *destFileSpec=JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, PathFindFileNameW(url));
+ //filter reserved characters in file name
+ CleanNameForPath(destFileSpec);
+
+ // verify that passed-in URL is a valid media type
+ if (!url || !destFileSpec || (!IsImage(destFileSpec) && !IsPlaylist(destFileSpec) && !IsMedia(destFileSpec)))
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ return S_OK;
+ }
+
+ wchar_t path_to_store[MAX_PATH] = {0};
+ if (GetOnlineDownloadPath(this->key, this->info->GetName(), path_to_store))
+ {
+ CreateDirectoryW(path_to_store, NULL);
+
+ wchar_t destfile[MAX_PATH] = {0};
+ PathCombineW(destfile, path_to_store, destFileSpec);
+
+ JSAPI2::AsyncDownloaderAPICallback *callback = new JSAPI2::AsyncDownloaderAPICallback(url, destfile, key, this->info->GetName());
+ {
+ Nullsoft::Utility::AutoLock lock(asyncDownloadsLock);
+ if (asyncDownloads.size() < SIMULTANEOUS_ASYNCDOWNLOADS)
+ {
+ DownloadToken dt = WAC_API_DOWNLOADMANAGER->DownloadEx(AutoChar(url), callback, api_downloadManager::DOWNLOADEX_CALLBACK | api_downloadManager::DOWNLOADEX_UI);
+ asyncDownloads.push_back(dt);
+ }
+ else
+ {
+ DownloadToken dt = WAC_API_DOWNLOADMANAGER->DownloadEx(AutoChar(url), callback, api_downloadManager::DOWNLOADEX_CALLBACK | api_downloadManager::DOWNLOADEX_PENDING | api_downloadManager::DOWNLOADEX_UI);
+ asyncDownloads.push_back(dt);
+ }
+ }
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::AsyncDownloaderAPI::RegisterForEvents(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_DISPATCH, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ switch (security.GetActionAuthorization(L"downloader", L"events", key, info, JSAPI2::api_security::ACTION_PROMPT))
+ {
+ case JSAPI2::api_security::ACTION_DISALLOWED:
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ break;
+ case JSAPI2::api_security::ACTION_ALLOWED:
+ {
+ /** if this is the first time someone is registering an event
+ ** add ourselves to the callback manager
+ */
+ if (events.empty())
+ JSAPI2::callbackManager.Register(this);
+
+ IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
+ event->AddRef();
+ // TODO: benski> not sure, but we might need to: event->AddRef();
+ events.push_back(event);
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ }
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::AsyncDownloaderAPI::UnregisterFromEvents(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_DISPATCH, puArgErr);
+
+ IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
+ // TODO: benski> not sure, but we might need to: event->Release();
+
+ size_t index = events.size();
+ while(index--)
+ {
+ if (events[index] == event)
+ {
+ events.erase(events.begin() + index);
+ event->Release();
+ }
+ }
+
+ /** if we don't have any more event listeners
+ ** remove ourselves from the callback manager
+ */
+ if (events.empty())
+ JSAPI2::callbackManager.Deregister(this);
+
+ return S_OK;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::AsyncDownloaderAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::AsyncDownloaderAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::AsyncDownloaderAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::AsyncDownloaderAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
+
+
+void JSAPI2::AsyncDownloaderAPI::InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount)
+{
+ size_t index = events.size();
+ if (0 == index)
+ {
+ JSAPI2::callbackManager.Deregister(this);
+ return;
+ }
+
+ JSAPI::CallbackParameters *eventData= new JSAPI::CallbackParameters;
+ if (NULL == eventData) return;
+
+ eventData->AddString(L"event", eventName);
+
+ if (NULL != parameters && 0 != parametersCount)
+ eventData->AddPropertyIndirect(parameters, parametersCount);
+
+ HRESULT hr;
+ while (index--)
+ {
+ IDispatch *pEvent = events[index];
+ if (NULL != pEvent)
+ {
+ hr = JSAPI::InvokeEvent(eventData, pEvent);
+ if (FAILED(hr) && SCRIPT_E_REPORTED != hr)
+ {
+ events.erase(events.begin() + index);
+ pEvent->Release();
+ }
+ }
+ }
+
+ if (events.empty())
+ JSAPI2::callbackManager.Deregister(this);
+
+ eventData->Release();
+}
+
+
+void JSAPI2::AsyncDownloaderAPI::OnInit(const wchar_t *url)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter =
+ {JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url};
+
+ InvokeEvent(L"OnInit", &parameter, 1);
+}
+
+
+void JSAPI2::AsyncDownloaderAPI::OnConnect(const wchar_t *url)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter =
+ {JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url};
+
+ InvokeEvent(L"OnConnect", &parameter, 1);
+}
+
+
+void JSAPI2::AsyncDownloaderAPI::OnData(const wchar_t *url, size_t downloadedlen, size_t totallen)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter[3] =
+ {{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url},
+ {JSAPI::CallbackParameters::typeLong, L"downloadedlen", (ULONG_PTR)downloadedlen},
+ {JSAPI::CallbackParameters::typeLong, L"totallen", (ULONG_PTR)totallen}};
+
+ InvokeEvent(L"OnData", &parameter[0], 3);
+}
+
+
+void JSAPI2::AsyncDownloaderAPI::OnCancel(const wchar_t *url)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter =
+ {JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url};
+
+ InvokeEvent(L"OnCancel", &parameter, 1);
+}
+
+
+void JSAPI2::AsyncDownloaderAPI::OnError(const wchar_t *url, int error)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter[2] =
+ {{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url},
+ {JSAPI::CallbackParameters::typeLong, L"error", (ULONG_PTR)error}};
+
+ InvokeEvent(L"OnError", &parameter[0], 2);
+}
+
+
+void JSAPI2::AsyncDownloaderAPI::OnFinish(const wchar_t *url, const wchar_t *destfilename)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter[2] =
+ {{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url},
+ {JSAPI::CallbackParameters::typeString, L"destfilename", (ULONG_PTR)destfilename}};
+
+ InvokeEvent(L"OnFinish", &parameter[0], 2);
+}
+
+const wchar_t *JSAPI2::AsyncDownloaderAPI::GetKey()
+{
+ return this->key;
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_AsyncDownloader.h b/Src/Winamp/JSAPI2_AsyncDownloader.h
new file mode 100644
index 00000000..f05da9d5
--- /dev/null
+++ b/Src/Winamp/JSAPI2_AsyncDownloader.h
@@ -0,0 +1,47 @@
+#pragma once
+#include <ocidl.h>
+#include "JSAPI_Info.h"
+#include <vector>
+#include "JSAPI_CallbackParameters.h"
+
+namespace JSAPI2
+{
+ class AsyncDownloaderAPI : public IDispatch
+ {
+ public:
+ AsyncDownloaderAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ ~AsyncDownloaderAPI();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ public:
+ /** Callbacks
+ ** JSAPI2::CallbackManager will have been nice enough to marshall onto our thread
+ ** so we don't have to worry about that
+ */
+ void OnInit(const wchar_t *url);
+ void OnConnect(const wchar_t *url);
+ void OnData(const wchar_t *url, size_t downloadedlen, size_t totallen);
+ void OnCancel(const wchar_t *url);
+ void OnError(const wchar_t *url, int error);
+ void OnFinish(const wchar_t *url, const wchar_t *destfilename);
+ void InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount);
+ //Getter for key
+ const wchar_t *GetKey();
+ private:
+ const wchar_t *key;
+ volatile LONG refCount;
+ JSAPI::ifc_info *info;
+ typedef std::vector<IDispatch*> EventsList;
+ EventsList events;
+
+ STDMETHOD (DownloadMedia)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (RegisterForEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (UnregisterFromEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_Bookmarks.cpp b/Src/Winamp/JSAPI2_Bookmarks.cpp
new file mode 100644
index 00000000..e570d72e
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Bookmarks.cpp
@@ -0,0 +1,122 @@
+#include "JSAPI2_Bookmarks.h"
+#include "JSAPI2_Security.h"
+#include "main.h"
+#include "JSAPI.h"
+#include "../nu/AutoChar.h"
+
+JSAPI2::BookmarksAPI::BookmarksAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
+{
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+#define DISP_TABLE \
+ CHECK_ID(Add)\
+
+#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
+enum {
+ DISP_TABLE
+};
+#undef CHECK_ID
+#define CHECK_ID(str)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
+
+HRESULT JSAPI2::BookmarksAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::BookmarksAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::BookmarksAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::BookmarksAPI::Add(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"bookmarks", L"add", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_VARIANT(pvarResult, V_BOOL, VARIANT_TRUE);
+ wchar_t *filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ wchar_t *title = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
+ if (title)
+ Bookmark_additem(filename, title);
+ else if (filename)
+ Bookmark_additem(filename, filename);
+ else
+ JSAPI_SET_VARIANT(pvarResult, V_BOOL, VARIANT_FALSE);
+ }
+ else
+ {
+ JSAPI_SET_VARIANT(pvarResult, V_BOOL, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::BookmarksAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::BookmarksAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::BookmarksAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::BookmarksAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
diff --git a/Src/Winamp/JSAPI2_Bookmarks.h b/Src/Winamp/JSAPI2_Bookmarks.h
new file mode 100644
index 00000000..10cc9cc5
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Bookmarks.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <ocidl.h>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class BookmarksAPI : public IDispatch
+ {
+ public:
+ BookmarksAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ private:
+ const wchar_t *key;
+ volatile LONG refCount;
+ JSAPI::ifc_info *info;
+
+ STDMETHOD (Add)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_CallbackManager.cpp b/Src/Winamp/JSAPI2_CallbackManager.cpp
new file mode 100644
index 00000000..1272daa5
--- /dev/null
+++ b/Src/Winamp/JSAPI2_CallbackManager.cpp
@@ -0,0 +1,567 @@
+#include "JSAPI2_CallbackManager.h"
+#include "JSAPI2_TransportAPI.h"
+#include "JSAPI2_AsyncDownloader.h"
+#include "JSAPI2_MediaCore.h"
+#include "api.h"
+
+JSAPI2::CallbackManager JSAPI2::callbackManager;
+
+JSAPI2::CallbackManager::CallbackManager() : callbackGuard("JSAPI2::CallbackManager::callbackGuard")
+{}
+
+void JSAPI2::CallbackManager::Register( JSAPI2::TransportAPI *me )
+{
+ /* benski> important note:
+ even thought JSAPI2::Transport inherits from IUnknown,
+ we don't call AddRef here!
+ because this would introduce a circular reference.
+ JSAPI2::TransportAPI will call Deregister during it's
+ destructor.
+ */
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+ transports.push_back( new TransportCallback( me ) );
+}
+
+void JSAPI2::CallbackManager::Deregister( JSAPI2::TransportAPI *me )
+{
+ /* benski> important note:
+ even thought JSAPI2::Transport inherits from IUnknown,
+ we don't call Release here!
+ because this would introduce a circular reference.
+ JSAPI2::TransportAPI will call Deregister during it's
+ destructor.
+ */
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+ for ( size_t i = 0; i != transports.size(); i++ )
+ {
+ TransportCallback *callback = transports[ i ];
+ if ( callback->api == me )
+ {
+ delete callback;
+ transports.erase( transports.begin() + i );
+ i--;
+ }
+ }
+}
+
+
+void JSAPI2::CallbackManager::Register( JSAPI2::MediaCoreAPI *me )
+{
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+
+ //if (!mediaCores.contains(me))
+ if ( mediaCores.end() == std::find( mediaCores.begin(), mediaCores.end(), me ) )
+ {
+ mediaCores.push_back( me );
+ }
+}
+
+void JSAPI2::CallbackManager::Deregister( JSAPI2::MediaCoreAPI *me )
+{
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+
+ auto it = mediaCores.begin();
+ while ( it != mediaCores.end() )
+ {
+ if ( *it != me )
+ {
+ it++;
+ continue;
+ }
+
+ it = mediaCores.erase( it );
+ }
+}
+
+
+void JSAPI2::CallbackManager::Register( JSAPI2::AsyncDownloaderAPI *me )
+{
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+ asyncDownloaders.push_back( new AsyncDownloaderCallback( me ) );
+}
+
+void JSAPI2::CallbackManager::Deregister( JSAPI2::AsyncDownloaderAPI *me )
+{
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+ for ( size_t i = 0; i != asyncDownloaders.size(); i++ )
+ {
+ AsyncDownloaderCallback *callback = asyncDownloaders[ i ];
+ if ( callback->api == me )
+ {
+ delete callback;
+ asyncDownloaders.erase( asyncDownloaders.begin() + i );
+ i--;
+ }
+ }
+}
+
+/* --- OnStop --- */
+struct OnStopAPCData
+{
+ JSAPI2::TransportAPI *transport;
+ int position;
+ int is_full_stop;
+};
+
+static void CALLBACK CMGR_OnStopAPC(ULONG_PTR param)
+{
+ OnStopAPCData *data = (OnStopAPCData *)param;
+ data->transport->OnStop(data->position, data->is_full_stop);
+ data->transport->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnStop(int position, int is_full_stop)
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock(callbackGuard);
+
+ for ( TransportCallback *l_transport : transports )
+ {
+ OnStopAPCData *data = new OnStopAPCData;
+ data->transport = l_transport->api;
+ data->position = position;
+ data->is_full_stop = is_full_stop;
+
+ data->transport->AddRef(); // so it doesn't disappear while we're switching threads
+
+ if ( threadId == l_transport->threadId )
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnStopAPC( (ULONG_PTR)data );
+ }
+ else
+ {
+ // different thread, do an APC
+ if ( QueueUserAPC( CMGR_OnStopAPC, l_transport->threadHandle, (ULONG_PTR)data ) == 0 )
+ {
+ data->transport->Release();
+ delete data;
+ }
+ }
+ }
+}
+/* --- --- */
+
+/* --- OnPlay --- */
+struct OnPlayAPC
+{
+ JSAPI2::TransportAPI *transport;
+ wchar_t *filename;
+};
+
+static void CALLBACK CMGR_OnPlayAPC(ULONG_PTR param)
+{
+ OnPlayAPC *data = (OnPlayAPC *)param;
+ data->transport->OnPlay(data->filename);
+
+ free(data->filename);
+
+ data->transport->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnPlay(const wchar_t *filename)
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock(callbackGuard);
+
+ for ( TransportCallback *l_transport : transports )
+ {
+ OnPlayAPC *data = new OnPlayAPC;
+ data->transport = l_transport->api;
+ data->filename = _wcsdup(filename);
+
+ data->transport->AddRef(); // so it doesn't disappear while we're switching threads
+
+ if ( threadId == l_transport->threadId )
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnPlayAPC( (ULONG_PTR)data );
+ }
+ else
+ {
+ // different thread, do an APC
+ if ( QueueUserAPC( CMGR_OnPlayAPC, l_transport->threadHandle, (ULONG_PTR)data ) == 0 )
+ {
+ data->transport->Release();
+ free( data->filename );
+ delete data;
+ }
+ }
+ }
+}
+
+/* --- --- */
+
+
+struct OnPauseAPC
+{
+ JSAPI2::TransportAPI *transport;
+ bool pause_state;
+};
+
+static void CALLBACK CMGR_OnPauseAPC(ULONG_PTR param)
+{
+ OnPauseAPC *data = (OnPauseAPC *)param;
+ data->transport->OnPause(data->pause_state);
+ data->transport->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnPause(bool pause_state)
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+
+ for ( TransportCallback *l_transport : transports )
+ {
+ OnPauseAPC *data = new OnPauseAPC;
+ data->transport = l_transport->api;
+ data->pause_state = pause_state;
+
+ data->transport->AddRef(); // so it doesn't disappear while we're switching threads
+
+ if (threadId == l_transport->threadId)
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnPauseAPC((ULONG_PTR)data);
+ }
+ else
+ {
+ // different thread, do an APC
+ if (QueueUserAPC(CMGR_OnPauseAPC, l_transport->threadHandle, (ULONG_PTR)data) == 0)
+ {
+ data->transport->Release();
+ delete data;
+ }
+ }
+ }
+}
+
+/* --- --- */
+bool JSAPI2::CallbackManager::OverrideMetadata( const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch )
+{
+ if ( NULL != filename && NULL != tag && NULL != out )
+ {
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+ for ( MediaCoreAPI *l_mediaCore : mediaCores )
+ {
+ if ( l_mediaCore->OverrideMetadata( filename, tag, out, outCch ) )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/* --- OnInit --- */
+struct OnInitAPC
+{
+ JSAPI2::AsyncDownloaderAPI *asyncDownloader;
+ wchar_t *url;
+};
+
+static void CALLBACK CMGR_OnInitAPC(ULONG_PTR param)
+{
+ OnInitAPC *data = (OnInitAPC *)param;
+ data->asyncDownloader->OnInit(data->url);
+ free(data->url);
+ data->asyncDownloader->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnInit( const wchar_t *url, const wchar_t *onlinesvcId )
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+
+ for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
+ {
+ if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
+ continue; //only call back to the same online service that issued the download reqeust
+
+ OnInitAPC *data = new OnInitAPC;
+ data->asyncDownloader = l_downloader->api;
+ data->url = _wcsdup( url );
+
+ data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
+
+ if ( threadId == l_downloader->threadId )
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnInitAPC( (ULONG_PTR)data );
+ }
+ else
+ {
+ // different thread, do an APC
+ if ( QueueUserAPC( CMGR_OnInitAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
+ {
+ data->asyncDownloader->Release();
+ free( data->url );
+ delete data;
+ }
+ }
+
+ }
+}
+
+
+/* --- OnConnect --- */
+struct OnConnectAPC
+{
+ JSAPI2::AsyncDownloaderAPI *asyncDownloader;
+ wchar_t *url;
+};
+
+static void CALLBACK CMGR_OnConnectAPC(ULONG_PTR param)
+{
+ OnConnectAPC *data = (OnConnectAPC *)param;
+ data->asyncDownloader->OnConnect(data->url);
+ free(data->url);
+ data->asyncDownloader->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnConnect( const wchar_t *url, const wchar_t *onlinesvcId )
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+
+ for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
+ {
+ if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
+ continue; //only call back to the same online service that issued the download reqeust
+
+ OnConnectAPC *data = new OnConnectAPC;
+ data->asyncDownloader = l_downloader->api;
+ data->url = _wcsdup( url );
+
+ data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
+
+ if ( threadId == l_downloader->threadId )
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnConnectAPC( (ULONG_PTR)data );
+ }
+ else
+ {
+ // different thread, do an APC
+ if ( QueueUserAPC( CMGR_OnConnectAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
+ {
+ data->asyncDownloader->Release();
+ free( data->url );
+ delete data;
+ }
+ }
+ }
+}
+
+
+/* --- OnCancel --- */
+struct OnCancelAPC
+{
+ JSAPI2::AsyncDownloaderAPI *asyncDownloader;
+ wchar_t *url;
+};
+
+static void CALLBACK CMGR_OnCancelAPC(ULONG_PTR param)
+{
+ OnCancelAPC *data = (OnCancelAPC *)param;
+ data->asyncDownloader->OnCancel(data->url);
+ free(data->url);
+ data->asyncDownloader->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnCancel( const wchar_t *url, const wchar_t *onlinesvcId )
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock( callbackGuard );
+
+ for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
+ {
+ if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
+ continue; //only call back to the same online service that issued the download reqeust
+
+ OnCancelAPC *data = new OnCancelAPC;
+ data->asyncDownloader = l_downloader->api;
+ data->url = _wcsdup( url );
+
+ data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
+
+ if ( threadId == l_downloader->threadId )
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnCancelAPC( (ULONG_PTR)data );
+ }
+ else
+ {
+ // different thread, do an APC
+ if ( QueueUserAPC( CMGR_OnCancelAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
+ {
+ data->asyncDownloader->Release();
+ free( data->url );
+ delete data;
+ }
+ }
+ }
+}
+
+
+/* --- OnData --- */
+struct OnDataAPC
+{
+ JSAPI2::AsyncDownloaderAPI *asyncDownloader;
+ wchar_t *url;
+ size_t downloadedlen;
+ size_t totallen;
+};
+
+static void CALLBACK CMGR_OnDataAPC(ULONG_PTR param)
+{
+ OnDataAPC *data = (OnDataAPC *)param;
+ data->asyncDownloader->OnData(data->url, data->downloadedlen, data->totallen);
+ free(data->url);
+ data->asyncDownloader->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnData(const wchar_t *url, size_t downloadedlen, size_t totallen, const wchar_t *onlinesvcId)
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock(callbackGuard);
+
+ for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
+ {
+ if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
+ continue; //only call back to the same online service that issued the download reqeust
+
+ OnDataAPC *data = new OnDataAPC;
+ data->asyncDownloader = downloader->api;
+ data->url = _wcsdup(url);
+ data->downloadedlen = downloadedlen;
+ data->totallen = totallen;
+ data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
+ if (threadId == downloader->threadId)
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnDataAPC((ULONG_PTR)data);
+ }
+ else
+ {
+ // different thread, do an APC
+ if (QueueUserAPC(CMGR_OnDataAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
+ {
+ data->asyncDownloader->Release();
+ free(data->url);
+ delete data;
+ }
+ }
+ }
+}
+
+
+/* --- OnError --- */
+struct OnErrorAPC
+{
+ JSAPI2::AsyncDownloaderAPI *asyncDownloader;
+ wchar_t *url;
+ int error;
+};
+
+static void CALLBACK CMGR_OnErrorAPC(ULONG_PTR param)
+{
+ OnErrorAPC *data = (OnErrorAPC *)param;
+ data->asyncDownloader->OnError(data->url, data->error);
+ free(data->url);
+ data->asyncDownloader->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnError(const wchar_t *url, int error, const wchar_t *onlinesvcId)
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock(callbackGuard);
+
+ for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
+ {
+ if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
+ continue; //only call back to the same online service that issued the download reqeust
+
+ OnErrorAPC *data = new OnErrorAPC;
+ data->asyncDownloader = downloader->api;
+ data->url = _wcsdup(url);
+ data->error = error;
+ data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
+ if (threadId == downloader->threadId)
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnErrorAPC((ULONG_PTR)data);
+ }
+ else
+ {
+ // different thread, do an APC
+ if (QueueUserAPC(CMGR_OnErrorAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
+ {
+ data->asyncDownloader->Release();
+ free(data->url);
+ delete data;
+ }
+ }
+ }
+}
+
+
+/* --- OnFinish --- */
+struct OnFinishAPC
+{
+ JSAPI2::AsyncDownloaderAPI *asyncDownloader;
+ wchar_t *url;
+ wchar_t *destfilename;
+};
+
+static void CALLBACK CMGR_OnFinishAPC(ULONG_PTR param)
+{
+ OnFinishAPC *data = (OnFinishAPC *)param;
+ data->asyncDownloader->OnFinish(data->url, data->destfilename);
+ free(data->url);
+ free(data->destfilename);
+ data->asyncDownloader->Release();
+ delete data;
+}
+
+void JSAPI2::CallbackManager::OnFinish(const wchar_t *url, const wchar_t *destfilename, const wchar_t *onlinesvcId)
+{
+ DWORD threadId = GetCurrentThreadId();
+ Nullsoft::Utility::AutoLock lock(callbackGuard);
+
+ for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
+ {
+ if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
+ continue; //only call back to the same online service that issued the download reqeust
+
+ OnFinishAPC *data = new OnFinishAPC;
+ data->asyncDownloader = downloader->api;
+ data->url = _wcsdup(url);
+ data->destfilename = _wcsdup(destfilename);
+ data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
+ if (threadId == downloader->threadId)
+ {
+ // same thread! huzzah but I wonder how that happened :)
+ CMGR_OnFinishAPC((ULONG_PTR)data);
+ }
+ else
+ {
+ // different thread, do an APC
+ if (QueueUserAPC(CMGR_OnFinishAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
+ {
+ data->asyncDownloader->Release();
+ free(data->url);
+ free(data->destfilename);
+ delete data;
+ }
+ }
+ }
+}
diff --git a/Src/Winamp/JSAPI2_CallbackManager.h b/Src/Winamp/JSAPI2_CallbackManager.h
new file mode 100644
index 00000000..af6d6b12
--- /dev/null
+++ b/Src/Winamp/JSAPI2_CallbackManager.h
@@ -0,0 +1,93 @@
+#pragma once
+#include "../nu/AutoLock.h"
+#include <vector>
+#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
+
+extern "C" HANDLE DuplicateCurrentThread();
+namespace JSAPI2
+{
+ template <class API> struct CallbackInfo
+ {
+ CallbackInfo()
+ {
+ api = 0;
+ threadId = 0;
+ threadHandle = 0;
+ }
+
+ CallbackInfo(API *me)
+ {
+ api = me;
+ threadId = GetCurrentThreadId();
+ threadHandle = DuplicateCurrentThread();
+ }
+
+ ~CallbackInfo()
+ {
+ CloseHandle(threadHandle);
+ threadHandle = 0;
+ }
+ API *api;
+ DWORD threadId;
+ HANDLE threadHandle;
+ };
+
+ class TransportAPI;
+ class MediaCoreAPI;
+ class AsyncDownloaderAPI;
+ class CallbackManager
+ {
+ public:
+ CallbackManager();
+
+ public:
+ /** stuff for Winamp to call to trigger callbacks
+ ** these are primarily responsible for getting over to the correct thread
+ ** to keep that particular logic out of the various functions
+ */
+ void OnStop(int position, int is_full_stop);
+ void OnPlay(const wchar_t *filename);
+ void OnPause(bool pause_state);
+
+ /** Stuff that's OK to call on any thread
+ */
+ bool OverrideMetadata(const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch);
+
+ /** stuff for Winamp to call to trigger callbacks
+ ** these are primarily responsible for getting over to the correct thread
+ ** to keep that particular logic out of the various functions
+ */
+ void OnInit(const wchar_t *url, const wchar_t *onlinesvcId);
+ void OnConnect(const wchar_t *url, const wchar_t *onlinesvcId);
+ void OnData(const wchar_t *url, size_t downloadedlen, size_t totallen, const wchar_t *onlinesvcId);
+ void OnCancel(const wchar_t *url, const wchar_t *onlinesvcId);
+ void OnError(const wchar_t *url, int error, const wchar_t *onlinesvcId);
+ void OnFinish(const wchar_t *url, const wchar_t *destfilename, const wchar_t *onlinesvcId);
+ public:
+ /* stuff for other JSAPI2 classes to call */
+ void Register(JSAPI2::TransportAPI *me);
+ void Deregister(JSAPI2::TransportAPI *me);
+
+ void Register(JSAPI2::MediaCoreAPI *me);
+ void Deregister(JSAPI2::MediaCoreAPI *me);
+
+ void Register(JSAPI2::AsyncDownloaderAPI *me);
+ void Deregister(JSAPI2::AsyncDownloaderAPI *me);
+ private:
+ /* Transport API callbacks */
+ typedef CallbackInfo<JSAPI2::TransportAPI> TransportCallback;
+ typedef std::vector<TransportCallback*> TransportsList;
+ TransportsList transports;
+
+ typedef std::vector<MediaCoreAPI*> MediaCoreList;
+ MediaCoreList mediaCores;
+
+ typedef CallbackInfo<JSAPI2::AsyncDownloaderAPI> AsyncDownloaderCallback;
+ typedef std::vector<AsyncDownloaderCallback*> AsyncDownloadersList;
+ AsyncDownloadersList asyncDownloaders;
+
+ Nullsoft::Utility::LockGuard callbackGuard;
+ };
+
+ extern CallbackManager callbackManager;
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_Creator.cpp b/Src/Winamp/JSAPI2_Creator.cpp
new file mode 100644
index 00000000..339f352e
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Creator.cpp
@@ -0,0 +1,240 @@
+#include "main.h"
+#include "resource.h"
+#include "JSAPI2_Creator.h"
+#include "JSAPI2_TransportAPI.h"
+#include "JSAPI2_PlayerAPI.h"
+#include "JSAPI2_Downloader.h"
+#include "JSAPI2_SecurityAPI.h"
+#include "JSAPI2_Security.h"
+#include "JSAPI2_Bookmarks.h"
+#include "JSAPI2_Application.h"
+#include "JSAPI2_SkinAPI.h"
+#include "JSAPI2_MediaCore.h"
+#include "JSAPI2_AsyncDownloader.h"
+#include "api.h"
+#include "language.h"
+
+IDispatch *JSAPI2_Creator::CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info)
+{
+ if (!wcscmp(name, L"Transport"))
+ return new JSAPI2::TransportAPI(key, info);
+ else if (!wcscmp(name, L"PlayQueue"))
+ return new JSAPI2::PlayerAPI(key, info);
+ else if (!wcscmp(name, L"Downloader"))
+ return new JSAPI2::DownloaderAPI(key, info);
+ else if (!wcscmp(name, L"AsyncDownloader"))
+ return new JSAPI2::AsyncDownloaderAPI(key, info);
+ else if (!wcscmp(name, L"Security"))
+ return new JSAPI2::SecurityAPI(key, info);
+ else if (!wcscmp(name, L"Bookmarks"))
+ return new JSAPI2::BookmarksAPI(key, info);
+ else if (!wcscmp(name, L"Application"))
+ return new JSAPI2::ApplicationAPI(key, info);
+ else if (!wcscmp(name, L"Skin"))
+ return new JSAPI2::SkinAPI(key, info);
+ else if (!wcscmp(name, L"MediaCore"))
+ return new JSAPI2::MediaCoreAPI(key, info);
+ else
+ return 0;
+}
+
+static int GetDescription(const wchar_t *group, const wchar_t *action, wchar_t *str, size_t str_len, int *flags)
+{
+ if (!wcscmp(group, L"application"))
+ {
+ if (action && !wcscmp(action, L"launchurl"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_APPLICATION_LAUNCHURL, NULL, 0));
+ }
+ else
+ return 1;
+ return 0;
+
+ }
+ else if (!wcscmp(group, L"transport"))
+ {
+ if (action && !wcscmp(action, L"events"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_TRANSPORT_EVENTS, NULL, 0));
+ }
+ else if (action && !wcscmp(action, L"metadata"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_TRANSPORT_METADATA, NULL, 0));
+ }
+ else if (action && !wcscmp(action, L"controls"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_TRANSPORT_CONTROLS, NULL, 0));
+ }
+ else
+ return 1;
+
+ return 0;
+ }
+ else if(!wcscmp(group, L"player"))
+ {
+ if (action && !wcscmp(action, L"playlist"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_PLAYER_PLAYLIST, NULL, 0));
+ }
+ else if (action && !wcscmp(action, L"metadata"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_PLAYER_METADATA, NULL, 0));
+ }
+ else
+ return 1;
+ return 0;
+ }
+ else if (!wcscmp(group, L"downloader"))
+ {
+ if (action && !wcscmp(action, L"events"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_DOWNLOADER_EVENTS, NULL, 0));
+ }
+ else if (action && !wcscmp(action, L"downloadmedia"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_DOWNLOADER_DOWNLOADMEDIA, NULL, 0));
+ }
+ else
+ return 1;
+
+ return 0;
+ }
+ else if (!wcscmp(group, L"security"))
+ {
+ *flags = JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_SECURITY_AUTH, NULL, 0));
+ return 0;
+ }
+ else if (!wcscmp(group, L"bookmarks"))
+ {
+ *flags = JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_BOOKMARKS_AUTH, NULL, 0));
+ return 0;
+ }
+ else if (!wcscmp(group, L"skin"))
+ {
+ *flags = JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_SKIN_AUTH, NULL, 0));
+ return 0;
+ }
+ else if (!wcscmp(group, L"mediacore"))
+ {
+ if (action && !wcscmp(action, L"metadatahook"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_MEDIACORE_METADATAHOOK, NULL, 0));
+ }
+ else if (action && !wcscmp(action, L"metadata"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_MEDIACORE_METADATA, NULL, 0));
+ }
+ else if (action && !wcscmp(action, L"extensions"))
+ {
+ *flags = 0;
+ StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_MEDIACORE_EXTENSIONS, NULL, 0));
+ }
+ else
+ return 1;
+ return 0;
+ }
+ else
+ return 1;
+
+
+}
+
+
+
+int JSAPI2_Creator::PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data)
+{
+ int flags = 0;
+ wchar_t display_str[1024] = {0};
+ if (GetDescription(group, action, display_str, 1024, &flags) == 0)
+ {
+ const wchar_t *title_str = JSAPI2::security.GetAssociatedName(authorization_key);
+ return JSAPI2::security.SecurityPrompt(parent, title_str, display_str, flags);
+ }
+ else
+ return JSAPI2::svc_apicreator::AUTHORIZATION_UNDEFINED;
+}
+
+#define CBCLASS JSAPI2_Creator
+START_DISPATCH;
+CB(JSAPI2_SVC_APICREATOR_CREATEAPI, CreateAPI);
+CB(JSAPI2_SVC_APICREATOR_PROMPTFORAUTHORIZATION, PromptForAuthorization);
+END_DISPATCH;
+#undef CBCLASS
+
+static JSAPI2_Creator jsapi2_svc;
+static const char serviceName[] = "Winamp Javascript Objects";
+
+// {53CCACEF-1EFE-4060-8D09-329AD0D4F9C4}
+static const GUID jsapi2_factory_guid =
+{ 0x53ccacef, 0x1efe, 0x4060, { 0x8d, 0x9, 0x32, 0x9a, 0xd0, 0xd4, 0xf9, 0xc4 } };
+
+
+
+FOURCC JSAPI2CreatorFactory::GetServiceType()
+{
+ return jsapi2_svc.getServiceType();
+}
+
+const char *JSAPI2CreatorFactory::GetServiceName()
+{
+ return serviceName;
+}
+
+GUID JSAPI2CreatorFactory::GetGUID()
+{
+ return jsapi2_factory_guid;
+}
+
+void *JSAPI2CreatorFactory::GetInterface(int global_lock)
+{
+ // if (global_lock)
+ // WASABI_API_SVC->service_lock(this, (void *)ifc);
+ return &jsapi2_svc;
+}
+
+int JSAPI2CreatorFactory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int JSAPI2CreatorFactory::ReleaseInterface(void *ifc)
+{
+ //WASABI_API_SVC->service_unlock(ifc);
+ return 1;
+}
+
+const char *JSAPI2CreatorFactory::GetTestString()
+{
+ return 0;
+}
+
+int JSAPI2CreatorFactory::ServiceNotify(int msg, int param1, int param2)
+{
+ return 1;
+}
+
+#define CBCLASS JSAPI2CreatorFactory
+START_DISPATCH;
+CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
+CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
+CB(WASERVICEFACTORY_GETGUID, GetGUID)
+CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
+CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
+CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
+CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
+CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_Creator.h b/Src/Winamp/JSAPI2_Creator.h
new file mode 100644
index 00000000..b7af84e1
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Creator.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "../Winamp/JSAPI2_svc_apicreator.h"
+
+#include <api/service/waservicefactory.h>
+#include <api/service/services.h>
+
+
+class JSAPI2CreatorFactory : public waServiceFactory
+{
+public:
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+ void *GetInterface(int global_lock);
+ int SupportNonLockingInterface();
+ int ReleaseInterface(void *ifc);
+ const char *GetTestString();
+ int ServiceNotify(int msg, int param1, int param2);
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
+class JSAPI2_Creator : public JSAPI2::svc_apicreator
+{
+ IDispatch *CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info);
+ int PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data);
+protected:
+ RECVS_DISPATCH;
+};
diff --git a/Src/Winamp/JSAPI2_Downloader.h b/Src/Winamp/JSAPI2_Downloader.h
new file mode 100644
index 00000000..0d8275c5
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Downloader.h
@@ -0,0 +1,26 @@
+#pragma once
+#include <ocidl.h>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class DownloaderAPI : public IDispatch
+ {
+ public:
+ DownloaderAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ private:
+ const wchar_t *key;
+ volatile LONG refCount;
+ JSAPI::ifc_info *info;
+
+ STDMETHOD (DownloadMedia)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_DownloaderAPI.cpp b/Src/Winamp/JSAPI2_DownloaderAPI.cpp
new file mode 100644
index 00000000..4a6a6d99
--- /dev/null
+++ b/Src/Winamp/JSAPI2_DownloaderAPI.cpp
@@ -0,0 +1,159 @@
+#include "JSAPI2_Downloader.h"
+#include "JSAPI2_Security.h"
+#include "main.h"
+#include "../Agave/Language/api_language.h"
+#include "JSAPI.h"
+#include "../nu/AutoChar.h"
+#include "api.h"
+#include "resource.h"
+#include "../Plugins/General/gen_ml/ml.h"
+#include <api/service/svcs/svc_imgload.h>
+
+JSAPI2::DownloaderAPI::DownloaderAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
+{
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+enum
+{
+ DISP_DOWNLOADERAPI_DOWNLOADMEDIA,
+};
+
+#define DISP_TABLE \
+ CHECK_ID(DownloadMedia, DISP_DOWNLOADERAPI_DOWNLOADMEDIA)\
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT JSAPI2::DownloaderAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE;
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::DownloaderAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::DownloaderAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+bool IsImage(const wchar_t *filename);
+bool IsPlaylist(const wchar_t *filename);
+bool IsMedia(const wchar_t *filename);
+bool GetOnlineDownloadPath(const wchar_t *key, const wchar_t *svcname, wchar_t path_to_store[MAX_PATH]);
+HRESULT JSAPI2::DownloaderAPI::DownloadMedia(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_BOOL, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"downloader", L"downloadmedia", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+
+ const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ wchar_t *destFileSpec=JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, PathFindFileNameW(url));
+
+ //filter reserved characters in file name
+ CleanNameForPath(destFileSpec);
+
+ // verify that passed-in URL is a valid media type
+ if (!IsImage(destFileSpec) && !IsPlaylist(destFileSpec) && !IsMedia(destFileSpec))
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ return S_OK;
+ }
+
+ wchar_t path_to_store[MAX_PATH] = {0};
+ if (GetOnlineDownloadPath(this->key, this->info->GetName(), path_to_store))
+ {
+ wchar_t dlgtitle[256] = {0};
+ CreateDirectoryW(path_to_store, NULL);
+
+ wchar_t destfile[MAX_PATH] = {0};
+ PathCombineW(destfile, path_to_store, destFileSpec);
+
+ httpRetrieveFileW(hMainWindow, AutoChar(url), destfile, getStringW(IDS_DOWNLOADING,dlgtitle,256));
+
+ // TODO: optional adding to media library or not (param 3)
+ LMDB_FILE_ADD_INFOW fi = {const_cast<wchar_t *>(destfile), -1, -1};
+ sendMlIpc(ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi);
+ sendMlIpc(ML_IPC_DB_SYNCDB, 0);
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::DownloaderAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE;
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::DownloaderAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::DownloaderAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::DownloaderAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
diff --git a/Src/Winamp/JSAPI2_ExternalObject.cpp b/Src/Winamp/JSAPI2_ExternalObject.cpp
new file mode 100644
index 00000000..53ccb1f9
--- /dev/null
+++ b/Src/Winamp/JSAPI2_ExternalObject.cpp
@@ -0,0 +1,307 @@
+#include "JSAPI2_ExternalObject.h"
+#include "JSAPI2_svc_apicreator.h"
+#include "JSAPI2_TransportAPI.h"
+#include "JSAPI2_PlayerAPI.h"
+#include "JSAPI2_Downloader.h"
+#include "JSAPI2_SecurityAPI.h"
+#include "JSAPI2_Security.h"
+#include "JSAPI2_Bookmarks.h"
+#include "JSAPI2_Application.h"
+#include "JSAPI2_SkinAPI.h"
+#include "JSAPI2_MediaCore.h"
+#include "JSAPI2_AsyncDownloader.h"
+#include "JSAPI.h"
+#include "api.h"
+
+#include "main.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoCharFn.h"
+#include <api/service/waservicefactory.h>
+#include <shlwapi.h>
+/* benski: basic thoughts
+
+ExternalObject will be created "on demand" when ml_online loads a page
+so ExternalObjects will have a lifetime (unlike ExternalCOM which is a singleton)
+
+create wasabi services for creating window.external.* objects
+when a window.external.* function is requested, services are enumerated
+the key is passed to the object creator. The returned object will be treated
+as a singleton from ExternalObject's perspective. It will be Release()'d when
+the ExternalObject is destroyed.
+
+the basic layout will be
+window.external.API.method
+
+e.g.
+window.external.Transport.Play();
+
+any time that non-singleton objects need to be created (Config object,
+playlist object, etc) they will be created from a method within the API object
+e.g.
+var new_playlist = window.external.Playlist.Create();
+*/
+
+JSAPI2::ExternalObject::ExternalObject(const wchar_t *_key)
+{
+ hwnd=0;
+
+ if (_key)
+ key = _wcsdup(_key);
+ else
+ key = 0;
+
+ refCount = 1;
+ // create Config API now.
+
+ ConfigCOM *configCOM;
+ wchar_t szPath[MAX_PATH] = {0};
+ PathCombineW(szPath, CONFIGDIR, L"jscfg.ini");
+ if (SUCCEEDED(ConfigCOM::CreateInstanceW(key, AutoCharFn(szPath), &configCOM)))
+ {
+ AddDispatch(L"Config", configCOM);
+ configCOM->Release();
+ }
+}
+
+JSAPI2::ExternalObject::~ExternalObject()
+{
+ for (JSAPI::DispatchTable::iterator itr = dispatchTable.begin(); itr != dispatchTable.end(); itr++)
+ {
+ //JSAPI::Dispatcher *entry = *itr;
+ delete (*itr);
+ }
+ dispatchTable.clear();
+ if (key) free(key);
+}
+
+DWORD JSAPI2::ExternalObject::AddDispatch(const wchar_t *name, IDispatch *object)
+{
+ int id = (int) dispatchTable.size();
+ dispatchTable.push_back(new JSAPI::Dispatcher(name, id, object));
+
+ return id;
+}
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT JSAPI2::ExternalObject::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ if (GetDispID(rgszNames[i], fdexNameCaseSensitive, &rgdispid[i]) == DISPID_UNKNOWN)
+ unknowns=true;
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::ExternalObject::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ return InvokeEx(dispid, lcid, wFlags, pdispparams, pvarResult, pexecinfo, 0);
+}
+
+STDMETHODIMP JSAPI2::ExternalObject::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else if (IsEqualIID(riid, IID_IWasabiDispatchable))
+ *ppvObject = (IWasabiDispatchable *)this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::ExternalObject::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+ULONG JSAPI2::ExternalObject::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
+
+HRESULT JSAPI2::ExternalObject::GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+ *pid = DISP_E_UNKNOWNNAME;
+
+ for (size_t entry=0;entry!=dispatchTable.size();entry++)
+ {
+ if (!wcscmp(bstrName, dispatchTable[entry]->name))
+ {
+ if (dispatchTable[entry]->object)
+ {
+ *pid = (DISPID)entry;
+ return S_OK;
+ }
+ else
+ {
+ return DISPID_UNKNOWN;
+ }
+ }
+ }
+ // look it up in wasabi
+ IDispatch *disp = 0;
+ waServiceFactory *sf = 0;
+ int n = 0;
+ do
+ {
+ sf = WASABI_API_SVC->service_enumService(JSAPI2::svc_apicreator::getServiceType(), n++);
+ if (!sf)
+ break;
+
+ if (sf)
+ {
+ JSAPI2::svc_apicreator *creator = (JSAPI2::svc_apicreator *)sf->getInterface();
+ if (creator)
+ {
+ disp = creator->CreateAPI(bstrName, key, static_cast<JSAPI::ifc_info *>(this));
+ }
+ sf->releaseInterface(creator);
+ }
+ } while (sf && !disp);
+ *pid = AddDispatch(bstrName, disp);
+ if (!disp)
+ {
+ *pid = DISP_E_UNKNOWNNAME;
+ return DISPID_UNKNOWN;
+ }
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::ExternalObject::InvokeEx(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+ if (id >= 0 && (size_t)id < dispatchTable.size())
+ {
+ IDispatch *disp = dispatchTable[id]->object;
+ if (disp)
+ disp->AddRef(); // I assume we're supposed to do this, but I'm not 100% sure
+ JSAPI_INIT_RESULT(pvarRes, VT_DISPATCH);
+ JSAPI_SET_RESULT(pvarRes, pdispVal, disp);
+ return S_OK;
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+
+}
+
+HRESULT JSAPI2::ExternalObject::DeleteMemberByName(BSTR bstrName, DWORD grfdex)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::DeleteMemberByDispID(DISPID id)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::GetMemberProperties(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::GetMemberName(DISPID id, BSTR *pbstrName)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::GetNextDispID(DWORD grfdex, DISPID id, DISPID *pid)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::GetNameSpaceParent(IUnknown **ppunk)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::ExternalObject::QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable)
+{
+ if (IsEqualIID(riid, JSAPI::IID_JSAPI_ifc_info))
+ {
+ *ppDispatchable = (JSAPI::ifc_info *)this;
+ }
+ else
+ {
+ *ppDispatchable = NULL;
+ return E_NOINTERFACE;
+ }
+ (*ppDispatchable)->AddRef();
+ return S_OK;
+}
+
+const wchar_t *JSAPI2::ExternalObject::GetUserAgent()
+{
+ return L"JSAPI2";
+}
+
+void JSAPI2::ExternalObject::SetHWND(HWND hwnd)
+{
+ this->hwnd = hwnd;
+}
+
+HWND JSAPI2::ExternalObject::GetHWND()
+{
+ return hwnd;
+}
+
+void JSAPI2::ExternalObject::SetName(const wchar_t *name)
+{
+ JSAPI2::security.AssociateName(key, name);
+}
+
+const wchar_t *JSAPI2::ExternalObject::GetName()
+{
+ return JSAPI2::security.GetAssociatedName(key);
+}
+
+int JSAPI2::ExternalObject::AddAPI(const wchar_t *name, IDispatch *dispatch)
+{
+ if (dispatch)
+ {
+ dispatch->AddRef();
+ AddDispatch(name, dispatch);
+ return 0;
+ }
+ return 1;
+}
+
+
+#define CBCLASS JSAPI2::ExternalObject
+START_DISPATCH;
+CB(JSAPI_IFC_INFO_GETUSERAGENT, GetUserAgent)
+VCB(JSAPI_IFC_INFO_SETHWND, SetHWND)
+CB(JSAPI_IFC_INFO_GETHWND, GetHWND)
+VCB(JSAPI_IFC_INFO_SETNAME, SetName)
+CB(JSAPI_IFC_INFO_GETNAME, GetName)
+CB(JSAPI_IFC_INFO_ADDAPI, AddAPI)
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Winamp/JSAPI2_ExternalObject.h b/Src/Winamp/JSAPI2_ExternalObject.h
new file mode 100644
index 00000000..e609f253
--- /dev/null
+++ b/Src/Winamp/JSAPI2_ExternalObject.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <ocidl.h>
+#include "JSAPI_DispatchTable.h"
+#include "../nu/ConfigCOM.h"
+#include "IWasabiDispatchable.h"
+#include "JSAPI_Info.h"
+#include <dispex.h>
+
+namespace JSAPI2
+{
+ class ExternalObject : public IDispatchEx,
+ public IWasabiDispatchable,
+ public JSAPI::ifc_info
+ {
+ public:
+ ExternalObject(const wchar_t *_key);
+ ~ExternalObject();
+ // *** IUnknown Methods ***
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ private:
+ // *** IDispatch Methods ***
+ STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD(GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD(GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ // *** IDispatchEx Methods ***
+ STDMETHOD (GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid);
+ STDMETHOD (InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller);
+ STDMETHOD (DeleteMemberByName)(BSTR bstrName, DWORD grfdex) ;
+ STDMETHOD (DeleteMemberByDispID)(DISPID id);
+ STDMETHOD (GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex);
+ STDMETHOD (GetMemberName)(DISPID id, BSTR *pbstrName);
+ STDMETHOD (GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid);
+ STDMETHOD (GetNameSpaceParent)(IUnknown **ppunk);
+
+ // *** IWasabiDispatchable Methods ***
+ STDMETHOD(QueryDispatchable)(REFIID riid, Dispatchable **ppDispatchable);
+
+ // *** JSAPI::ifc_info Methods ***
+ const wchar_t *GetUserAgent();
+ void SetHWND(HWND hwnd);
+ HWND GetHWND();
+ void SetName(const wchar_t *name);
+ const wchar_t *GetName();
+ int AddAPI(const wchar_t *name, IDispatch *dispatch);
+ private:
+ // private helper methods
+ DWORD AddDispatch(const wchar_t *name, IDispatch *object);
+
+ // members
+ JSAPI::DispatchTable dispatchTable;
+ volatile LONG refCount;
+ wchar_t *key;
+ HWND hwnd;
+ protected:
+ RECVS_DISPATCH;
+ };
+}
diff --git a/Src/Winamp/JSAPI2_MediaCore.cpp b/Src/Winamp/JSAPI2_MediaCore.cpp
new file mode 100644
index 00000000..d73bd3cf
--- /dev/null
+++ b/Src/Winamp/JSAPI2_MediaCore.cpp
@@ -0,0 +1,285 @@
+#include "JSAPI2_MediaCore.h"
+#include "main.h"
+#include "api.h"
+#include "JSAPI.h"
+#include "JSAPI2_Security.h"
+#include "JSAPI2_CallbackManager.h"
+
+JSAPI2::MediaCoreAPI::MediaCoreAPI(const wchar_t *_key, JSAPI::ifc_info *_info) : metadataGuard("MediaCoreAPI metadata Guard")
+{
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+JSAPI2::MediaCoreAPI::~MediaCoreAPI()
+{
+ JSAPI2::callbackManager.Deregister(this);
+}
+
+#define DISP_TABLE \
+ CHECK_ID(IsRegisteredExtension)\
+ CHECK_ID(GetMetadata)\
+ CHECK_ID(AddMetadataHook)\
+ CHECK_ID(RemoveMetadataHook)\
+
+
+#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
+enum {
+ DISP_TABLE
+};
+
+#undef CHECK_ID
+#define CHECK_ID(str)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
+
+HRESULT JSAPI2::MediaCoreAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::MediaCoreAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::MediaCoreAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::MediaCoreAPI::IsRegisteredExtension(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ const wchar_t *extension = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ int start_offs=0;
+ wchar_t filename[MAX_PATH] = {0};
+ StringCbPrintfW(filename, sizeof(filename), L"test.%s", extension);
+ In_Module *i = in_setmod_noplay(filename, &start_offs);
+ if (i)
+ V_BOOL(pvarResult) = VARIANT_TRUE;
+ else
+ V_BOOL(pvarResult) = VARIANT_FALSE;
+
+ return S_OK;
+}
+
+HRESULT JSAPI2::MediaCoreAPI::GetMetadata(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ if (security.GetActionAuthorization(L"mediacore", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ wchar_t buffer[4096] = {0};
+ extendedFileInfoStructW info;
+
+ info.filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ info.metadata = JSAPI_PARAM(pdispparams, 2).bstrVal;
+ info.ret = buffer;
+ info.retlen = sizeof(buffer)/sizeof(*buffer);
+
+ if (NULL != info.filename &&
+ NULL != info.metadata)
+ {
+ if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ info.ret = NULL;
+
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
+ }
+ else
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+
+ return S_OK;
+}
+void JSAPI2::MediaCoreAPI::RemoveMetadataHook(const wchar_t *filename)
+{
+ Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
+RemoveMetadataHook_again:
+ MetadataMap::iterator itr;
+ for (itr=metadataMap.begin();itr!=metadataMap.end();itr++)
+ {
+ if (!_wcsicmp(filename, itr->url.c_str()))
+ {
+ metadataMap.erase(itr);
+ goto RemoveMetadataHook_again;
+ }
+ }
+}
+
+void JSAPI2::MediaCoreAPI::RemoveMetadataHook(const wchar_t *filename, const wchar_t *tag)
+{
+ Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
+RemoveMetadataHook_again2:
+ MetadataMap::iterator itr;
+ for (itr=metadataMap.begin();itr!=metadataMap.end();itr++)
+ {
+ if (!_wcsicmp(filename, itr->url.c_str())
+ && !_wcsicmp(tag, itr->tag.c_str()))
+ {
+ metadataMap.erase(itr);
+ goto RemoveMetadataHook_again2;
+ }
+ }
+}
+
+HRESULT JSAPI2::MediaCoreAPI::AddMetadataHook(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 3);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 3, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"mediacore", L"metadatahook", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ const wchar_t *filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ const wchar_t *tag = JSAPI_PARAM(pdispparams, 2).bstrVal;
+ const wchar_t *value = JSAPI_PARAM(pdispparams, 3).bstrVal;
+
+ if (NULL == filename || L'\0' == *filename ||
+ NULL == tag || L'\0' == *tag)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ return S_OK;
+ }
+
+ JSAPI2::callbackManager.Register(this);
+ metadata_info info;
+ info.url = filename;
+ info.tag = tag;
+ info.metadata= value;
+
+ Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
+
+ RemoveMetadataHook(filename, tag);
+
+ metadataMap.push_back(info);
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+
+ return S_OK;
+}
+
+HRESULT JSAPI2::MediaCoreAPI::RemoveMetadataHook(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ const wchar_t *filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ const wchar_t *tag = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
+
+ if (NULL == filename || L'\0' == *filename)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ return S_OK;
+ }
+
+ if (NULL != tag && L'\0' == *tag)
+ tag = NULL;
+
+ if (NULL != tag)
+ RemoveMetadataHook(filename, tag);
+ else
+ RemoveMetadataHook(filename);
+
+
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+
+ return S_OK;
+}
+
+bool JSAPI2::MediaCoreAPI::OverrideMetadata(const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch)
+{
+ Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
+ MetadataMap::iterator itr;
+ for (itr=metadataMap.begin();itr!=metadataMap.end();itr++)
+ {
+ if (!_wcsicmp(filename, itr->url.c_str()) && !_wcsicmp(tag, itr->tag.c_str()))
+ {
+ StringCchCopyW(out, outCch, itr->metadata.c_str());
+ return true;
+ }
+ }
+ return false;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::MediaCoreAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::MediaCoreAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::MediaCoreAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::MediaCoreAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
diff --git a/Src/Winamp/JSAPI2_MediaCore.h b/Src/Winamp/JSAPI2_MediaCore.h
new file mode 100644
index 00000000..53cd57d9
--- /dev/null
+++ b/Src/Winamp/JSAPI2_MediaCore.h
@@ -0,0 +1,48 @@
+#pragma once
+#include <ocidl.h>
+#include <vector>
+#include <string>
+#include "../nu/AutoLock.h"
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class MediaCoreAPI : public IDispatch
+ {
+ public:
+ MediaCoreAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ ~MediaCoreAPI();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ /* For CallbackManager */
+ bool OverrideMetadata(const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch);
+ private:
+ const wchar_t *key;
+ volatile LONG refCount;
+ JSAPI::ifc_info *info;
+
+struct metadata_info
+{
+ std::wstring url;
+ std::wstring tag;
+ std::wstring metadata;
+};
+typedef std::vector<metadata_info> MetadataMap;
+MetadataMap metadataMap;
+Nullsoft::Utility::LockGuard metadataGuard;
+
+ STDMETHOD (IsRegisteredExtension)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (GetMetadata)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (AddMetadataHook)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (RemoveMetadataHook)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ void RemoveMetadataHook(const wchar_t *filename);
+ void RemoveMetadataHook(const wchar_t *filename, const wchar_t *tag);
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_PlayerAPI.cpp b/Src/Winamp/JSAPI2_PlayerAPI.cpp
new file mode 100644
index 00000000..3fd74c04
--- /dev/null
+++ b/Src/Winamp/JSAPI2_PlayerAPI.cpp
@@ -0,0 +1,384 @@
+#include "JSAPI2_PlayerAPI.h"
+#include "JSAPI2_Security.h"
+#include "main.h"
+#include "JSAPI.h"
+#include "ipc_pe.h"
+#include <strsafe.h>
+
+JSAPI2::PlayerAPI::PlayerAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
+{
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+enum
+{
+ DISPID_PLAYERAPI_PLAY, // start playing a file immediately (and clear the old playlist)
+ DISPID_PLAYERAPI_ENQUEUE, // insert a URL at the end of the playlist
+ DISPID_PLAYERAPI_INSERT, // insert a URL at a particular position in the playlist
+ DISPID_PLAYERAPI_CLEARQUEUE, // clear the playlist
+ DISPID_PLAYERAPI_GETURL, // get the URL (or filename) for an item in the playlist
+ DISPID_PLAYERAPI_GETTITLE, // get title for an item in the playlist
+ DISPID_PLAYERAPI_GETMETADATA, // get a metadata string for an item in the playlist
+
+ // properties
+ DISPID_PLAYERAPI_LENGTH, // length of the playlist
+ DISPID_PLAYERAPI_POSITION, // position in the playlist
+};
+
+#define DISP_TABLE \
+ CHECK_ID(Play, DISPID_PLAYERAPI_PLAY)\
+ CHECK_ID(Enqueue, DISPID_PLAYERAPI_ENQUEUE)\
+ CHECK_ID(Insert, DISPID_PLAYERAPI_INSERT)\
+ CHECK_ID(ClearQueue, DISPID_PLAYERAPI_CLEARQUEUE)\
+ CHECK_ID(GetURL, DISPID_PLAYERAPI_GETURL)\
+ CHECK_ID(GetTitle, DISPID_PLAYERAPI_GETTITLE)\
+ CHECK_ID(GetMetadata, DISPID_PLAYERAPI_GETMETADATA)\
+ CHECK_ID(length, DISPID_PLAYERAPI_LENGTH)\
+ CHECK_ID(cursor, DISPID_PLAYERAPI_POSITION)\
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT JSAPI2::PlayerAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::PlayerAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::PlayerAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::PlayerAPI::Play(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ enqueueFileWithMetaStructW s = {0,0,0,0};
+ SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_DELETE);
+
+ //PlayList_delete();
+ s.filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ s.title = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
+ s.ext = NULL;
+ s.length = JSAPI_PARAM_OPTIONAL(pdispparams, 3, lVal, 0);
+
+ /*if (title)
+ PlayList_append_withinfo(filename, title, length);
+ else
+ PlayList_appendthing(filename, 0);
+ plEditRefresh();
+ */
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
+ SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_STARTPLAY);
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::PlayerAPI::Enqueue(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ enqueueFileWithMetaStructW s = {0,0,0,0};
+
+ //PlayList_delete();
+ s.filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ s.title = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
+ s.ext = NULL;
+ s.length = JSAPI_PARAM_OPTIONAL(pdispparams, 3, lVal, 0);
+
+ /*if (title)
+ PlayList_append_withinfo(filename, title, length);
+ else
+ PlayList_appendthing(filename, 0);
+ plEditRefresh();
+ */
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
+
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+
+HRESULT JSAPI2::PlayerAPI::Insert(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 2, 4);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 4, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ fileinfoW info;
+ COPYDATASTRUCT cds;
+ cds.dwData = IPC_PE_INSERTFILENAMEW;
+ cds.lpData = &info;
+ cds.cbData = sizeof(info);
+ StringCbCopyW(info.file, sizeof(info.file), JSAPI_PARAM(pdispparams, 2).bstrVal);
+ info.index = JSAPI_PARAM(pdispparams, 1).lVal;
+ // benski> TODO const wchar_t *title = JSAPI_PARAM_OPTIONAL(pdispparams, 3, bstrVal, 0);
+ // benski> TODO int length = JSAPI_PARAM_OPTIONAL(pdispparams, 4, lVal, 0);
+
+ SendMessageW(hPLWindow, WM_COPYDATA, 0, (LPARAM)&cds);
+
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::PlayerAPI::ClearQueue(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_DELETE);
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::PlayerAPI::GetURL(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ if (security.GetActionAuthorization(L"player", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ int position = JSAPI_PARAM(pdispparams, 1).lVal;
+ wchar_t filename[FILENAME_SIZE] = {0};
+ if (PlayList_getitem2W(position, filename, 0) == 0)
+ {
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(filename));
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::PlayerAPI::GetTitle(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ if (security.GetActionAuthorization(L"player", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ int position = JSAPI_PARAM(pdispparams, 1).lVal;
+ wchar_t filetitle[FILETITLE_SIZE] = {0};
+ if (PlayList_getitem2W(position, 0, filetitle) == 0)
+ {
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(filetitle));
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::PlayerAPI::GetMetadata(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ if (security.GetActionAuthorization(L"player", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ int position = JSAPI_PARAM(pdispparams, 1).lVal;
+ wchar_t filename[FILENAME_SIZE] = {0};
+ if (PlayList_getitem2W(position, filename, 0) == 0)
+ {
+ wchar_t buffer[4096] = {0};
+ extendedFileInfoStructW info;
+
+ info.filename = filename;
+ info.metadata = JSAPI_PARAM(pdispparams, 2).bstrVal;
+ info.ret = buffer;
+ info.retlen = sizeof(buffer)/sizeof(*buffer);
+
+ if (NULL != info.filename &&
+ NULL != info.metadata)
+ {
+ if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ info.ret = NULL;
+
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
+ }
+ else
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::PlayerAPI::length(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = PlayList_getlength();
+ return S_OK;
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::PlayerAPI::cursor(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+ if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ PlayList_setposition(JSAPI_PARAM(pdispparams, 1).lVal);
+ plEditRefresh();
+ }
+ return S_OK;
+ }
+ else if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = PlayList_getPosition();
+ return S_OK;
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+
+#undef CHECK_ID
+#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::PlayerAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::PlayerAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::PlayerAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::PlayerAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
diff --git a/Src/Winamp/JSAPI2_PlayerAPI.h b/Src/Winamp/JSAPI2_PlayerAPI.h
new file mode 100644
index 00000000..6c622ef6
--- /dev/null
+++ b/Src/Winamp/JSAPI2_PlayerAPI.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <ocidl.h>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class PlayerAPI : public IDispatch
+ {
+ public:
+ PlayerAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ private:
+ const wchar_t *key;
+ volatile LONG refCount;
+ JSAPI::ifc_info *info;
+
+ STDMETHOD (Play)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (Enqueue)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (Insert)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (ClearQueue)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (GetURL)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (GetTitle)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (GetMetadata)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+
+ STDMETHOD (length)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (cursor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_Security.cpp b/Src/Winamp/JSAPI2_Security.cpp
new file mode 100644
index 00000000..3e8706b1
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Security.cpp
@@ -0,0 +1,255 @@
+#include "api.h"
+#include "JSAPI2_Security.h"
+#include "JSAPI2_svc_apicreator.h"
+#include <bfc/platform/types.h>
+#include "main.h"
+#include "resource.h"
+#include "language.h"
+#include <api/service/waservicefactory.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+JSAPI2::Security::~Security()
+{
+ for(NameMap::iterator iter = names.begin(); iter != names.end(); iter++)
+ {
+ if (NULL != iter->second)
+ free(iter->second);
+ }
+}
+
+int JSAPI2::Security::GetActionAuthorization( const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization, AuthorizationData *data )
+{
+ // TODO: benski> we should build a cache table, as we may hit this function repeatedly and it incurs a file lock
+ // but for now it will get the ball rolling
+ if ( action )
+ {
+ wchar_t group_action[ 256 ] = { 0 };
+ StringCbPrintfW( group_action, sizeof( group_action ), L"%s@%s", action, group );
+ int authorization = GetPrivateProfileIntW( authorization_key, group_action, api_security::ACTION_UNDEFINED, JSAPI2_INIFILE );
+ if ( authorization != api_security::ACTION_UNDEFINED )
+ return authorization;
+ }
+ if ( group )
+ {
+ int authorization = GetPrivateProfileIntW( authorization_key, group, api_security::ACTION_UNDEFINED, JSAPI2_INIFILE );
+ if ( authorization != api_security::ACTION_UNDEFINED )
+ return authorization;
+ }
+
+ int authorization = GetPrivateProfileIntW( authorization_key, authorization_key, default_authorization, JSAPI2_INIFILE );
+
+ if ( ( ACTION_UNDEFINED == authorization || ACTION_PROMPT == authorization ) &&
+ false != IsAuthorizationBypassed( authorization_key ) )
+ {
+ authorization = ACTION_ALLOWED;
+ }
+
+ if ( ( authorization == ACTION_UNDEFINED || authorization == ACTION_PROMPT )/* if we have to prompt */
+ && default_authorization != ACTION_UNDEFINED /* clients pass ACTION_UNDEFINED, API's don't */
+ && group )
+ {
+ waServiceFactory *sf = 0;
+ int n = 0;
+ do
+ {
+ sf = WASABI_API_SVC->service_enumService( JSAPI2::svc_apicreator::getServiceType(), n++ );
+ if ( !sf )
+ break;
+
+ if ( sf )
+ {
+ JSAPI2::svc_apicreator *creator = (JSAPI2::svc_apicreator *)sf->getInterface();
+ if ( creator )
+ {
+ HWND parent = 0;
+ if ( info )
+ parent = info->GetHWND();
+ if ( !parent )
+ parent = this->GetAssociation( authorization_key );
+
+ int prompt = creator->PromptForAuthorization( parent, group, action, authorization_key, data );
+ if ( ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_MASK ) != JSAPI2::svc_apicreator::AUTHORIZATION_UNDEFINED )
+ {
+ sf->releaseInterface( creator );
+ int new_authorization = 0;
+ switch ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_MASK )
+ {
+ case JSAPI2::svc_apicreator::AUTHORIZATION_ALLOW:
+ new_authorization = ACTION_ALLOWED;
+ break;
+ case JSAPI2::svc_apicreator::AUTHORIZATION_DENY:
+ new_authorization = ACTION_DISALLOWED;
+ break;
+ default:
+ return default_authorization;
+ }
+ if ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY )
+ action = 0;
+ if ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS )
+ SetActionAuthorization( group, action, authorization_key, new_authorization );
+ if ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS_FOR_SERVICE )
+ SetActionAuthorization( 0, 0, authorization_key, new_authorization );
+
+ return new_authorization;
+ }
+ }
+
+ sf->releaseInterface( creator );
+ }
+ } while ( sf );
+ }
+
+ return authorization;
+}
+
+int JSAPI2::Security::SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization)
+{
+ // TODO: benski> we should build a cache table, as we may hit this function repeatedly and it incurs a file lock
+ // but for now it will get the ball rolling
+ wchar_t intval[64] = {0};
+ _itow(authorization, intval, 10);
+ if (action)
+ {
+ wchar_t group_action[256] = {0};
+ StringCbPrintfW(group_action, sizeof(group_action), L"%s@%s", action, group);
+ WritePrivateProfileStringW(authorization_key, group_action, intval, JSAPI2_INIFILE);
+ }
+ else if (group)
+ WritePrivateProfileStringW(authorization_key, group, intval, JSAPI2_INIFILE);
+ else
+ WritePrivateProfileStringW(authorization_key, authorization_key, intval, JSAPI2_INIFILE);
+
+ return JSAPI2::api_security::SUCCESS;
+}
+
+void JSAPI2::Security::Associate(const wchar_t *authorization_key, HWND hwnd)
+{
+ unsigned long key;
+ if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
+ return;
+
+ associations[key] = (void *)hwnd;
+}
+
+HWND JSAPI2::Security::GetAssociation(const wchar_t *authorization_key)
+{
+ unsigned long key;
+ if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
+ return NULL;
+
+ AssociationMap::iterator iter = associations.find(key);
+ return (HWND)((iter != associations.end()) ? iter->second : NULL);
+}
+
+
+INT_PTR JSAPI2_SecurityPrompt(HWND hParent, LPCWSTR pszCaption, LPCWSTR pszTitle, LPCWSTR pszMessage, UINT flags);
+
+int JSAPI2::Security::SecurityPrompt(HWND parent, const wchar_t *title_string, const wchar_t *display_string, int flags)
+{
+ return (INT_PTR)JSAPI2_SecurityPrompt(parent, NULL, title_string, display_string, flags);
+}
+
+void JSAPI2::Security::AssociateName(const wchar_t *authorization_key, const wchar_t *name)
+{
+ unsigned long key;
+ if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
+ return;
+
+ NameMap::iterator iter = names.find(key);
+ if (NULL != name)
+ {
+ if (iter != names.end())
+ {
+ if (NULL != iter->second) free(iter->second);
+ iter->second = _wcsdup(name);
+ }
+ else
+ {
+ names.insert({key, _wcsdup(name)});
+ }
+ }
+ else
+ {
+ if (iter != names.end())
+ {
+ if (NULL != iter->second)
+ {
+ free(iter->second);
+ iter->second = NULL;
+ }
+ names.erase(iter);
+ }
+ }
+}
+
+const wchar_t *JSAPI2::Security::GetAssociatedName(const wchar_t *authorization_key)
+{
+ unsigned long key;
+ if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
+ return NULL;
+
+ NameMap::iterator iter = names.find(key);
+ return (iter != names.end()) ? iter->second : NULL;
+}
+
+void JSAPI2::Security::ResetAuthorization(const wchar_t *authorization_key)
+{
+ const wchar_t empty[2] = {0, 0};
+ WritePrivateProfileSectionW(authorization_key, empty, JSAPI2_INIFILE);
+}
+
+void JSAPI2::Security::SetBypass(const wchar_t *authorization_key, bool enable_bypass)
+{
+ size_t index = bypassList.size();
+
+ unsigned long key;
+ if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
+ return;
+
+ while(index--)
+ {
+ if (bypassList[index] == key)
+ {
+ if (false == enable_bypass)
+ bypassList.erase(bypassList.begin() + index);
+ return;
+ }
+ }
+
+ if (false != enable_bypass)
+ bypassList.push_back(key);
+}
+
+bool JSAPI2::Security::IsAuthorizationBypassed(const wchar_t *authorization_key)
+{
+ size_t index = bypassList.size();
+ if (0 == index) return false;
+
+ unsigned long key;
+ if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
+ return false;
+
+ while(index--)
+ {
+ if (bypassList[index] == key)
+ return true;
+ }
+ return false;
+}
+
+JSAPI2::Security JSAPI2::security;
+
+#define CBCLASS JSAPI2::Security
+START_DISPATCH;
+CB(JSAPI2_API_SECURITY_GETACTIONAUTHORIZATION, GetActionAuthorization);
+CB(JSAPI2_API_SECURITY_SETACTIONAUTHORIZATION, SetActionAuthorization);
+VCB(JSAPI2_API_SECURITY_ASSOCIATE, Associate);
+CB(JSAPI2_API_SECURITY_GETASSOCIATION, GetAssociation);
+CB(JSAPI2_API_SECURITY_SECURITYPROMPT, SecurityPrompt);
+VCB(JSAPI2_API_SECURITY_ASSOCIATENAME, AssociateName);
+CB(JSAPI2_API_SECURITY_GETASSOCIATEDNAME, GetAssociatedName);
+VCB(JSAPI2_API_SECURITY_RESETAUTHORIZATION, ResetAuthorization);
+VCB(JSAPI2_API_SECURITY_SETBYPASS, SetBypass);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_Security.h b/Src/Winamp/JSAPI2_Security.h
new file mode 100644
index 00000000..a7bbe914
--- /dev/null
+++ b/Src/Winamp/JSAPI2_Security.h
@@ -0,0 +1,43 @@
+#pragma once
+#include "JSAPI2_api_security.h"
+#include <bfc/platform/types.h>
+#include <map>
+#include <vector>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class Security : public JSAPI2::api_security
+ {
+ public:
+ ~Security();
+ static const char *getServiceName() { return "JSAPI2 Security API"; }
+ static const GUID getServiceGuid() { return api_securityGUID; }
+ int GetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization = ACTION_UNDEFINED, AuthorizationData *data = 0);
+ int SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization);
+ void Associate(const wchar_t *authorization_key, HWND hwnd);
+ HWND GetAssociation(const wchar_t *authorization_key);
+ int SecurityPrompt(HWND hwnd, const wchar_t *title_string, const wchar_t *display_string, int flags);
+ void AssociateName(const wchar_t *authorization_key, const wchar_t *name);
+ const wchar_t *GetAssociatedName(const wchar_t *authorization_key);
+ void ResetAuthorization(const wchar_t *authorization_key);
+ void SetBypass(const wchar_t *authorization_key, bool enable_bypass);
+
+ protected:
+ bool IsAuthorizationBypassed(const wchar_t *authorization_key);
+
+ protected:
+ RECVS_DISPATCH;
+
+
+ private:
+ typedef std::map<uint32_t, wchar_t*> NameMap;
+ typedef std::map<uint32_t, void*> AssociationMap;
+ typedef std::vector<uint32_t> BypassList;
+ AssociationMap associations;
+ NameMap names;
+ BypassList bypassList;
+ };
+
+ extern Security security;
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_SecurityAPI.cpp b/Src/Winamp/JSAPI2_SecurityAPI.cpp
new file mode 100644
index 00000000..56c11328
--- /dev/null
+++ b/Src/Winamp/JSAPI2_SecurityAPI.cpp
@@ -0,0 +1,132 @@
+#include "JSAPI2_SecurityAPI.h"
+#include "JSAPI2_Security.h"
+#include "main.h"
+#include "JSAPI.h"
+
+JSAPI2::SecurityAPI::SecurityAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
+{
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+enum
+{
+ DISPID_SECURITYAPI_SETACTIONAUTHORIZATION,
+ DISPID_SECURITYAPI_GETACTIONAUTHORIZATION,
+};
+
+#define DISP_TABLE \
+ CHECK_ID(SetActionAuthorization, DISPID_SECURITYAPI_SETACTIONAUTHORIZATION)\
+ CHECK_ID(GetActionAuthorization, DISPID_SECURITYAPI_GETACTIONAUTHORIZATION)\
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT JSAPI2::SecurityAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::SecurityAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::SecurityAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::SecurityAPI::GetActionAuthorization(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_I4);
+ JSAPI_SET_RESULT(pvarResult, lVal, security.GetActionAuthorization(JSAPI_PARAM(pdispparams, 1).bstrVal, JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0), key, info, JSAPI2::api_security::ACTION_UNDEFINED));
+ return S_OK;
+}
+
+HRESULT JSAPI2::SecurityAPI::SetActionAuthorization(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 3);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 3, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ if (security.GetActionAuthorization(L"security", L"set", key, info, JSAPI2::api_security::ACTION_DISALLOWED) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ const wchar_t *group = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ const wchar_t *action = JSAPI_PARAM(pdispparams, 2).bstrVal;
+ int authorization = JSAPI_PARAM(pdispparams, 2).lVal;
+ security.SetActionAuthorization(group, action, key, authorization);
+ }
+ else
+ {
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ }
+ return S_OK;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::SecurityAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::SecurityAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::SecurityAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::SecurityAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
diff --git a/Src/Winamp/JSAPI2_SecurityAPI.h b/Src/Winamp/JSAPI2_SecurityAPI.h
new file mode 100644
index 00000000..a330bb00
--- /dev/null
+++ b/Src/Winamp/JSAPI2_SecurityAPI.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <ocidl.h>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class SecurityAPI : public IDispatch
+ {
+ public:
+ SecurityAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ private:
+ const wchar_t *key;
+ JSAPI::ifc_info *info;
+ volatile LONG refCount;
+
+ STDMETHOD (GetActionAuthorization)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (SetActionAuthorization)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_SecurityPrompt.cpp b/Src/Winamp/JSAPI2_SecurityPrompt.cpp
new file mode 100644
index 00000000..cf16e013
--- /dev/null
+++ b/Src/Winamp/JSAPI2_SecurityPrompt.cpp
@@ -0,0 +1,718 @@
+#include "main.h"
+#include "./resource.h"
+#include "./api.h"
+#include "./language.h"
+#include "./jsapi2_svc_apicreator.h"
+#include "./commandLink.h"
+
+
+#include <strsafe.h>
+
+
+#ifndef LONGX86
+#ifdef _WIN64
+ #define LONGX86 LONG_PTR
+#else /*_WIN64*/
+ #define LONGX86 LONG
+#endif /*_WIN64*/
+#endif // LONGX86
+
+#ifdef WIN64
+ #define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWLP_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
+#else
+ #define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWL_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
+#endif
+
+#ifdef __cplusplus
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) ::SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#else
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#endif // __cplusplus
+
+#define SENDWAIPC(__ipcMsgId, __param) SENDMSG(hMainWindow, WM_WA_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
+
+
+#ifndef OIC_WARNING
+#define OIC_WARNING 32515
+#endif
+
+#define SECDLG_PROP L"SecurityPromptProp"
+
+#ifndef IDC_HELPLINK
+#define IDC_HELPLINK 10000
+#endif
+
+typedef struct __SECDLGCREATEPARAM
+{
+ HWND hCenter;
+ LPCWSTR pszCaption;
+ LPCWSTR pszTitle;
+ LPCWSTR pszMessage;
+ UINT flags;
+} SECDLGCREATEPARAM;
+
+typedef struct __SECDLG
+{
+ HFONT titleFont;
+ SIZE minSize;
+ SIZE maxSize;
+} SECDLG;
+
+#define GetDialog(__hwnd) ((SECDLG*)GetPropW((__hwnd), SECDLG_PROP))
+
+static INT_PTR CALLBACK SecurityPrompt_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+static HWND SecurityPrompt_GetPlayerWindow()
+{
+ return (NULL != g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow;
+}
+
+INT_PTR JSAPI2_SecurityPrompt(HWND hParent, LPCWSTR pszCaption, LPCWSTR pszTitle, LPCWSTR pszMessage, UINT flags)
+{
+ SECDLGCREATEPARAM param;
+ ZeroMemory(&param, sizeof(SECDLGCREATEPARAM));
+ param.hCenter = hParent;
+ param.flags = flags;
+ param.pszCaption = pszCaption;
+ param.pszTitle = pszTitle;
+ param.pszMessage = pszMessage;
+
+
+ if (NULL == hParent)
+ hParent = SecurityPrompt_GetPlayerWindow();
+
+ return LPDialogBoxParamW(IDD_JSAPI2_AUTHORIZATION2, hParent, SecurityPrompt_DialogProc, (LPARAM)&param);
+}
+
+static BOOL SecurityPrompt_GetCenterRect(HWND hCenter, RECT *centerRect, BOOL fUseMonitor)
+{
+ if (NULL == centerRect)
+ return FALSE;
+
+ HWND hDesktop = GetDesktopWindow();
+ HWND hTest = hCenter;
+ while(NULL != hTest)
+ {
+ DWORD windowStyle = GetWindowLongPtrW(hTest, GWL_STYLE);
+ if (WS_VISIBLE != ((WS_VISIBLE | WS_MINIMIZE) & windowStyle))
+ {
+ hTest = NULL;
+ hCenter = NULL;
+ }
+ else
+ {
+ hTest = GetParent(hTest);
+ }
+ }
+
+ if (FALSE != fUseMonitor || NULL == hCenter || !GetWindowRect(hCenter, centerRect))
+ {
+ MONITORINFO mi;
+ mi.cbSize = sizeof(MONITORINFO);
+ if (NULL == hCenter)
+ {
+ hCenter = SecurityPrompt_GetPlayerWindow();
+ if (NULL != hCenter)
+ {
+ DWORD windowStyle = GetWindowLongPtrW(hCenter, GWL_STYLE);
+ if (WS_VISIBLE != ((WS_VISIBLE | WS_MINIMIZE) & windowStyle))
+ hCenter = NULL;
+ }
+ }
+
+ HMONITOR hMonitor = MonitorFromWindow(hCenter,
+ (NULL != hCenter) ? MONITOR_DEFAULTTONEAREST : MONITOR_DEFAULTTOPRIMARY);
+
+
+ if (NULL != hMonitor && GetMonitorInfo(hMonitor, &mi))
+ {
+ CopyRect(centerRect, &mi.rcWork);
+ }
+ else
+ {
+ if (NULL == hDesktop || !GetWindowRect(hDesktop, centerRect))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void SecurityPrompt_CenterDialog(HWND hwnd, HWND hCenter)
+{
+ if (NULL == hwnd)
+ return;
+
+ RECT centerRect, windowRect;
+ if (!GetWindowRect(hwnd, &windowRect) ||
+ !SecurityPrompt_GetCenterRect(hCenter, &centerRect, FALSE))
+ {
+ return;
+ }
+
+ windowRect.left = centerRect.left + ((centerRect.right - centerRect.left) - (windowRect.right - windowRect.left))/2;
+ windowRect.top = centerRect.top + ((centerRect.bottom - centerRect.top) - (windowRect.bottom - windowRect.top))/2;
+
+ SetWindowPos(hwnd, NULL, windowRect.left, windowRect.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+}
+
+static void SecurityPrompt_CalculateMinMax(HWND hwnd, HWND hCenter)
+{
+ SECDLG *psd = GetDialog(hwnd);
+ if (NULL == hwnd || NULL == psd) return;
+
+ RECT centerRect, windowRect;
+ if (GetWindowRect(hwnd, &windowRect))
+ {
+ psd->minSize.cx = windowRect.right - windowRect.left;
+ psd->minSize.cy = windowRect.bottom - windowRect.top;
+ }
+ if (SecurityPrompt_GetCenterRect(hCenter, &centerRect, TRUE))
+ {
+ InflateRect(&centerRect, -16, -16);
+ psd->maxSize.cx = centerRect.right - centerRect.left;
+ psd->maxSize.cy = centerRect.bottom - centerRect.top;
+
+ if (psd->maxSize.cx > 360)
+ psd->maxSize.cx = 360;
+ }
+}
+
+static void SecurityPrompt_LoadIcon(HWND hwnd, HINSTANCE hInstance, LPCWSTR pszIcon)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_MESSAGEICON);
+ if (NULL == hControl) return;
+
+ SendMessageW(hControl, WM_SETREDRAW, FALSE, 0L);
+
+ HICON hIcon = (HICON)LoadImageW(hInstance, pszIcon, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_SHARED | LR_DEFAULTSIZE);
+
+ HICON hPrevious = (HICON)SendMessageW(hControl, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
+ if (NULL != hPrevious)
+ DeleteObject(hPrevious);
+
+ if (NULL != hIcon)
+ {
+ hPrevious = (HICON)SendMessageW(hControl, STM_GETIMAGE, IMAGE_ICON, 0L);
+ if (hPrevious != hIcon)
+ DeleteObject(hIcon);
+ }
+
+ SendMessageW(hControl, WM_SETREDRAW, TRUE, 0L);
+
+ if (0 != ShowWindow(hControl, (NULL != hIcon) ? SW_SHOWNA : SW_HIDE))
+ InvalidateRect(hControl, NULL, TRUE);
+
+}
+static BOOL SecurityPrompt_GetWindowTextSize(HWND hwnd, SIZE *pSize, BOOL fMultiline, LONG lineWidth)
+{
+ if (NULL == pSize) return FALSE;
+
+ INT cchLen = GetWindowTextLengthW(hwnd);
+ if (0 == cchLen)
+ {
+ ZeroMemory(pSize, sizeof(SIZE));
+ return TRUE;
+ }
+ cchLen++;
+ LPWSTR pszText = NULL;
+ WCHAR szBuffer[1024] = {0};
+ if (cchLen > ARRAYSIZE(szBuffer))
+ {
+ pszText = (LPWSTR)calloc(cchLen, sizeof(WCHAR));
+ if (NULL == pszText) return FALSE;
+ }
+ else
+ {
+ pszText = szBuffer;
+ cchLen = ARRAYSIZE(szBuffer);
+ }
+
+ BOOL resultOk = FALSE;
+ cchLen = GetWindowTextW(hwnd, pszText, cchLen);
+ if (0 != cchLen)
+ {
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL != hdc)
+ {
+ HFONT hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
+ HFONT originalFont = (HFONT)SelectObject(hdc, hf);
+
+ if (FALSE == fMultiline)
+ {
+ resultOk = GetTextExtentPoint32W(hdc, pszText, cchLen, pSize);
+ }
+ else
+ {
+ RECT textRect;
+ SetRect(&textRect, 0, 0, lineWidth, 0);
+ INT h = DrawTextW(hdc, pszText, cchLen, &textRect, DT_CALCRECT | DT_NOPREFIX | DT_NOCLIP | DT_WORDBREAK);
+ resultOk = (0 != h);
+ if (resultOk)
+ {
+ pSize->cx = textRect.right - textRect.left;
+ pSize->cy = textRect.bottom - textRect.top;
+ }
+
+ }
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+ }
+ }
+
+
+ if (pszText != szBuffer)
+ free(pszText);
+
+ return resultOk;
+}
+
+static LONG SecurityPrompt_CalculateFooterHeight(HWND hwnd, LONG marginCY)
+{
+ RECT rect;
+ HWND hControl;
+
+
+ LONG height = 0;
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_ALLOW)) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+ height += (rect.bottom - rect.top);
+ }
+
+
+ if (0 == height &&
+ NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_DENY)) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+ height += (rect.bottom - rect.top);
+ }
+
+ INT szCtrl[] = {IDC_APPLYTOALL, IDC_SEPARATOR, IDC_HELPTEXT, };
+ for (INT i = 0; i < ARRAYSIZE(szCtrl); i++)
+ {
+ if (NULL != (hControl = GetDlgItem(hwnd, szCtrl[i])) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+ LONG h = (rect.bottom - rect.top);
+ if (h > 0)
+ {
+ if (height > 0) height += marginCY;
+ height += h;
+ }
+ }
+ }
+
+ if (0 != height)
+ height += 2*marginCY;
+
+ return height;
+}
+
+static void SecurityPrompt_UpdateLayout(HWND hwnd, BOOL fRedraw)
+{
+ SECDLG *psd = GetDialog(hwnd);
+ if (NULL == hwnd || NULL == psd) return;
+
+ HWND hControl;
+ RECT rect;
+ LONG marginCX, marginCY;
+ SIZE clientSize, iconSize, titleSize, messageSize;
+ ZeroMemory(&clientSize, sizeof(SIZE));
+
+ SetRect(&rect, 6, 6, 6, 6);
+ if (MapDialogRect(hwnd, &rect))
+ {
+ marginCX = rect.left;
+ marginCY = rect.top;
+ }
+ else
+ {
+ marginCX = 12;
+ marginCY = 12;
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGEICON)) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2);
+ iconSize.cx = rect.right - rect.left;
+ iconSize.cy = rect.bottom - rect.top;
+ }
+ else
+ {
+ ZeroMemory(&iconSize, sizeof(SIZE));
+ }
+
+ if (NULL == (hControl = GetDlgItem(hwnd, IDC_TITLE)) ||
+ 0 == (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) ||
+ FALSE == SecurityPrompt_GetWindowTextSize(hControl, &titleSize, FALSE, 0))
+ {
+ ZeroMemory(&titleSize, sizeof(SIZE));
+ }
+
+ if (NULL == (hControl = GetDlgItem(hwnd, IDC_MESSAGE)) ||
+ 0 == (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) ||
+ FALSE == SecurityPrompt_GetWindowTextSize(hControl, &messageSize, TRUE, psd->maxSize.cx - (iconSize.cx + marginCX * 3)))
+ {
+ ZeroMemory(&messageSize, sizeof(SIZE));
+ }
+
+ clientSize.cx = iconSize.cx;
+ if (messageSize.cx > 0)
+ {
+ clientSize.cx += messageSize.cx;
+ if (iconSize.cx > 0) clientSize.cx += marginCX;
+ }
+ if (titleSize.cx > clientSize.cx)
+ titleSize.cx = clientSize.cx;
+ clientSize.cx += 2*marginCX;
+
+ clientSize.cy = titleSize.cy;
+
+ LONG h1 = messageSize.cy;
+ if (h1 > 0) h1 += 2 * marginCY;
+
+ LONG h2 = iconSize.cy;
+ if (h2 > 0) h2 += marginCY;
+
+ clientSize.cy += (h1 > h2) ? h1 : h2;
+ if (clientSize.cy > 0)
+ {
+ if (clientSize.cy != titleSize.cy && 0 != titleSize.cy)
+ clientSize.cy += marginCY;
+ }
+ clientSize.cy += SecurityPrompt_CalculateFooterHeight(hwnd, marginCY);
+
+
+ DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ DWORD windowExStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
+
+ SetRect(&rect, 0, 0, clientSize.cx, clientSize.cy);
+ if (AdjustWindowRectEx(&rect, windowStyle, FALSE, windowExStyle))
+ {
+ clientSize.cx = rect.right - rect.left;
+ clientSize.cy = rect.bottom - rect.top;
+ }
+ if (clientSize.cx < psd->minSize.cx) clientSize.cx = psd->minSize.cx;
+ if (clientSize.cy < psd->minSize.cy) clientSize.cy = psd->minSize.cy;
+
+
+ SetWindowPos(hwnd, NULL, 0, 0, clientSize.cx, clientSize.cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
+
+ RECT clientRect;
+ if (!GetClientRect(hwnd, &clientRect))
+ SetRectEmpty(&clientRect);
+ else
+ InflateRect(&clientRect, -marginCX, -marginCY);
+
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_TITLE)))
+ {
+ SetWindowPos(hControl, NULL, clientRect.left, clientRect.top, clientRect.right - clientRect.left, titleSize.cy, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGEICON)))
+ {
+ LONG y = clientRect.top;
+ if (titleSize.cy > 0) y += (titleSize.cy + marginCY);
+ SetWindowPos(hControl, NULL, clientRect.left, y, iconSize.cx, iconSize.cy, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGE)))
+ {
+ LONG x = clientRect.left;
+ if (iconSize.cx > 0) x += (iconSize.cx + marginCX);
+ LONG y = clientRect.top;
+ if (titleSize.cy > 0) y += (titleSize.cy + marginCY);
+ SetWindowPos(hControl, NULL, x, y, clientRect.right - x, messageSize.cy, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+
+ HWND hHelp;
+ hHelp = GetDlgItem(hwnd, IDC_HELPTEXT);
+ if (NULL == hHelp || !GetWindowRect(hHelp, &rect))
+ SetRectEmpty(&rect);
+ else
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2);
+
+ SIZE linkSize;
+ LONG bottomLine = clientRect.bottom;
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_HELPLINK)) &&
+ CommandLink_GetIdealSize(hControl, &linkSize))
+ {
+ RECT margins;
+
+ if (!CommandLink_GetMargins(hControl, &margins))
+ SetRectEmpty(&margins);
+
+ if (linkSize.cy > 0)
+ {
+ bottomLine -= (linkSize.cy - margins.bottom);
+ }
+
+ SetWindowPos(hControl, NULL, clientRect.left - margins.left, bottomLine, linkSize.cx, linkSize.cy, SWP_NOACTIVATE | SWP_NOZORDER);
+ if (NULL != hHelp)
+ {
+ LONG x = clientRect.left + linkSize.cx - margins.right;
+ LONG cy = rect.bottom - rect.top;
+ SetWindowPos(hHelp, NULL, x, clientRect.bottom - cy, clientRect.right - x, cy, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_SEPARATOR)) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+ bottomLine -= (marginCY + (rect.bottom - rect.top));
+ SetWindowPos(hControl, NULL, 0, bottomLine, clientRect.right - clientRect.left + 2*marginCX + 2, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_APPLYTOALL)) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+ bottomLine -= (marginCY + (rect.bottom - rect.top));
+ SetWindowPos(hControl, NULL, clientRect.left, bottomLine, clientRect.right - clientRect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ LONG buttonRight = clientRect.right;
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_DENY)) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+
+ SetWindowPos(hControl, NULL, buttonRight - (rect.right - rect.left), bottomLine - (marginCY + (rect.bottom - rect.top)),
+ rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ if (rect.right > rect.left)
+ {
+ buttonRight -= ((rect.right - rect.left) + marginCX);
+ }
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_ALLOW)) &&
+ 0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ GetWindowRect(hControl, &rect))
+ {
+ SetWindowPos(hControl, NULL, buttonRight - (rect.right - rect.left), bottomLine - (marginCY + (rect.bottom - rect.top)),
+ rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+}
+
+static HFONT SecurityPrompt_GetTitleFont(HWND hwnd)
+{
+ SECDLG *psd = GetDialog(hwnd);
+ if (NULL == psd)
+ return (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
+
+ if (NULL != psd->titleFont)
+ return psd->titleFont;
+
+
+ LOGFONTW lf;
+ ZeroMemory(&lf, sizeof(LOGFONTW));
+
+ HFONT hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
+
+ if (NULL != hf)
+ GetObjectW(hf, sizeof(LOGFONTW), &lf);
+
+ if (L'\0' == lf.lfFaceName[0])
+ {
+ if (!SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(LOGFONTW), &lf, 0) ||
+ FAILED(StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"MS Shell Dlg 2")))
+ {
+ lf.lfFaceName[0] = L'\0';
+ }
+ }
+
+ if (L'\0' != lf.lfFaceName[0])
+ {
+ lf.lfWeight = FW_SEMIBOLD;
+ psd->titleFont = CreateFontIndirectW(&lf);
+ }
+
+ return psd->titleFont;
+}
+
+static BOOL SecurityPrompt_ShowHelp(HWND hwnd)
+{
+ INT result = (INT)(INT_PTR)ShellExecuteW(hwnd, L"open",
+ L"https://help.winamp.com/hc/articles/8112753225364-Online-Services-Security",
+ NULL, NULL, SW_SHOWNORMAL);
+ return (result > 32);
+}
+
+static INT_PTR SecurityPrompt_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param)
+{
+ SECDLGCREATEPARAM *createParam = (SECDLGCREATEPARAM*)param;
+ if (NULL == createParam) return 0;
+
+ SECDLG *psd = (SECDLG*)calloc(1, sizeof(SECDLG));
+ if (NULL != psd)
+ {
+ if (!SetPropW(hwnd, SECDLG_PROP, psd))
+ {
+ free(psd);
+ psd = NULL;
+ }
+ }
+
+ HMENU hMenu = GetSystemMenu(hwnd, FALSE);
+ if (NULL != hMenu)
+ {
+ EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND|MF_DISABLED);
+ DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
+ DeleteMenu(hMenu, SC_SIZE, MF_BYCOMMAND);
+ }
+
+
+ SecurityPrompt_LoadIcon(hwnd, NULL, MAKEINTRESOURCEW(OIC_WARNING));
+
+ WCHAR szBuffer[4096] = {0};
+ LPCWSTR pszText;
+ HWND hControl;
+
+ SecurityPrompt_CalculateMinMax(hwnd, createParam->hCenter);
+
+ if (NULL != (pszText = createParam->pszCaption) && IS_INTRESOURCE(pszText))
+ pszText = getStringW((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
+
+ if (NULL != pszText && L'\0' != *pszText)
+ SetWindowTextW(hwnd, pszText);
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_TITLE)))
+ {
+ if (NULL != (pszText = createParam->pszTitle) && IS_INTRESOURCE(pszText))
+ pszText = getStringW((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
+
+ HFONT hf = SecurityPrompt_GetTitleFont(hwnd);
+ if (NULL != hf) SendMessageW(hControl, WM_SETFONT, (WPARAM)hf, 0L);
+
+ SetWindowTextW(hControl, pszText);
+ ShowWindow(hControl, (NULL != pszText && L'\0' != *pszText) ? SW_SHOWNA : SW_HIDE);
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGE)))
+ {
+ if (NULL != (pszText = createParam->pszMessage) && IS_INTRESOURCE(pszText))
+ pszText = getStringW((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
+ SetWindowTextW(hControl, pszText);
+ ShowWindow(hControl, (NULL != pszText && L'\0' != *pszText) ? SW_SHOWNA : SW_HIDE);
+ }
+
+ getStringW(IDS_CLICKHERE, szBuffer, ARRAYSIZE(szBuffer));
+
+ HWND hLink = CreateWindowExW(WS_EX_NOPARENTNOTIFY, NWC_COMMANDLINKW, szBuffer,
+ WS_VISIBLE | WS_CHILD | WS_TABSTOP | /*CLS_HOTTRACK | */CLS_DEFAULTCOLORS | CLS_ALWAYSUNDERLINE,
+ 0, 0, 0, 0, hwnd, (HMENU)IDC_HELPLINK, hMainInstance, NULL);
+
+ if (NULL != hLink)
+ {
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_APPLYTOALL)))
+ SetWindowPos(hLink, hControl, 0, 0, 0, 0, SWP_NOACTIVATE |SWP_NOSIZE | SWP_NOMOVE);
+
+ SendMessageW(hLink, WM_SETFONT, (WPARAM)SendMessageW(hwnd, WM_GETFONT, 0, 0L), 0L);
+ }
+
+ CheckDlgButton(hwnd, IDC_APPLYTOALL,
+ (0 != (JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS_FOR_SERVICE &createParam->flags)) ?
+ BST_CHECKED : BST_UNCHECKED);
+
+ SecurityPrompt_UpdateLayout(hwnd, FALSE);
+
+ SecurityPrompt_CenterDialog(hwnd, createParam->hCenter);
+ SendMessageW(hwnd, DM_REPOSITION, 0, 0L);
+
+ DWORD dialogThread = GetWindowThreadProcessId(hwnd, NULL);
+ DWORD parentThread = GetWindowThreadProcessId(GetParent(hwnd), NULL);
+ if (dialogThread != parentThread)
+ {
+ AttachThreadInput(parentThread, dialogThread, TRUE);
+ SetForegroundWindow(hwnd);
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_DENY)) &&
+ WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
+ PostMessageW(hwnd, WM_NEXTDLGCTL, (WPARAM)hControl, TRUE))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void SecurityPrompt_OnDestroy(HWND hwnd)
+{
+ SECDLG *psd = GetDialog(hwnd);
+ RemovePropW(hwnd, SECDLG_PROP);
+
+ DWORD dialogThread = GetWindowThreadProcessId(hwnd, NULL);
+ DWORD parentThread = GetWindowThreadProcessId(GetParent(hwnd), NULL);
+ if (dialogThread != parentThread)
+ {
+ AttachThreadInput(parentThread, dialogThread, FALSE);
+ }
+
+ if (NULL == psd) return;
+
+ if (NULL != psd->titleFont)
+ DeleteObject(psd->titleFont);
+
+ free(psd);
+}
+
+static void SecurityPrompt_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
+{
+ switch(commandId)
+ {
+ case IDC_BUTTON_ALLOW:
+ case IDC_BUTTON_DENY:
+ if(BN_CLICKED == eventId)
+ {
+ INT_PTR result = (IDC_BUTTON_ALLOW == commandId) ?
+ JSAPI2::svc_apicreator::AUTHORIZATION_ALLOW :
+ JSAPI2::svc_apicreator::AUTHORIZATION_DENY;
+
+ result |= (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_APPLYTOALL)) ?
+ JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS_FOR_SERVICE :
+ JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS;
+
+ EndDialog(hwnd, result);
+ }
+ break;
+ }
+}
+
+static LRESULT SecurityPrompt_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
+{
+ switch(controlId)
+ {
+ case IDC_HELPLINK:
+ if (NM_CLICK == pnmh->code)
+ SecurityPrompt_ShowHelp(hwnd);
+ return TRUE;
+ }
+ return 0;
+}
+static INT_PTR CALLBACK SecurityPrompt_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return SecurityPrompt_OnInitDialog(hwnd, (HWND)wParam, lParam);
+ case WM_DESTROY: SecurityPrompt_OnDestroy(hwnd); break;
+ case WM_COMMAND: SecurityPrompt_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ case WM_NOTIFY: MSGRESULT(hwnd, SecurityPrompt_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam));
+
+ }
+
+
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_SkinAPI.cpp b/Src/Winamp/JSAPI2_SkinAPI.cpp
new file mode 100644
index 00000000..b920d6a7
--- /dev/null
+++ b/Src/Winamp/JSAPI2_SkinAPI.cpp
@@ -0,0 +1,217 @@
+#include "JSAPI2_SkinAPI.h"
+#include "JSAPI2_Security.h"
+#include "main.h"
+#include "JSAPI.h"
+#include "wa_dlg.h"
+#include "api.h"
+#include "../nu/AutoWide.h"
+#include <tataki/color/skinclr.h>
+#include <api/service/waservicefactory.h>
+
+JSAPI2::SkinAPI::SkinAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
+{
+ Tataki::Init(serviceManager); // we might need it, go ahead and init here
+ info = _info;
+ key = _key;
+ refCount = 1;
+}
+
+JSAPI2::SkinAPI::~SkinAPI()
+{
+ Tataki::Quit();
+}
+
+enum
+{
+ DISPID_SKINAPI_GETCLASSICCOLOR,
+ DISPID_SKINAPI_GETPLAYLISTCOLOR,
+ DISPID_SKINAPI_GETSKINCOLOR,
+ DISPID_SKINAPI_NAME,
+ DISPID_SKINAPI_FONT,
+ DISPID_SKINAPI_FONTSIZE,
+
+};
+
+#define DISP_TABLE \
+ CHECK_ID(GetClassicColor, DISPID_SKINAPI_GETCLASSICCOLOR)\
+ CHECK_ID(GetPlaylistColor, DISPID_SKINAPI_GETPLAYLISTCOLOR)\
+ CHECK_ID(GetSkinColor, DISPID_SKINAPI_GETSKINCOLOR)\
+ CHECK_ID(name, DISPID_SKINAPI_NAME)\
+ CHECK_ID(font, DISPID_SKINAPI_FONT)\
+ CHECK_ID(fontsize, DISPID_SKINAPI_FONTSIZE)\
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT JSAPI2::SkinAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::SkinAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::SkinAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::SkinAPI::GetClassicColor(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ COLORREF color = WADlg_getColor(JSAPI_PARAM(pdispparams, 1).lVal);
+ color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
+ wchar_t colorString[8] = {0};
+ StringCchPrintfW(colorString, 8, L"#%06X", color);
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(colorString));
+
+ return S_OK;
+}
+
+HRESULT JSAPI2::SkinAPI::GetPlaylistColor(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ COLORREF color = Skin_PLColors[JSAPI_PARAM(pdispparams, 1).lVal];
+ color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
+ wchar_t colorString[8] = {0};
+ StringCchPrintfW(colorString, 8, L"#%06X", color);
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(colorString));
+
+ return S_OK;
+}
+
+HRESULT JSAPI2::SkinAPI::GetSkinColor(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ ARGB32 color;
+ if (SkinColor::TryGetColor(&color, JSAPI_PARAM(pdispparams, 1).bstrVal))
+ {
+ color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
+ wchar_t colorString[8] = {0};
+ StringCchPrintfW(colorString, 8, L"#%06X", color);
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(colorString));
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+
+ return S_OK;
+}
+
+HRESULT JSAPI2::SkinAPI::name(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = SysAllocString(config_skin);
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::SkinAPI::font(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = SysAllocString(GetFontNameW());
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::SkinAPI::fontsize(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = GetFontSize();
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+
+ return E_FAIL;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::SkinAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::SkinAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::SkinAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::SkinAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
diff --git a/Src/Winamp/JSAPI2_SkinAPI.h b/Src/Winamp/JSAPI2_SkinAPI.h
new file mode 100644
index 00000000..25e53412
--- /dev/null
+++ b/Src/Winamp/JSAPI2_SkinAPI.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <ocidl.h>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class SkinAPI : public IDispatch
+ {
+ public:
+ SkinAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ ~SkinAPI();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ private:
+ const wchar_t *key;
+ JSAPI::ifc_info *info;
+ volatile LONG refCount;
+
+ STDMETHOD (GetClassicColor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (GetPlaylistColor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (GetSkinColor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+
+ STDMETHOD (name)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (font)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (fontsize)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+
+ };
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_TransportAPI.cpp b/Src/Winamp/JSAPI2_TransportAPI.cpp
new file mode 100644
index 00000000..be311ddb
--- /dev/null
+++ b/Src/Winamp/JSAPI2_TransportAPI.cpp
@@ -0,0 +1,532 @@
+#include "JSAPI2_TransportAPI.h"
+#include "JSAPI2_Security.h"
+#include "JSAPI2_CallbackManager.h"
+#include "main.h"
+#include "JSAPI.h"
+#include "JSAPI_CallbackParameters.h"
+
+#define SCRIPT_E_REPORTED 0x80020101
+
+JSAPI2::TransportAPI::TransportAPI(const wchar_t *_key, JSAPI::ifc_info *info)
+{
+ this->info = info;
+ key = _key;
+ refCount = 1;
+}
+
+JSAPI2::TransportAPI::~TransportAPI()
+{
+ // just in case someone forgot
+ JSAPI2::callbackManager.Deregister(this);
+
+ size_t index = events.size();
+ while(index--)
+ {
+ IDispatch *pEvent = events[index];
+ if (NULL != pEvent)
+ pEvent->Release();
+ }
+}
+
+#define DISP_TABLE \
+ CHECK_ID(Prev)\
+ CHECK_ID(Play)\
+ CHECK_ID(Pause)\
+ CHECK_ID(Stop)\
+ CHECK_ID(Next)\
+ CHECK_ID(shuffle)\
+ CHECK_ID(repeat)\
+ CHECK_ID(position)\
+ CHECK_ID(length)\
+ CHECK_ID(url)\
+ CHECK_ID(title)\
+ CHECK_ID(playing)\
+ CHECK_ID(paused)\
+ CHECK_ID(GetMetadata)\
+ CHECK_ID(RegisterForEvents)\
+ CHECK_ID(UnregisterFromEvents)\
+
+
+#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
+enum {
+ DISP_TABLE
+};
+
+#undef CHECK_ID
+#define CHECK_ID(str)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
+ { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
+
+HRESULT JSAPI2::TransportAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ DISP_TABLE
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI2::TransportAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::TransportAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI2::TransportAPI::ButtonPress(WPARAM button, const wchar_t *action, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ switch (security.GetActionAuthorization(L"transport", action, key, info, JSAPI2::api_security::ACTION_PROMPT))
+ {
+ case JSAPI2::api_security::ACTION_DISALLOWED:
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ break;
+ case JSAPI2::api_security::ACTION_ALLOWED:
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ SendMessageW(hMainWindow, WM_COMMAND, button, 0);
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::TransportAPI::Prev(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ return ButtonPress(WINAMP_BUTTON1, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
+}
+
+HRESULT JSAPI2::TransportAPI::Play(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ return ButtonPress(WINAMP_BUTTON2, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
+}
+
+HRESULT JSAPI2::TransportAPI::Pause(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ return ButtonPress(WINAMP_BUTTON3, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
+}
+
+HRESULT JSAPI2::TransportAPI::Stop(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ return ButtonPress(WINAMP_BUTTON4, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
+}
+
+HRESULT JSAPI2::TransportAPI::Next(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ return ButtonPress(WINAMP_BUTTON5, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
+}
+
+HRESULT JSAPI2::TransportAPI::shuffle(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BOOL, puArgErr);
+ switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
+ {
+ case JSAPI2::api_security::ACTION_DISALLOWED:
+ return S_OK;
+ case JSAPI2::api_security::ACTION_ALLOWED:
+ if (!!config_shuffle != JSAPI_PARAM(pdispparams, 1).lVal)
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_FILE_SHUFFLE, 0);
+
+ return S_OK;
+ }
+ }
+ else if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ V_BOOL(pvarResult) = (0 != config_shuffle) ? VARIANT_TRUE : VARIANT_FALSE;//(LONG)SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GET_SHUFFLE);
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+
+ return E_FAIL;
+}
+
+
+HRESULT JSAPI2::TransportAPI::repeat(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BOOL, puArgErr);
+ switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
+ {
+ case JSAPI2::api_security::ACTION_DISALLOWED:
+ return S_OK;
+ case JSAPI2::api_security::ACTION_ALLOWED:
+ if (!!config_repeat != !!JSAPI_PARAM(pdispparams, 1).boolVal)
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_FILE_REPEAT, 0);
+
+ return S_OK;
+ }
+ }
+ else if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ V_BOOL(pvarResult) = (0 != config_repeat) ? VARIANT_TRUE : VARIANT_FALSE;
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+
+ return E_FAIL;
+}
+
+HRESULT JSAPI2::TransportAPI::position(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+ if (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ SendMessageW(hMainWindow, WM_WA_IPC, JSAPI_PARAM(pdispparams, 1).lVal, IPC_JUMPTOTIME);
+ }
+ return S_OK;
+ }
+ else if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = (LONG)SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GETOUTPUTTIME);
+ return S_OK;
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::TransportAPI::length(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = (LONG)SendMessageW(hMainWindow, WM_WA_IPC, 2, IPC_GETOUTPUTTIME);
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::TransportAPI::url(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+ if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(FileName));
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+
+}
+
+HRESULT JSAPI2::TransportAPI::title(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(FileTitle));
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::TransportAPI::playing(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
+ {
+ case JSAPI2::api_security::ACTION_DISALLOWED:
+ V_BOOL(pvarResult) = VARIANT_FALSE;
+ break;
+ case JSAPI2::api_security::ACTION_ALLOWED:
+ V_BOOL(pvarResult) = ::playing?VARIANT_TRUE:VARIANT_FALSE;
+ break;
+ }
+
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::TransportAPI::paused(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
+ {
+ case JSAPI2::api_security::ACTION_DISALLOWED:
+ V_BOOL(pvarResult) = VARIANT_FALSE;
+ break;
+ case JSAPI2::api_security::ACTION_ALLOWED:
+ V_BOOL(pvarResult) = ::paused?VARIANT_TRUE:VARIANT_FALSE;
+ break;
+ }
+
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI2::TransportAPI::GetMetadata(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ wchar_t buffer[4096] = {0};
+ extendedFileInfoStructW info;
+
+ info.filename = FileName;
+ info.metadata = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ info.ret = buffer;
+ info.retlen = sizeof(buffer)/sizeof(*buffer);
+
+ if (NULL != info.filename &&
+ NULL != info.metadata)
+ {
+ if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ info.ret = NULL;
+
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
+ }
+ else
+ JSAPI_EMPTY_RESULT(pvarResult);
+
+ }
+ else
+ {
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+
+ return S_OK;
+}
+
+HRESULT JSAPI2::TransportAPI::RegisterForEvents(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_DISPATCH, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
+
+ switch (security.GetActionAuthorization(L"transport", L"events", key, info, JSAPI2::api_security::ACTION_PROMPT))
+ {
+ case JSAPI2::api_security::ACTION_DISALLOWED:
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
+ break;
+ case JSAPI2::api_security::ACTION_ALLOWED:
+ {
+ /** if this is the first time someone is registering an event
+ ** add ourselves to the callback manager
+ */
+ if (events.empty())
+ JSAPI2::callbackManager.Register(this);
+
+ IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
+ event->AddRef();
+ // TODO: benski> not sure, but we might need to: event->AddRef();
+ events.push_back(event);
+ JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
+ }
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI2::TransportAPI::UnregisterFromEvents(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_DISPATCH, puArgErr);
+
+ IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
+ // TODO: benski> not sure, but we might need to: event->Release();
+
+ size_t index = events.size();
+ while(index--)
+ {
+ if (events[index] == event)
+ {
+ events.erase(events.begin() + index);
+ event->Release();
+ }
+ }
+
+ /** if we don't have any more event listeners
+ ** remove ourselves from the callback manager
+ */
+ if (events.empty())
+ JSAPI2::callbackManager.Deregister(this);
+
+ return S_OK;
+}
+
+#undef CHECK_ID
+#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
+HRESULT JSAPI2::TransportAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ DISP_TABLE
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP JSAPI2::TransportAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI2::TransportAPI::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI2::TransportAPI::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
+
+void JSAPI2::TransportAPI::InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount)
+{
+ size_t index = events.size();
+ if (0 == index)
+ {
+ JSAPI2::callbackManager.Deregister(this);
+ return;
+ }
+
+ JSAPI::CallbackParameters *eventData= new JSAPI::CallbackParameters;
+ if (NULL == eventData) return;
+
+ eventData->AddString(L"event", eventName);
+
+ if (NULL != parameters && 0 != parametersCount)
+ eventData->AddPropertyIndirect(parameters, parametersCount);
+
+ HRESULT hr;
+ while (index--)
+ {
+ IDispatch *pEvent = events[index];
+ if (NULL != pEvent)
+ {
+ hr = JSAPI::InvokeEvent(eventData, pEvent);
+ if (FAILED(hr) && SCRIPT_E_REPORTED != hr)
+ {
+ events.erase(events.begin() + index);
+ pEvent->Release();
+ }
+ }
+ }
+
+ if (events.empty())
+ JSAPI2::callbackManager.Deregister(this);
+
+ eventData->Release();
+}
+
+void JSAPI2::TransportAPI::OnStop(int position, int is_full_stop)
+{
+ if (!is_full_stop)
+ {
+ JSAPI::CallbackParameters::PropertyTemplate parameter =
+ {JSAPI::CallbackParameters::typeLong, L"position", (ULONG_PTR)position};
+
+ InvokeEvent(L"OnStop", &parameter, 1);
+ }
+ else
+ {
+ InvokeEvent(L"OnEndOfFile", NULL, 0);
+ }
+}
+
+void JSAPI2::TransportAPI::OnPlay(const wchar_t *filename)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter =
+ {JSAPI::CallbackParameters::typeString, L"filename", (ULONG_PTR)filename};
+
+ InvokeEvent(L"OnPlay", &parameter, 1);
+}
+
+
+void JSAPI2::TransportAPI::OnPause(bool pause_state)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter =
+ {JSAPI::CallbackParameters::typeBool, L"paused", (ULONG_PTR)pause_state};
+
+ InvokeEvent(L"OnPause", &parameter, 1);
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_TransportAPI.h b/Src/Winamp/JSAPI2_TransportAPI.h
new file mode 100644
index 00000000..fbe3a373
--- /dev/null
+++ b/Src/Winamp/JSAPI2_TransportAPI.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <ocidl.h>
+#include <vector>
+#include "JSAPI_Info.h"
+#include "JSAPI_CallbackParameters.h"
+
+namespace JSAPI2
+{
+ class TransportAPI : public IDispatch
+ {
+ public:
+ TransportAPI(const wchar_t *_key, JSAPI::ifc_info *info);
+ ~TransportAPI();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+ public:
+ /** Callbacks
+ ** JSAPI2::CallbackManager will have been nice enough to marshall onto our thread
+ ** so we don't have to worry about that
+ */
+ void OnStop(int position, int is_full_stop);
+ void OnPlay(const wchar_t *filename);
+ void OnPause(bool pause_state);
+ void InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount);
+ private:
+ const wchar_t *key;
+ volatile LONG refCount;
+ JSAPI::ifc_info *info;
+ typedef std::vector<IDispatch*> EventsList;
+ EventsList events;
+
+ STDMETHOD (ButtonPress)(WPARAM button, const wchar_t *action, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (Prev)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (Play)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (Pause)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (Stop)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (Next)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (shuffle)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (repeat)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (position)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (length)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (url)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (title)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (playing)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (paused)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (GetMetadata)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (RegisterForEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ STDMETHOD (UnregisterFromEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
+ };
+}
diff --git a/Src/Winamp/JSAPI2_api_security.h b/Src/Winamp/JSAPI2_api_security.h
new file mode 100644
index 00000000..0638766a
--- /dev/null
+++ b/Src/Winamp/JSAPI2_api_security.h
@@ -0,0 +1,117 @@
+#pragma once
+#include <bfc/dispatch.h>
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class api_security : public Dispatchable
+ {
+ public:
+ enum
+ {
+ ACTION_UNDEFINED = -1,
+ ACTION_DISALLOWED = 0,
+ ACTION_ALLOWED = 1,
+ ACTION_PROMPT = 2,
+ };
+
+ enum
+ {
+ SUCCESS = 0,
+ FAILURE = 1,
+ };
+
+
+ struct AuthorizationData
+ {
+ GUID data_id;
+ void *data;
+ size_t data_len;
+ };
+
+ // returns one of JSAPI2::api_security::ACTION_DISALLOWED, etc.
+ int GetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization = ACTION_ALLOWED, AuthorizationData *data = 0);
+
+ // returns JSAPI2_SUCCESS, etc.
+ int SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization);
+
+ // associates an HWND with a key.. used for prompting
+ void Associate(const wchar_t *authorization_key, HWND hwnd);
+ HWND GetAssociation(const wchar_t *authorization_key);
+
+ // if you just want a simple security prompt, you can call this in your svc_apicreator::PromptForAuthorization implementation
+ int SecurityPrompt(HWND hwnd, const wchar_t *title_string, const wchar_t *display_string, int flags=0);
+
+ // associates a name (e.g. an online service name) with a key.. used for prompting
+ void AssociateName(const wchar_t *authorization_key, const wchar_t *name);
+ const wchar_t *GetAssociatedName(const wchar_t *authorization_key);
+
+ // clears out all settings for a given key
+ void ResetAuthorization(const wchar_t *authorization_key);
+
+ void SetBypass(const wchar_t *authorization_key, bool enable_bypass);
+
+ enum
+ {
+ JSAPI2_API_SECURITY_GETACTIONAUTHORIZATION = 0,
+ JSAPI2_API_SECURITY_SETACTIONAUTHORIZATION = 1,
+ JSAPI2_API_SECURITY_ASSOCIATE = 2,
+ JSAPI2_API_SECURITY_GETASSOCIATION = 3,
+ JSAPI2_API_SECURITY_SECURITYPROMPT = 4,
+ JSAPI2_API_SECURITY_ASSOCIATENAME = 5,
+ JSAPI2_API_SECURITY_GETASSOCIATEDNAME = 6,
+ JSAPI2_API_SECURITY_RESETAUTHORIZATION = 7,
+ JSAPI2_API_SECURITY_SETBYPASS = 8,
+ };
+
+ };
+
+ inline int api_security::GetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization, AuthorizationData *data)
+ {
+ return _call(JSAPI2_API_SECURITY_GETACTIONAUTHORIZATION, (int)default_authorization, group, action, authorization_key, info, default_authorization, data);
+ }
+
+ inline int api_security::SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization)
+ {
+ return _call(JSAPI2_API_SECURITY_SETACTIONAUTHORIZATION, (int)FAILURE, group, action, authorization_key, authorization);
+ }
+
+ inline void api_security::Associate(const wchar_t *authorization_key, HWND hwnd)
+ {
+ _voidcall(JSAPI2_API_SECURITY_ASSOCIATE, authorization_key, hwnd);
+ }
+
+ inline HWND api_security::GetAssociation(const wchar_t *authorization_key)
+ {
+ return _call(JSAPI2_API_SECURITY_GETASSOCIATION, (HWND)0, authorization_key);
+ }
+
+ inline int api_security::SecurityPrompt(HWND hwnd, const wchar_t *title_string, const wchar_t *display_string, int flags)
+ {
+ return _call(JSAPI2_API_SECURITY_SECURITYPROMPT, (int)0, hwnd, title_string, display_string, flags);
+ }
+
+ inline void api_security::AssociateName(const wchar_t *authorization_key, const wchar_t *name)
+ {
+ _voidcall(JSAPI2_API_SECURITY_ASSOCIATENAME, authorization_key, name);
+ }
+
+ inline const wchar_t *api_security::GetAssociatedName(const wchar_t *authorization_key)
+ {
+ return _call(JSAPI2_API_SECURITY_GETASSOCIATEDNAME, (const wchar_t *)0, authorization_key);
+ }
+
+ inline void api_security::ResetAuthorization(const wchar_t *authorization_key)
+ {
+ _voidcall(JSAPI2_API_SECURITY_RESETAUTHORIZATION, authorization_key);
+ }
+ inline void api_security::SetBypass(const wchar_t *authorization_key, bool enable_bypass)
+ {
+ _voidcall(JSAPI2_API_SECURITY_SETBYPASS, authorization_key, enable_bypass);
+ }
+
+ // {D8BA8766-E489-4cfc-8527-9F3206257FFC}
+ static const GUID api_securityGUID =
+ { 0xd8ba8766, 0xe489, 0x4cfc, { 0x85, 0x27, 0x9f, 0x32, 0x6, 0x25, 0x7f, 0xfc } };
+
+}; \ No newline at end of file
diff --git a/Src/Winamp/JSAPI2_svc_apicreator.h b/Src/Winamp/JSAPI2_svc_apicreator.h
new file mode 100644
index 00000000..f88efe00
--- /dev/null
+++ b/Src/Winamp/JSAPI2_svc_apicreator.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <bfc/dispatch.h>
+#include <bfc/std_mkncc.h>
+#include <ocidl.h>
+#include "jsapi2_api_security.h"
+#include "JSAPI_Info.h"
+
+namespace JSAPI2
+{
+ class svc_apicreator : public Dispatchable
+ {
+ public:
+ enum
+ {
+ AUTHORIZATION_UNDEFINED = 0x0,
+ AUTHORIZATION_ALLOW = 0x1,
+ AUTHORIZATION_DENY = 0x2,
+
+ AUTHORIZATION_MASK = 0xFFF,
+
+ AUTHORIZATION_FLAG_ALWAYS = 0x1000,
+ AUTHORIZATION_FLAG_ALWAYS_FOR_SERVICE = 0x2000,
+ AUTHORIZATION_FLAG_GROUP_ONLY = 0x4000,
+ };
+ public:
+ static FOURCC getServiceType() { return MK4CC('j','s','a','c'); }
+ // this key is guaranteed to out-live your object, so you can just save the pointer
+ // also, DO NOT add a reference to the info object or else you will create a circular reference
+ IDispatch *CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info);
+
+ // returns new AUTHORIZATION_* enum to save to settings, or AUTHORIZATION_UNDEFINED if this isn't our API
+ int PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data);
+ enum
+ {
+ JSAPI2_SVC_APICREATOR_CREATEAPI = 0,
+ JSAPI2_SVC_APICREATOR_PROMPTFORAUTHORIZATION = 1,
+ };
+ };
+
+}
+
+inline IDispatch *JSAPI2::svc_apicreator::CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info)
+{
+ return _call(JSAPI2_SVC_APICREATOR_CREATEAPI , (IDispatch *)0, name, key, info);
+}
+
+inline int JSAPI2::svc_apicreator::PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data)
+{
+ return _call(JSAPI2_SVC_APICREATOR_PROMPTFORAUTHORIZATION, (int)AUTHORIZATION_UNDEFINED, parent, group, action, authorization_key, data);
+}
diff --git a/Src/Winamp/JSAPI_CallbackParameters.cpp b/Src/Winamp/JSAPI_CallbackParameters.cpp
new file mode 100644
index 00000000..281159da
--- /dev/null
+++ b/Src/Winamp/JSAPI_CallbackParameters.cpp
@@ -0,0 +1,384 @@
+#include "JSAPI_CallbackParameters.h"
+#include "JSAPI.h"
+
+JSAPI::CallbackParameters::CallbackParameters()
+{
+ refCount = 1;
+}
+
+JSAPI::CallbackParameters::~CallbackParameters()
+{
+ //for (size_t p=0;p!=params.size();p++)
+ //{
+ // ParameterList::value_type &property = params.at(p);
+ // // some types need to be specifically destroyed or released
+ // switch(property.second.vt)
+ // {
+ // case VT_DISPATCH: // add a reference if it's an IDispatch
+ // property.second.pdispVal->Release();
+ // break;
+ // case VT_BSTR: // re-allocate
+ // SysFreeString(property.second.bstrVal);
+ // break;
+ // }
+ //}
+ for (auto &param : params)
+ {
+ // some types need to be specifically destroyed or released
+ switch(param.second.vt)
+ {
+ case VT_DISPATCH: // add a reference if it's an IDispatch
+ param.second.pdispVal->Release();
+ break;
+ case VT_BSTR: // re-allocate
+ SysFreeString(param.second.bstrVal);
+ break;
+ }
+ }
+}
+
+HRESULT JSAPI::CallbackParameters::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ rgdispid[i] = DISPID_UNKNOWN;
+ const wchar_t *propertyName = rgszNames[i];
+
+ bool found=false;
+ //for (size_t p=0;p!=params.size();p++)
+ size_t p = 0;
+ for(auto it = params.begin(); it != params.end(); it++, p++)
+ {
+ //ParameterList::value_type &property = params.at(p);
+ if (!wcscmp(it->first.c_str(), propertyName))
+ {
+ found=true;
+ rgdispid[i] = (DISPID)p;
+ break;
+ }
+ }
+ if (!found)
+ unknowns=true;
+ }
+
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI::CallbackParameters::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ size_t index = (size_t)dispid;
+ if (index>=params.size())
+ return DISP_E_MEMBERNOTFOUND;
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ if (pvarResult)
+ {
+ //ParameterList::value_type &property = params.at(index);
+ auto it = params.begin();
+ while (index--)
+ {
+ it++;
+ }
+
+ *pvarResult = it->second;
+ // do any type-specific allocations that are necessary
+ switch(pvarResult->vt)
+ {
+ case VT_DISPATCH: // add a reference if it's an IDispatch
+ pvarResult->pdispVal->AddRef();
+ break;
+ case VT_BSTR: // re-allocate
+ pvarResult->bstrVal = SysAllocString(pvarResult->bstrVal);
+ break;
+ }
+ }
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+
+HRESULT JSAPI::CallbackParameters::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::CallbackParameters::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP JSAPI::CallbackParameters::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else if (IsEqualIID(riid, IID_IDispatchEx))
+ *ppvObject = (IDispatchEx *)this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI::CallbackParameters::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI::CallbackParameters::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
+
+HRESULT JSAPI::CallbackParameters::GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+ //for (size_t p=0;p!=params.size();p++)
+ //{
+ // ParameterList::value_type &property = params.at(p);
+ // if (!wcscmp(property.first.c_str(), bstrName))
+ // {
+ // *pid= (DISPID)p;
+ // return S_OK;
+ // }
+ //}
+ size_t p = 0;
+ for (auto it = params.begin(); it != params.end(); it++, p++)
+ {
+ if (!wcscmp(it->first.c_str(), bstrName))
+ {
+ *pid = (DISPID)p;
+ return S_OK;
+ }
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT JSAPI::CallbackParameters::InvokeEx(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+ JSAPI_VERIFY_PARAMCOUNT(pdp, 0);
+ size_t index = (size_t)id;
+ if (index>=params.size())
+ return DISP_E_MEMBERNOTFOUND;
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ if (pvarRes)
+ {
+ //ParameterList::value_type &property = params.at(index);
+ auto it = params.begin();
+ while (index--)
+ {
+ it++;
+ }
+
+ *pvarRes = it->second;
+ // do any type-specific allocations that are necessary
+ switch(pvarRes->vt)
+ {
+ case VT_DISPATCH: // add a reference if it's an IDispatch
+ pvarRes->pdispVal->AddRef();
+ break;
+ case VT_BSTR: // re-allocate
+ pvarRes->bstrVal = SysAllocString(pvarRes->bstrVal);
+ break;
+ }
+ }
+ return S_OK;
+ }
+ else
+ return DISP_E_MEMBERNOTFOUND;
+
+}
+
+HRESULT JSAPI::CallbackParameters::DeleteMemberByName(BSTR bstrName, DWORD grfdex)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::CallbackParameters::DeleteMemberByDispID(DISPID id)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::CallbackParameters::GetMemberProperties(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::CallbackParameters::GetMemberName(DISPID id, BSTR *pbstrName)
+{
+ if (id >= 0 && (size_t)id < params.size())
+ {
+ auto it = params.begin();
+ while (id--)
+ {
+ it++;
+ }
+ *pbstrName = SysAllocString(it->first.c_str());
+ return S_OK;
+ }
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::CallbackParameters::GetNextDispID(DWORD grfdex, DISPID id, DISPID *pid)
+{
+ if (grfdex == fdexEnumDefault)
+ {
+ if (id == DISPID_UNKNOWN)
+ {
+ if (params.size() == 0)
+ return S_FALSE;
+ else
+ {
+ *pid = 0;
+ return S_OK;
+ }
+ }
+ else
+ {
+ size_t index = id+1;
+ if (index >= params.size())
+ {
+ return S_FALSE;
+ }
+ else
+ {
+ *pid = (DISPID)index;
+ return S_OK;
+ }
+
+ }
+ }
+
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::CallbackParameters::GetNameSpaceParent(IUnknown **ppunk)
+{
+ return E_NOTIMPL;
+}
+
+void JSAPI::CallbackParameters::AddProperty(const wchar_t *name, const VARIANT &property)
+{
+ params[name]=property;
+}
+
+void JSAPI::CallbackParameters::AddString(const wchar_t *name, const wchar_t *value)
+{
+ VARIANT bstrVar;
+ V_VT(&bstrVar) = VT_BSTR;
+ V_BSTR(&bstrVar) = SysAllocString(value);
+ AddProperty(name, bstrVar);
+}
+
+void JSAPI::CallbackParameters::AddDispatch(const wchar_t *name, IDispatch *disp)
+{
+ VARIANT dispVar;
+ V_VT(&dispVar) = VT_DISPATCH;
+ V_DISPATCH(&dispVar) = disp;
+ disp->AddRef();
+ AddProperty(name, dispVar);
+}
+
+void JSAPI::CallbackParameters::AddLong(const wchar_t *name, LONG value)
+{
+ VARIANT i4Var;
+ V_VT(&i4Var) = VT_I4;
+ V_I4(&i4Var) = value;
+ AddProperty(name, i4Var);
+}
+
+void JSAPI::CallbackParameters::AddBoolean(const wchar_t *name, bool value)
+{
+ VARIANT boolVar;
+ V_VT(&boolVar) = VT_BOOL;
+ V_BOOL(&boolVar) = value?VARIANT_TRUE:VARIANT_FALSE;
+ AddProperty(name, boolVar);
+}
+
+size_t JSAPI::CallbackParameters::AddPropertyIndirect(const JSAPI::CallbackParameters::PropertyTemplate *entries, size_t count)
+{
+ if (NULL == entries) return 0;
+
+ size_t inserted = 0;
+ VARIANT val;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ const PropertyTemplate *ppt = &entries[i];
+ if (NULL == ppt->name)
+ continue;
+
+ switch(ppt->type)
+ {
+ case typeBool:
+ V_VT(&val) = VT_BOOL;
+ V_BOOL(&val) = (FALSE != ((BOOL)ppt->value)) ? VARIANT_TRUE : VARIANT_FALSE;
+ break;
+ case typeString:
+ V_VT(&val) = VT_BSTR;
+ V_BSTR(&val) = SysAllocString((LPCWSTR)ppt->value);
+ break;
+ case typeLong:
+ V_VT(&val) = VT_I4;
+ V_I4(&val) = (ULONG)ppt->value;
+ break;
+ case typeDispatch:
+ V_VT(&val) = VT_DISPATCH;
+ V_DISPATCH(&val) = (IDispatch*)ppt->value;
+ if (NULL != val.pdispVal)
+ val.pdispVal->AddRef();
+ break;
+ default:
+ continue;
+ break;
+ }
+ AddProperty(ppt->name, val);
+ inserted++;
+ }
+
+ return inserted;
+}
+
+/* ---------------------------------------------------------------------------- */
+HRESULT JSAPI::InvokeEvent(JSAPI::CallbackParameters *parameters, IDispatch *invokee)
+{
+ unsigned int ret;
+ DISPPARAMS params;
+ VARIANTARG arguments[1];
+
+ VariantInit(&arguments[0]);
+ V_VT(&arguments[0]) = VT_DISPATCH;
+ V_DISPATCH(&arguments[0]) = parameters;
+ parameters->AddRef();
+
+ params.cArgs = 1;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = NULL;
+ params.rgvarg = arguments;
+
+ HRESULT hr = invokee->Invoke(0, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, 0, 0, &ret);
+
+ VariantClear(&arguments[0]);
+
+ return hr;
+}
+
diff --git a/Src/Winamp/JSAPI_CallbackParameters.h b/Src/Winamp/JSAPI_CallbackParameters.h
new file mode 100644
index 00000000..8886dbc9
--- /dev/null
+++ b/Src/Winamp/JSAPI_CallbackParameters.h
@@ -0,0 +1,87 @@
+#pragma once
+#include <dispex.h>
+#include <map>
+#include <string>
+
+/*
+This is just a generic property map
+wchar_t * -> VARIANT
+
+Since it stores added properties consecutively (no sorting on property name)
+it should be safe to add properties after-the-fact, but it's not recommended
+
+not thread safe, so don't add properties on a different than than whomever is reading them via IDispatch
+*/
+namespace JSAPI
+{
+ class CallbackParameters : public IDispatchEx
+ {
+ public:
+ CallbackParameters();
+ ~CallbackParameters();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ /** Call this to add a new property
+ ** On object destruction, ~CallbackParameters() will call
+ **** Release() on any VT_DISPATCH variants
+ **** SysFreeString() on any VT_BSTR variants
+ **** TODO on any VT_ARRAY variants
+ ** so be sure to prepare your data ahead of time (e.g. call AddRef)
+ ** if you call the helper functions (below) they will do
+ ** SysAllocString, AddRef, etc for you.
+ */
+ void AddProperty(const wchar_t *name, const VARIANT &property);
+
+ /** helper functions if you don't want to build your own VARIANT
+ **/
+ void AddString(const wchar_t *name, const wchar_t *value);
+ void AddDispatch(const wchar_t *name, IDispatch *disp); // note: calls AddRef() on your object;
+ void AddLong(const wchar_t *name, LONG value);
+ void AddBoolean(const wchar_t *name, bool value);
+
+ typedef enum
+ {
+ typeBool = 0,
+ typeString = 1,
+ typeLong = 2,
+ typeDispatch = 3,
+ } PtopertyType;
+
+ typedef struct __PropertyTemplate
+ {
+ unsigned char type;
+ const wchar_t *name;
+ ULONG_PTR value;
+ } PropertyTemplate;
+
+
+
+ size_t AddPropertyIndirect(const PropertyTemplate *entries, size_t count);
+
+ private:
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ // *** IDispatchEx Methods ***
+ STDMETHOD (GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid);
+ STDMETHOD (InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller);
+ STDMETHOD (DeleteMemberByName)(BSTR bstrName, DWORD grfdex) ;
+ STDMETHOD (DeleteMemberByDispID)(DISPID id);
+ STDMETHOD (GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex);
+ STDMETHOD (GetMemberName)(DISPID id, BSTR *pbstrName);
+ STDMETHOD (GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid);
+ STDMETHOD (GetNameSpaceParent)(IUnknown **ppunk);
+ private:
+ typedef std::map<std::wstring, VARIANT> ParameterList;
+ ParameterList params;
+ volatile LONG refCount;
+ };
+
+ // helper function which calls Invoke(0) with 1 parameter (VT_DISPATCH of your CallbackParameters object)
+ HRESULT InvokeEvent(JSAPI::CallbackParameters *parameters, IDispatch *invokee);
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI_DispatchTable.cpp b/Src/Winamp/JSAPI_DispatchTable.cpp
new file mode 100644
index 00000000..b8793b4c
--- /dev/null
+++ b/Src/Winamp/JSAPI_DispatchTable.cpp
@@ -0,0 +1,22 @@
+#include "JSAPI_DispatchTable.h"
+#include <strsafe.h>
+
+JSAPI::Dispatcher::Dispatcher(const wchar_t *_name, DISPID _id, IDispatch *_object)
+:id(_id), object(_object)
+{
+ memset(name, 0, sizeof(name));
+
+ if (NULL != object)
+ object->AddRef();
+
+ StringCchCopyW(name, ARRAYSIZE(name), _name);
+}
+
+JSAPI::Dispatcher::~Dispatcher()
+{
+ if (NULL != object)
+ {
+ object->Release();
+ object = NULL;
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI_DispatchTable.h b/Src/Winamp/JSAPI_DispatchTable.h
new file mode 100644
index 00000000..7e93eb55
--- /dev/null
+++ b/Src/Winamp/JSAPI_DispatchTable.h
@@ -0,0 +1,17 @@
+#pragma once
+#include <vector>
+#include <ocidl.h>
+namespace JSAPI
+{
+ struct Dispatcher
+ {
+ Dispatcher():id(0),object(0){ name[0] = 0; }
+ Dispatcher(const wchar_t *_name, DISPID _id, IDispatch *_object);
+ ~Dispatcher();
+ wchar_t name[128];
+ DISPID id;
+ IDispatch *object;
+ };
+
+ typedef std::vector<JSAPI::Dispatcher*> DispatchTable;
+}; \ No newline at end of file
diff --git a/Src/Winamp/JSAPI_Info.cpp b/Src/Winamp/JSAPI_Info.cpp
new file mode 100644
index 00000000..d463c560
--- /dev/null
+++ b/Src/Winamp/JSAPI_Info.cpp
@@ -0,0 +1,2 @@
+#include "JSAPI_Info.h"
+
diff --git a/Src/Winamp/JSAPI_Info.h b/Src/Winamp/JSAPI_Info.h
new file mode 100644
index 00000000..3858c1d0
--- /dev/null
+++ b/Src/Winamp/JSAPI_Info.h
@@ -0,0 +1,101 @@
+#pragma once
+#include <bfc/dispatch.h>
+
+namespace JSAPI
+{
+ class ifc_info_callback : public Dispatchable
+ {
+ public:
+ /* this is called when an action is denied by the user */
+ void OnSecurity(const wchar_t *group, const wchar_t *action, int authorization);
+ };
+
+ /*
+ JSAPI and JSAPI2's IDispatch object will also have this interface
+ (retrieve via IWasabiDispatchable)
+ It includes information about the API
+ Allows you to associate an HWND with the API (for dialog parenting, etc)
+ And register for callbacks to get notifications about things like security denial
+ */
+
+ // this GUID is an interface GUID, NOT a service GUID
+ // {64DE905A-8C95-4427-AACE-72A42EB2DE73}
+ static const GUID IID_JSAPI_ifc_info =
+ { 0x64de905a, 0x8c95, 0x4427, { 0xaa, 0xce, 0x72, 0xa4, 0x2e, 0xb2, 0xde, 0x73 } };
+
+ class ifc_info : public Dispatchable
+ {
+ public:
+ static GUID GetIID() { return IID_JSAPI_ifc_info; }
+
+ const wchar_t *GetUserAgent();
+
+ /* associates an HWND with this object
+ mainly used for parenting dialog boxes */
+ void SetHWND(HWND hwnd);
+ HWND GetHWND();
+
+ /* registers for callbacks */
+ void RegisterCallback(ifc_info_callback *callback);
+ void UnregisterCallback(ifc_info_callback *callback);
+
+ /* associates a name with this object */
+ void SetName(const wchar_t *name);
+ const wchar_t *GetName();
+
+ /* adds to the API (for this object only for JSAPI2, globally for JSAPI1 because it's a singleton */
+ int AddAPI(const wchar_t *name, IDispatch *dispatch);
+
+ enum
+ {
+ JSAPI_IFC_INFO_GETUSERAGENT = 0,
+ JSAPI_IFC_INFO_SETHWND = 1,
+ JSAPI_IFC_INFO_GETHWND = 2,
+ JSAPI_IFC_INFO_REGISTERCALLBACK = 3,
+ JSAPI_IFC_INFO_UNREGISTERCALLBACK = 4,
+ JSAPI_IFC_INFO_SETNAME = 5,
+ JSAPI_IFC_INFO_GETNAME = 6,
+ JSAPI_IFC_INFO_ADDAPI = 7,
+ };
+ };
+}
+
+inline const wchar_t *JSAPI::ifc_info::GetUserAgent()
+{
+ return _call(JSAPI_IFC_INFO_GETUSERAGENT, (const wchar_t *)0);
+}
+
+inline void JSAPI::ifc_info::SetHWND(HWND hwnd)
+{
+ _voidcall(JSAPI_IFC_INFO_SETHWND, hwnd);
+}
+
+inline HWND JSAPI::ifc_info::GetHWND()
+{
+ return _call(JSAPI_IFC_INFO_GETHWND, (HWND)0);
+}
+
+inline void JSAPI::ifc_info::RegisterCallback(ifc_info_callback *callback)
+{
+ _voidcall(JSAPI_IFC_INFO_REGISTERCALLBACK, callback);
+}
+
+inline void JSAPI::ifc_info::UnregisterCallback(ifc_info_callback *callback)
+{
+ _voidcall(JSAPI_IFC_INFO_UNREGISTERCALLBACK, callback);
+}
+
+inline void JSAPI::ifc_info::SetName(const wchar_t *name)
+{
+ _voidcall(JSAPI_IFC_INFO_SETNAME, name);
+}
+
+inline const wchar_t *JSAPI::ifc_info::GetName()
+{
+ return _call(JSAPI_IFC_INFO_GETNAME, (const wchar_t *)0);
+}
+
+inline int JSAPI::ifc_info::AddAPI(const wchar_t *name, IDispatch *dispatch)
+{
+ return _call(JSAPI_IFC_INFO_ADDAPI, (int)1, name, dispatch);
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI_ObjectArray.cpp b/Src/Winamp/JSAPI_ObjectArray.cpp
new file mode 100644
index 00000000..f422318f
--- /dev/null
+++ b/Src/Winamp/JSAPI_ObjectArray.cpp
@@ -0,0 +1,257 @@
+#include "JSAPI_ObjectArray.h"
+#include "JSAPI.h"
+#include <strsafe.h>
+
+JSAPI::ObjectArray::ObjectArray()
+{
+ refCount = 1;
+}
+
+JSAPI::ObjectArray::~ObjectArray()
+{
+ for ( IDispatch *l_object : objects )
+ l_object->Release();
+}
+
+enum
+{
+ OBJ_ARRAY_DISP_LENGTH,
+ OBJ_ARRAY_NUM_DISP,
+};
+
+HRESULT JSAPI::ObjectArray::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ rgdispid[i] = DISPID_UNKNOWN;
+ if (!wcscmp(rgszNames[i], L"length"))
+ rgdispid[i]=OBJ_ARRAY_DISP_LENGTH;
+ else
+ {
+ if (rgszNames[i][0] >= L'0' && rgszNames[i][0] <= L'9')
+ rgdispid[i]=_wtoi(rgszNames[i]) + OBJ_ARRAY_NUM_DISP;
+ else
+ unknowns=true;
+ }
+
+ }
+
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JSAPI::ObjectArray::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+
+ switch(dispid)
+ {
+ case OBJ_ARRAY_DISP_LENGTH:
+ {
+ JSAPI_INIT_RESULT(pvarResult, VT_I4);
+ JSAPI_SET_RESULT(pvarResult, lVal, (LONG)objects.size());
+ return S_OK;
+ }
+ default:
+ {
+ if (dispid < OBJ_ARRAY_NUM_DISP)
+ return DISP_E_MEMBERNOTFOUND;
+
+ size_t index = (size_t)dispid - OBJ_ARRAY_NUM_DISP;
+ if (index>=objects.size())
+ return DISP_E_MEMBERNOTFOUND;
+
+ objects[index]->AddRef();
+ JSAPI_INIT_RESULT(pvarResult, VT_DISPATCH);
+ JSAPI_SET_RESULT(pvarResult, pdispVal, objects[index]);
+ return S_OK;
+ }
+ }
+}
+
+HRESULT JSAPI::ObjectArray::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::ObjectArray::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP JSAPI::ObjectArray::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else if (IsEqualIID(riid, IID_IDispatchEx))
+ *ppvObject = (IDispatchEx *)this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG JSAPI::ObjectArray::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+
+ULONG JSAPI::ObjectArray::Release(void)
+{
+ LONG lRef = InterlockedDecrement(&refCount);
+ if (lRef == 0) delete this;
+ return lRef;
+}
+
+void JSAPI::ObjectArray::AddObject(IDispatch *obj)
+{
+ obj->AddRef();
+ objects.push_back(obj);
+}
+
+
+HRESULT JSAPI::ObjectArray::GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+ if (!wcscmp(bstrName, L"length"))
+ *pid=OBJ_ARRAY_DISP_LENGTH;
+ else
+ {
+ if (bstrName[0] >= L'0' && bstrName[0] <= L'9')
+ *pid=_wtoi(bstrName) + OBJ_ARRAY_NUM_DISP;
+ else
+ return DISP_E_MEMBERNOTFOUND;
+
+ }
+ return S_OK;
+}
+
+HRESULT JSAPI::ObjectArray::InvokeEx(
+ /* [in] */ DISPID id,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [in] */ DISPPARAMS *pdp,
+ /* [out] */ VARIANT *pvarRes,
+ /* [out] */ EXCEPINFO *pei,
+ /* [unique][in] */ IServiceProvider *pspCaller)
+{
+ JSAPI_VERIFY_PARAMCOUNT(pdp, 0);
+
+ switch(id)
+ {
+ case OBJ_ARRAY_DISP_LENGTH:
+ {
+ JSAPI_INIT_RESULT(pvarRes, VT_I4);
+ JSAPI_SET_RESULT(pvarRes, lVal, (LONG)objects.size());
+ return S_OK;
+ }
+ default:
+ {
+ if (id < OBJ_ARRAY_NUM_DISP)
+ return DISP_E_MEMBERNOTFOUND;
+
+ size_t index = (size_t)id - OBJ_ARRAY_NUM_DISP;
+ if (index>=objects.size())
+ return DISP_E_MEMBERNOTFOUND;
+
+ objects[index]->AddRef();
+ JSAPI_INIT_RESULT(pvarRes, VT_DISPATCH);
+ JSAPI_SET_RESULT(pvarRes, pdispVal, objects[index]);
+ return S_OK;
+ }
+ }
+
+}
+
+HRESULT JSAPI::ObjectArray::DeleteMemberByName(
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::ObjectArray::DeleteMemberByDispID(
+ /* [in] */ DISPID id)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::ObjectArray::GetMemberProperties(
+ /* [in] */ DISPID id,
+ /* [in] */ DWORD grfdexFetch,
+ /* [out] */ DWORD *pgrfdex)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::ObjectArray::GetMemberName(
+ /* [in] */ DISPID id,
+ /* [out] */ BSTR *pbstrName)
+{
+ if (id >= OBJ_ARRAY_NUM_DISP)
+ {
+ wchar_t temp[64] = {0};
+ StringCbPrintfW(temp, sizeof(temp), L"%d", id-OBJ_ARRAY_NUM_DISP);
+ *pbstrName = SysAllocString(temp);
+ return S_OK;
+ }
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::ObjectArray::GetNextDispID(
+ /* [in] */ DWORD grfdex,
+ /* [in] */ DISPID id,
+ /* [out] */ DISPID *pid)
+{
+ if (grfdex == fdexEnumDefault)
+ {
+ if (id == DISPID_UNKNOWN)
+ {
+ if (objects.empty())
+ return S_FALSE;
+ else
+ {
+ *pid = OBJ_ARRAY_NUM_DISP;
+ return S_OK;
+ }
+ }
+ else if (id < OBJ_ARRAY_NUM_DISP)
+ {
+ return S_FALSE;
+ }
+ else
+ {
+ size_t index = (id - OBJ_ARRAY_NUM_DISP) + 1;
+ if (index >= objects.size())
+ {
+ return S_FALSE;
+ }
+ else
+ {
+ *pid = OBJ_ARRAY_NUM_DISP + (LONG)index;
+ return S_OK;
+ }
+
+ }
+ }
+
+ return E_NOTIMPL;
+}
+
+HRESULT JSAPI::ObjectArray::GetNameSpaceParent(
+ /* [out] */ IUnknown **ppunk)
+{
+ return E_NOTIMPL;
+} \ No newline at end of file
diff --git a/Src/Winamp/JSAPI_ObjectArray.h b/Src/Winamp/JSAPI_ObjectArray.h
new file mode 100644
index 00000000..362005ef
--- /dev/null
+++ b/Src/Winamp/JSAPI_ObjectArray.h
@@ -0,0 +1,43 @@
+#pragma once
+#include <ocidl.h>
+#include <dispex.h>
+#include <vector>
+
+/* simulates an Array in javascript */
+namespace JSAPI
+{
+ class ObjectArray : /*public IDispatch,*/
+ public IDispatchEx
+ {
+ public:
+ ObjectArray();
+ ~ObjectArray();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ void AddObject(IDispatch *obj);
+ private:
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ // *** IDispatchEx Methods ***
+ STDMETHOD (GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid);
+ STDMETHOD (InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller);
+ STDMETHOD (DeleteMemberByName)(BSTR bstrName, DWORD grfdex) ;
+ STDMETHOD (DeleteMemberByDispID)(DISPID id);
+ STDMETHOD (GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex);
+ STDMETHOD (GetMemberName)(DISPID id, BSTR *pbstrName);
+ STDMETHOD (GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid);
+ STDMETHOD (GetNameSpaceParent)(IUnknown **ppunk);
+ private:
+ typedef std::vector<IDispatch*> Objects;
+ Objects objects;
+ volatile LONG refCount;
+
+ };
+
+} \ No newline at end of file
diff --git a/Src/Winamp/Jump.cpp b/Src/Winamp/Jump.cpp
new file mode 100644
index 00000000..a02a8e64
--- /dev/null
+++ b/Src/Winamp/Jump.cpp
@@ -0,0 +1,315 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+
+static LRESULT WINAPI jumpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+static LRESULT WINAPI jumpFileDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+
+HWND jump_hwnd, jump_hwnd2;
+
+int jump_dialog(HWND hwnd)
+{
+ if (IsWindow(jump_hwnd)) { SetForegroundWindow(jump_hwnd); return -1; }
+ LPCreateDialogW(IDD_JUMPDLG,DIALOG_PARENT(hwnd), jumpDlgProc);
+ return 0;
+}
+
+int jump_file_dialog(HWND hwnd)
+{
+ if (IsWindow(jump_hwnd2)) { SetForegroundWindow(jump_hwnd2); return -1; }
+ LPCreateDialogW(IDD_JUMPFILEDLG,DIALOG_PARENT(hwnd),jumpFileDlgProc);
+ return 0;
+}
+
+static LRESULT WINAPI jumpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ ShowWindow(jump_hwnd=hwndDlg,SW_SHOW);
+ {
+ char text[128] = {0};
+ int len=0;
+ if (in_mod) len=in_mod->GetLength()/1000;
+ StringCchPrintfA(text,128,"%d:%02d",len/60,len%60);
+
+ if (in_mod) len = in_mod->GetOutputTime()/1000;
+ else len=0;
+ SetDlgItemTextA(hwndDlg,IDC_TRACKLEN,text);
+ StringCchPrintfA(text,128,"%d:%02d",len/60,len%60);
+ SetDlgItemTextA(hwndDlg,IDC_MINUTES,text);
+
+ // show jump to time window and restore last position as applicable
+ POINT pt = {time_rect.left, time_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, time_rect.left, time_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ char text[129] = {0};
+ int m=0,s=0,bt=0;
+ char *p=text;
+ GetDlgItemTextA(hwndDlg,IDC_MINUTES,text,sizeof(text));
+ while (p && *p == ' ') p++;
+ while (p && *p >= '0' && *p <= '9') {bt=1;s=s*10+*p++-'0';}
+ if (p && *p++ == ':')
+ {
+ m=s;s=0;
+ while (p && *p >= '0' && *p <= '9') {bt=1;s=s*10+*p++-'0';}
+ }
+ if (bt)
+ {
+ int time=m*60000+s*1000;
+ if (time >= 0 && !PlayList_ishidden(PlayList_getPosition()))
+ {
+ if (in_seek(time) < 0)
+ SendMessageW(hMainWindow,WM_WA_MPEG_EOF,0,0);
+ else
+ {
+ ui_drawtime(in_getouttime()/1000,0);
+ }
+ }
+ Sleep(100);
+ while (1)
+ {
+ MSG msg = {0};
+ if (!PeekMessage(&msg,hMainWindow,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
+ break;
+ }
+ }
+ }
+ case IDCANCEL:
+ GetWindowRect(hwndDlg, &time_rect);
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ }
+ return FALSE;
+ case WM_DESTROY:
+ jump_hwnd=0;
+ return 0;
+ }
+ return 0;
+}
+
+static void parselist(char *out, const char *in)
+{
+ int inquotes=0, neednull=0;
+ while (in && *in)
+ {
+ char c=*in++;
+ if (c >= 'A' && c <= 'Z') c+='a'-'A';
+
+ if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
+ {
+ neednull=1;
+ *out++=c;
+ }
+ else if (c == '\"')
+ {
+ inquotes=!inquotes;
+ if (!inquotes)
+ {
+ *out++=0;
+ neednull=0;
+ }
+ }
+ else
+ {
+ if (inquotes) *out++=c;
+ else if (neednull)
+ {
+ *out++=0;
+ neednull=0;
+ }
+ }
+ }
+ *out++=0;
+ *out++=0;
+}
+
+extern "C"
+{
+ static int __cdecl substr_search(const char *bigtext, const char *littletext)
+ {
+ char littletext_list[128] = {0}, *plist = 0;
+ char bigtext_list[MAX_PATH*8] = {0};
+
+ parselist(littletext_list, littletext);
+
+ StringCchCopyA(bigtext_list, MAX_PATH*8, bigtext);
+ plist = bigtext_list;
+ while (plist && *plist)
+ {
+ if (*plist >= 'A' && *plist <= 'Z') *plist += 'a'-'A';
+ plist++;
+ }
+
+ plist = littletext_list;
+ while (plist && *plist)
+ {
+ if (!strstr(bigtext_list, plist)) return 0;
+ plist += lstrlenA(plist) + 1;
+ }
+ return 1;
+ }
+
+ static int (__cdecl *jtf_comparator)(const char *, const char *) = substr_search;
+ static int (__cdecl *jtf_comparatorW)(const wchar_t *, const wchar_t *) = 0;
+}
+
+void SetJumpComparator(void *functionPtr)
+{
+ if (functionPtr)
+ jtf_comparator = (int (__cdecl *)(const char *, const char *))(functionPtr);
+ else
+ jtf_comparator = substr_search;
+}
+
+void SetJumpComparatorW(void *functionPtr)
+{
+ if (functionPtr)
+ jtf_comparatorW = (int (__cdecl *)(const wchar_t *, const wchar_t *))(functionPtr);
+ else
+ jtf_comparatorW = 0;
+}
+
+static WNDPROC oldWndProc;
+
+static LRESULT WINAPI newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ if ((uMsg == WM_KEYDOWN || uMsg == WM_KEYUP) &&
+ (wParam == VK_UP || wParam == VK_DOWN || wParam == VK_PRIOR || wParam == VK_NEXT))
+ {
+ SendMessageW(GetDlgItem(GetParent(hwndDlg),IDC_SELBOX),uMsg,wParam,lParam);
+ return 0;
+ }
+ return CallWindowProc(oldWndProc,hwndDlg,uMsg,wParam,lParam);
+}
+
+static LRESULT WINAPI jumpFileDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ ShowWindow(jump_hwnd2=hwndDlg,SW_SHOW);
+ {
+ int x = 0;
+ HWND hw = GetDlgItem(hwndDlg,IDC_SELBOX);
+
+ // prevents showing the full playlist contents on loading as needed
+ if (!config_jtf_check)
+ {
+ int t = PlayList_getPosition();
+ int v = PlayList_getlength();
+ SendMessageW(hw,WM_SETREDRAW,FALSE,0);
+ for (x = 0; x < v; x ++)
+ {
+ wchar_t ft[FILETITLE_SIZE] = {0};
+ PlayList_getitem2W(x, 0, ft);
+ SendMessageW(hw,LB_SETITEMDATA,SendMessageW(hw,LB_ADDSTRING,0,(LPARAM) ft),x);
+ }
+ for (x = 0; x < v; x ++)
+ {
+ if (SendMessageW(hw,LB_GETITEMDATA,x,0)==t)
+ break;
+ }
+ SendMessageW(hw,WM_SETREDRAW,TRUE,0);
+ }
+ SendMessageW(hw, LB_SETCURSEL, x, 0);
+ oldWndProc = (WNDPROC) SetWindowLongPtrW(GetDlgItem(hwndDlg, IDC_EDIT1), GWLP_WNDPROC, (LONG_PTR)newWndProc);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ LRESULT x=SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0),0);
+
+ if (x >= 0 && x != PlayList_getPosition())
+ {
+ PlayList_setposition(x);
+ PlayList_getcurrent(FileName,FileTitle,FileTitleNum);
+ StartPlaying();
+ }
+
+ Sleep(100);
+ while (1)
+ {
+ MSG msg = {0};
+ if (!PeekMessage(&msg,hMainWindow,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
+ break;
+ }
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ case IDC_SELBOX:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ {
+ SendMessageW(hwndDlg,WM_COMMAND,IDOK,0);
+ }
+ return FALSE;
+ case IDC_EDIT1:
+ if (HIWORD(wParam) == EN_CHANGE)
+ {
+ wchar_t s[64] = {0};
+ if(jtf_comparatorW) GetDlgItemTextW(hwndDlg,IDC_EDIT1,s,64);
+ else GetDlgItemTextA(hwndDlg,IDC_EDIT1,(char*)s,64);
+ int v = PlayList_getlength();
+ HWND hw = GetDlgItem(hwndDlg,IDC_SELBOX);
+ SendMessageW(hw,WM_SETREDRAW,FALSE,0);
+ SendMessageW(hw,LB_RESETCONTENT,0,0);
+
+ // prevents showing the full playlist contents on searching as needed
+ if (!config_jtf_check || s[0] && config_jtf_check)
+ {
+ int x = 0;
+ for (; x < v; x++)
+ {
+ int addtolist = 1;
+ if (jtf_comparatorW)
+ {
+ wchar_t buf[FILENAME_SIZE+FILETITLE_SIZE+1] = {0};
+ PlayList_getitem_jtfW(x, buf);
+ addtolist = jtf_comparatorW(buf, s);
+ }
+ else
+ {
+ char buf[FILENAME_SIZE+FILETITLE_SIZE+1] = {0}, b2[FILETITLE_SIZE] = {0};
+ PlayList_getitem2(x,buf,b2);
+ StringCchCatA(buf,FILENAME_SIZE+FILETITLE_SIZE+1," ");
+ StringCchCatA(buf,FILENAME_SIZE+FILETITLE_SIZE+1,b2);
+ addtolist = jtf_comparator(buf,(char*)s);
+ }
+
+ if (!s[0] || addtolist)
+ {
+ wchar_t b2[FILETITLE_SIZE] = {0};
+ PlayList_getitem2W(x, 0, b2);
+ SendMessageW(hw,LB_SETITEMDATA,SendMessageW(hw,LB_ADDSTRING,0,(LPARAM) b2),x);
+ }
+ }
+ SendMessageW(hw,LB_SETCURSEL,0,x);
+ }
+ SendMessageW(hw,WM_SETREDRAW,TRUE,0);
+ }
+ return FALSE;
+ }
+ return FALSE;
+ case WM_DESTROY:
+ jump_hwnd2=0;
+ return 0;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/LazyServiceFactory.cpp b/Src/Winamp/LazyServiceFactory.cpp
new file mode 100644
index 00000000..277cbaa3
--- /dev/null
+++ b/Src/Winamp/LazyServiceFactory.cpp
@@ -0,0 +1,128 @@
+#include "LazyServiceFactory.h"
+#include "w5s.h"
+#include "api.h"
+#include <strsafe.h>
+/*
+various implementation notes:
+1) register for service notifications after registering service, so we can know if our service got loaded indirectly
+*/
+
+LazyServiceFactory::LazyServiceFactory(FOURCC _service_type, GUID _service_guid, char *_service_name, char *_service_test_string, const wchar_t *_service_filename)
+{
+ service_type=_service_type;
+ service_guid=_service_guid;
+ service_name=_service_name;
+ service_test_string = _service_test_string;
+ StringCbCopyW(service_filename, sizeof(service_filename), _service_filename);
+}
+
+LazyServiceFactory::~LazyServiceFactory()
+{
+ WASABI_API_SVC->service_deregister(this);
+ free(service_name);
+ free(service_test_string);
+}
+
+FOURCC LazyServiceFactory::GetServiceType()
+{
+ return service_type;
+}
+
+const char *LazyServiceFactory::GetServiceName()
+{
+ return service_name;
+}
+
+GUID LazyServiceFactory::GetGUID()
+{
+ return service_guid;
+}
+
+void *LazyServiceFactory::GetInterface(int global_lock)
+{
+ //load target W5S
+ w5s_load(service_filename);
+ // ask the service manager remove our service factory and put the new one in our old place (to keep enumeration valid)
+ WASABI_API_SVC->service_compactDuplicates(this);
+
+ // call the service manager to get the "real" service which should now (hopefully) be loaded
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(service_guid);
+ if (sf && sf != this)
+ return sf->getInterface();
+ return 0;
+}
+
+int LazyServiceFactory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int LazyServiceFactory::ReleaseInterface(void *ifc)
+{
+ // someone may have held on to our service factory when they loaded the service
+ // so they call us instead of the real service factory
+ // so go grab the 'real' service and release through that
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(service_guid);
+ if (sf && sf != this) // make sure we didn't just grab ourselves :)
+ {
+ return sf->releaseInterface(ifc);
+ }
+ return 0;
+}
+
+const char *LazyServiceFactory::GetTestString()
+{
+ return service_test_string;
+}
+
+int LazyServiceFactory::ServiceNotify(int msg, intptr_t param1, intptr_t param2)
+{
+ switch (msg)
+ {
+ case SvcNotify::ONDEREGISTERED:
+ WASABI_API_SYSCB->syscb_deregisterCallback(this);
+ break;
+ case SvcNotify::ONREGISTERED:
+ WASABI_API_SYSCB->syscb_registerCallback(this);
+ break;
+ }
+ return 1;
+}
+
+int LazyServiceFactory::Notify(int msg, intptr_t param1, intptr_t param2)
+{
+ switch (msg)
+ {
+ case SvcCallback::ONREGISTER:
+ {
+ waServiceFactory *sf = reinterpret_cast<waServiceFactory*>(param2);
+ GUID serviceGUID = sf->getGuid();
+ if (sf != this && serviceGUID != INVALID_GUID && serviceGUID == service_guid)
+ {
+ // real service got loaded, so unregister ourselves
+ WASABI_API_SVC->service_compactDuplicates(this);
+ }
+ }
+ break;
+ default: return 0;
+ }
+ return 1;
+}
+
+#define CBCLASS LazyServiceFactory
+START_MULTIPATCH;
+START_PATCH(ServiceFactoryPatch)
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_GETSERVICETYPE, GetServiceType);
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_GETSERVICENAME, GetServiceName);
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_GETGUID, GetGUID);
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_GETINTERFACE, GetInterface);
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface) ;
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface);
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_GETTESTSTRING, GetTestString);
+M_CB(ServiceFactoryPatch, waServiceFactory, WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify);
+NEXT_PATCH(SysCallbackPatch)
+M_CB(SysCallbackPatch, SysCallback, SYSCALLBACK_GETEVENTTYPE, GetEventType);
+M_CB(SysCallbackPatch, SysCallback, SYSCALLBACK_NOTIFY, Notify);
+END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/LazyServiceFactory.h b/Src/Winamp/LazyServiceFactory.h
new file mode 100644
index 00000000..6894b6b2
--- /dev/null
+++ b/Src/Winamp/LazyServiceFactory.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <api/service/waservicefactory.h>
+#include <bfc/multipatch.h>
+#include <api/syscb/callbacks/svccb.h>
+enum {ServiceFactoryPatch, SysCallbackPatch };
+class LazyServiceFactory : public MultiPatch<ServiceFactoryPatch, waServiceFactory>, public MultiPatch<SysCallbackPatch, SysCallback>
+{
+public:
+ LazyServiceFactory(FOURCC _service_type, GUID _service_guid, char *_service_name, char *_service_test_string, const wchar_t *_service_filename);
+ ~LazyServiceFactory();
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+ void *GetInterface(int global_lock);
+ int SupportNonLockingInterface();
+ int ReleaseInterface(void *ifc);
+ const char *GetTestString();
+ int ServiceNotify(int msg, intptr_t param1, intptr_t param2);
+ FOURCC GetEventType() { return SysCallback::SERVICE; }
+ int Notify(int msg, intptr_t param1, intptr_t param2);
+protected:
+ RECVS_MULTIPATCH;
+
+ FOURCC service_type;
+ char *service_name;
+ GUID service_guid;
+ wchar_t service_filename[MAX_PATH];
+ char *service_test_string;
+}; \ No newline at end of file
diff --git a/Src/Winamp/M3u.cpp b/Src/Winamp/M3u.cpp
new file mode 100644
index 00000000..0eab2567
--- /dev/null
+++ b/Src/Winamp/M3u.cpp
@@ -0,0 +1,73 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "strutil.h"
+#include "api.h"
+#include "WinampPlaylist.h"
+#include "../nu/AUtoWide.h"
+#include "../nu/AUtoChar.h"
+
+#include "../WAT/WAT.h"
+
+int savem3ufn(const wchar_t *filename, int rel, int useBase)
+{
+ UINT conv=CP_ACP;
+ if (!lstrcmpiW(PathFindExtensionW(filename), L".m3u8"))
+ conv=CP_UTF8;
+ FILE *fp = 0;
+ int ext = 1;
+ int pos = PlayList_getPosition();
+ fp = _wfopen(filename, L"wt");
+ if (!fp) return -1;
+ if (conv==CP_UTF8)
+ fputs("\xEF\xBB\xBF", fp); // write UTF-8 BOM
+ if (ext) fprintf(fp, "#EXTM3U\n");
+ PlayList_setposition(0);
+ if (PlayList_getlength()) for (;;)
+ {
+ if ( !PlayList_gethidden(PlayList_getPosition())
+ && !PlayList_hasanycurtain(PlayList_getPosition())
+ )
+ {
+ wchar_t fnbuf[FILENAME_SIZE] = {0};
+ wchar_t ftbuf[FILETITLE_SIZE] = {0};
+ PlayList_getitem2W(PlayList_getPosition(), fnbuf, ftbuf);
+ int len = PlayList_getcurrentlength();
+ if (rel)
+ {
+ PlayList_makerelative(filename, fnbuf, useBase);
+ if (fnbuf[0]=='#') // woops, can't start a line with #
+ PlayList_getitem2W(PlayList_getPosition(), fnbuf, 0); // retrieve file name again
+ }
+
+
+ if ( ext && PlayList_getcached( PlayList_getPosition() ) )
+ {
+ const char *l_ext_inf = PlayList_getExtInf( PlayList_getPosition() );
+
+ wa::strings::wa_string l_filename( fnbuf );
+
+ if ( ext && l_ext_inf && *l_ext_inf && l_filename.contains( "://" ) )
+ {
+ fprintf( fp, "#EXTINF:%d%s,%s\n%s\n", len, l_ext_inf, (char *)AutoChar( ftbuf, conv ), (char *)AutoChar( fnbuf, conv ) );
+
+ delete( l_ext_inf );
+ }
+ else
+ fprintf( fp, "#EXTINF:%d,%s\n%s\n", len, (char *)AutoChar( ftbuf, conv ), (char *)AutoChar( fnbuf, conv ) );
+ }
+ else
+ fprintf(fp, "%s\n", (char *)AutoChar(fnbuf, conv));
+ }
+ if (PlayList_advance(1) < 0)
+ break;
+ }
+ fclose(fp);
+ PlayList_setposition(pos);
+ return 0;
+}
diff --git a/Src/Winamp/Main.h b/Src/Winamp/Main.h
new file mode 100644
index 00000000..8af94615
--- /dev/null
+++ b/Src/Winamp/Main.h
@@ -0,0 +1,1179 @@
+#ifndef _MAIN_H_
+#define _MAIN_H_
+#ifdef __cplusplus
+
+//#pragma warning(error:4311)
+extern "C"
+{
+#endif
+#include <windows.h>
+//#include <windowsx.h>
+#include "wasabicfg.h"
+#include "wa_ipc.h"
+#include "config.h"
+#include "dpi.h"
+#ifndef __cplusplus
+#include "Plush/plush.h"
+#endif
+
+#define APSTUDIO_INVOKED
+#include "resource.h"
+
+#include <mbstring.h>
+#include <shlwapi.h>
+#include <stdio.h>
+#include <strsafe.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <shobjidl.h>
+#include <shellapi.h>
+#include "in2.h"
+#include "strutil.h"
+#include "../nu/trace.h"
+#ifndef NO_INPLACE_RESOLVE
+
+#if defined(_WIN64)
+ #include "../Elevator/IFileTypeRegistrar_64.h"
+#else
+ #include "../Elevator/IFileTypeRegistrar_32.h"
+#endif
+
+#endif
+ /* configuration */
+
+ //#undef MAX_PATH
+ //#define MAX_PATH 512
+#define OFFSCREEN_Y_POS -30000
+#define MAX_URL 4096
+extern HINSTANCE language_pack_instance;
+#define UPDATE_DISPLAY_TIMER 38
+#define STATS_TIMER 64
+
+#define SPLASH_DELAY 2000
+#define APP_NAME "Winamp"
+#ifdef __alpha
+#define APP_VERSION_PLATFORM "(AXP)"
+#elif defined(_WIN64)
+#define APP_VERSION_PLATFORM "(x64)"
+#elif defined(_WIN32_WINCE)
+#define APP_VERSION_PLATFORM "(CE)"
+#else
+#define APP_VERSION_PLATFORM "(x86)"
+#endif
+ extern const char app_name[], app_version[], app_version_string[];
+#define BIGINT 1000000000
+
+#define MAINMENU_OPTIONS_BASE (11+g_mm_optionsbase_adj)
+#define WINDOWMENU_FFWINDOWS_BASE (3+g_mm_ffwindowsbase_adj)
+
+#define HIDDEN_TRAP -33
+
+#define WINDOW_WIDTH 275
+#define WINDOW_HEIGHT 116
+
+
+#define FALLBACK_FONT L"Arial"
+//#define DEFAULT_FONT "Arial Unicode MS"
+ #define DEFAULT_FONT L"Arial"
+ //extern prefsDlgRec *g_piprefsdlgs;
+
+#define CAPTION_SIZE (MAX_PATH+128)
+
+#define AUDITSIZE 10
+
+//#define CLASSIC_SKIN_NAME L"Winamp Classic"
+#define MODERN_SKIN_NAME L"Winamp Modern"
+#define BENTO_SKIN_NAME L"Bento"
+#define BIG_BENTO_SKIN_NAME L"Big Bento"
+
+ /***********************
+ *** about.c
+ */
+ void about_dialog(void);
+
+
+ extern int about_lastpage;
+ extern HWND about_hwnd;
+
+
+ /***********************
+ *** about2.c
+ */
+ void About2_Start(HWND hwndParent);
+ void About2_Kill();
+
+ /***********************
+ *** bookmark.c
+ */
+ void Bookmark_additem(wchar_t *fn, wchar_t *ft);
+ void Bookmark_AddCommandline(wchar_t *commandLine);
+
+ /***********************
+ *** burn.cpp
+ */
+ int burn_start(burnCDStruct *param);
+ unsigned int burn_doBurn(char *cmdline, HWND winampWnd, HINSTANCE winampInstance);
+
+ /***********************
+ *** config.c
+ */
+ // configuration variables/with defaults
+ #ifndef NO_INPLACE_RESOLVE
+ int GetRegistrar(IFileTypeRegistrar **registrar, BOOL use_fallback);
+ #endif
+ void init_config();
+ void setup_config(void);
+ void config_write(int);
+ void config_read(int);
+ BOOL config_setup_filetypes(int mode);
+ void config_adddesktop(void);
+ int config_isregistered(wchar_t *);
+ BOOL config_registermediaplayer(DWORD accessEnabled);
+ BOOL config_register_capability(wchar_t *ext, int mode);
+ void config_register(wchar_t *ext, int reg);
+ void config_setinifile(wchar_t *inifile);
+ void config_setinidir(const wchar_t *inidir);
+ void config_setm3udir(const wchar_t *m3udir);
+ void config_setm3ubase(const wchar_t *m3ubase);
+ void config_load_langpack_var(void);
+ void config_save_langpack_var(void);
+ int config_isdircontext(void);
+ BOOL config_setup_filetype(const wchar_t *winamp_file, const wchar_t *name, BOOL use_fallback);
+ BOOL config_adddircontext(BOOL use_fallback);
+ int config_iscdplayer(void);
+ BOOL config_removedircontext(BOOL use_fallback);
+ BOOL config_regcdplayer(int reg, int mode);
+ void config_remove_winamp_keys(void);
+ void config_agent_add(void);
+ void config_agent_remove(void);
+ void regmimetype(const wchar_t *mtype, const wchar_t *programname, const wchar_t *ext, int nsonly);
+ void RemoveRegistrar();
+
+ /***********************
+ *** convert.cpp
+ */
+ int convert_file(convertFileStruct *cfs);
+ void convert_end(convertFileStruct *cfs);
+ int convert_fileW(convertFileStructW *cfs);
+ void convert_endW(convertFileStructW *cfs);
+ HWND convert_config(convertConfigStruct *ccs);
+ void convert_config_end(convertConfigStruct *ccs);
+ void convert_enumfmts(converterEnumFmtStruct *cefs);
+ void convert_setPriority(convertSetPriority *csp);
+ void convert_setPriorityW(convertSetPriorityW *csp);
+ int convert_setConfigItem(convertConfigItem *cci);
+ int convert_getConfigItem(convertConfigItem *cci);
+ int convert_file_test(convertFileStructW *cfs);
+
+ /***********************
+ *** dde.c
+ */
+ int dde_addstart(HWND hwnd);
+ void dde_delstart(void);
+ int dde_isquicklaunchavailable(void);
+ void dde_addquicklaunch(HWND hwnd);
+ void dde_adddesktop(HWND hwnd);
+ void dde_remdesktop(void);
+ void dde_remquicklaunch(void);
+
+ /***********************
+ *** dock.c
+ */
+ void FixMainWindowRect(RECT *r);
+ void EstMainWindowRect(RECT *r);
+ void EstEQWindowRect(RECT *r);
+ void EstPLWindowRect(RECT *r);
+ void EstVidWindowRect(RECT *r);
+ void SetVidWindowRect(RECT *r);
+ void SetMainWindowRect(RECT *r);
+ void SetEQWindowRect(RECT *r);
+ void SetPLWindowRect(RECT *r);
+ void MoveRect(RECT *r, int x, int y);
+ int IsWindowAttached(RECT rc, RECT rc2);
+ void SnapWindowToWindow(RECT *rcSrc, RECT rcDest);
+ void AdjustSnap(RECT old1, RECT old2, RECT *new1, RECT *new2);
+ int IsPointInRect(int x, int y, RECT *r);
+ void FixOverlaps(RECT *r1, RECT *r2);
+
+
+ /***********************
+ *** draw.c
+ */
+ extern int (WINAPI *jtf_drawtext)(HDC, LPCWSTR, int, LPRECT, UINT);
+ void draw_set_plbm(HBITMAP);
+ extern int pe_fontheight;
+ extern HPALETTE draw_hpal;
+ void draw_firstinit(void);
+ void draw_finalquit(void);
+ void draw_init(void);
+ void draw_paint(HWND hwnd);
+ void draw_printclient(HDC hdc, LPARAM drawingOptions);
+ void draw_kill(void);
+ void draw_clear(void);
+ void draw_monostereo(int value); // 0 is neither, 1 is mono, 2 is stereo
+ void draw_shuffle(int on, int pressed);
+ void draw_repeat(int on, int pressed);
+ void draw_eqplbut(int eqon, int eqpressed, int plon, int plpressed);
+ void draw_volumebar(int volume, int pressed); // volume is 0-51
+ void draw_panbar(int volume, int pressed);
+ void draw_songname(const wchar_t *name, int *position, int songlen);
+ void draw_positionbar(int position, int pressed); // position is 0-256
+ void draw_bitmixrate(int bitrate, int mixrate);
+ void draw_buttonbar(int buttonpressed); // starts at 0 with leftmost, -1 = no button
+ void draw_playicon(int whichicon); // 0 = none, 1 = play, 2 = stop, 4 = pause
+ void draw_time(int minutes, int seconds, int clear);
+ void draw_sa(unsigned char *values, int draw); // array of 12 bands, starting with leftmost, of 0..7
+ void draw_tbuttons(int b1, int b2, int b3, int b4);
+ void draw_setnoupdate(int);
+ void draw_tbar(int active, int windowshade, int egg);
+ void draw_eject(int pressed);
+ void draw_clutterbar(int enable);
+ void update_volume_text(int songlen);
+ void update_panning_text(int songlen);
+
+ /*****************
+ *** draw_eq.c
+ */
+ extern int eq_init;
+ void draw_eq_init();
+ void draw_eq_kill();
+ void draw_paint_eq(HWND hwnd);
+ void draw_printclient_eq(HDC hdc, LPARAM /*drawingOptions*/);
+ void draw_eq_tbutton(int b3, int wsb);
+ void draw_eq_slid(int which, int pos, int pressed); // left to right, 0-64
+ void draw_eq_tbar(int active);
+ void draw_eq_onauto(int on, int autoon, int onpressed, int autopressed);
+ void draw_eq_presets(int pressed);
+ void draw_eq_graphthingy(void);
+
+ /*****************
+ *** draw_pe.c
+ *** for functions that accept HDC as the first parameter,
+ *** hdc can be NULL, and it will use the Window DC
+ */
+ extern int pe_init;
+ void draw_pe_init();
+ void draw_pe_kill();
+ void draw_pe_tbutton(int b2, int b3, int b2_ws);
+ void draw_paint_pe(HWND hwnd);
+ void draw_printclient_pe(HWND hwnd, HDC hdc, LPARAM drawingOptions);
+ void draw_reinit_plfont(int notifyOthers);
+ void draw_pe_tbar(HWND hwnd, HDC hdc, int state);
+ void draw_pe_vslide(HWND hwnd, HDC hdc, int pushed, int pos); // pos 0..100
+ void draw_pe_timedisp(HDC hdc, int minutes, int seconds, int tlm, int clear);
+
+ void draw_pe_addbut(int which); // -1 = none, 0 = file, 1 = dir, 2 = loc
+ void draw_pe_rembut(int which); // -1 = none, 0 = sel, 1 = crop, 2 = all
+ void draw_pe_selbut(int which); // -1 = none, 0 = all, 1 = none, 2=inv
+ void draw_pe_miscbut(int which); // -1 = none, 0 = inf, 1 = sort, 2=misc
+ void draw_pe_iobut(int which); // -1 = none, 0 = load, 1=save, 2=clear
+
+ /*****************
+ *** draw_vw.c
+ */
+ extern int vw_init;
+ void draw_vw_init();
+ void draw_vw_kill();
+ void draw_vw_tbar(int state);
+ void draw_vw(HDC hdcout);
+ void draw_paint_vw(HWND hwnd);
+ void draw_vw_tbutton(int b3);
+ void draw_vw_mbuts(int whichb);
+ void draw_vw_info(wchar_t *t, int erase);
+
+ /*****************
+ *** dsp.c
+ */
+ void dsp_init(void);
+ void dsp_quit(void);
+ int dsp_dosamples(short int *samples, int numsamples, int bps, int nch, int srate);
+ int dsp_isactive(void);
+
+ /*****************
+ *** eq.c
+ */
+ extern unsigned char eq_tab[10];
+ void eq_dialog(HWND, int);
+ void eq_autoload(const char *mp3fn);
+ LRESULT CALLBACK EQ_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+
+ /*****************
+ *** embedwnd.cpp
+ */
+ #ifdef __cplusplus
+ typedef struct _EMBEDWND
+ {
+ HWND hLastFocus;
+ } EMBEDWND;
+ #include "../nu/CGlobalAtom.h"
+ static CGlobalAtom EMBEDWND_PROPW(L"EMBDEWND");
+ #define GetEmbedWnd(__hwnd) ((EMBEDWND*)GetPropW(__hwnd, EMBEDWND_PROPW))
+ #endif
+
+ extern LRESULT CALLBACK emb_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ extern HWND embedWindow(embedWindowState *state);
+ extern void SnapWindowToAllWindows(RECT *outrc, HWND hwndNoSnap);
+ extern BOOL SnapToScreen(RECT *outrc);
+
+ extern CRITICAL_SECTION embedcs;
+ extern embedWindowState *embedwndlist; // linked list
+ extern int embedwndlist_cnt;
+#define EMBED_STATE_EXTRA_LINK 0
+#define EMBED_STATE_EXTRA_ATTACHED 1
+#define EMBED_STATE_EXTRA_GUID 4 // note this reserved 5-7 also
+#define EMBED_STATE_EXTRA_REPARENTING 62
+#define EMBED_STATE_EXTRA_FFROOTWND 63
+
+ /*****************
+ *** equi.c
+ */
+ extern int minimize_hack_winamp;
+ extern int do_volbar_active, do_panbar_active;
+
+ void eq_ui_handlecursor(void);
+ void equi_handlemouseevent(int x, int y, int type, int stats);
+ void ui_handlecursor(void);
+
+ BOOL DoTrackPopup(HMENU hMenu, UINT fuFlags, int x, int y, HWND hwnd);
+
+ /*****************
+ *** gen.cpp
+ */
+
+ void load_genplugins();
+ void unload_genplugins();
+
+ /*****************
+ *** html.c
+ */
+ void doHtmlPlaylist(void);
+
+ /*****************
+ *** http.c
+ */
+ int httpRetrieveFile(HWND hwnd, const char *url, char *file, char *dlgtitle);
+ int httpRetrieveFileW(HWND hwnd, const char *url, const wchar_t *file, const wchar_t *dlgtitle);
+
+ /*****************
+ *** in.c
+ */
+
+ extern In_Module *in_mod;
+ int in_init();
+ void in_deinit();
+ In_Module *in_setmod(wchar_t *filename);
+ In_Module *in_setmod_noplay(const wchar_t *filename, int *start_offs); // starts at *start_offs, sets *start_offs with the value of the module used
+ char *in_getfltstr(void);
+ wchar_t *in_getfltstrW(BOOL skip);
+ char *in_getextlist(void);
+ wchar_t *in_getextlistW();
+ int in_getouttime(void);
+ int in_getlength(void);
+ void in_pause(int p);
+ int in_seek(int time_in_ms);
+ int in_open(const wchar_t *fn);
+ void in_setvol(int v);
+ void in_setpan(int p);
+ void in_close(void);
+ int in_infobox(HWND hwnd, const wchar_t *fn);
+ int in_get_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *dest, size_t destlen);
+ int in_get_extended_fileinfo(const char *fn, const char *metadata, char *dest, size_t destlen);
+ int in_set_extended_fileinfo(const char *fn, const char *metadata, char *dest);
+ int in_set_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *data);
+ int in_write_extended_fileinfo();
+ void eq_set(int on, char data[10], int preamp);
+ void in_flush(int ms);
+
+ /**************
+ *** jump.c
+ */
+ void SetJumpComparator(void *functionPtr);
+ void SetJumpComparatorW(void *functionPtr);
+ int jump_dialog(HWND hwnd);
+ int jump_file_dialog(HWND hwnd);
+
+
+
+ /***************
+ *** m3u.c
+ */
+ int savem3ufn(const wchar_t *filename, int rel, int useBase);
+
+ /* main.c */
+
+#include "buildType.h"
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x20A
+#endif
+ extern UINT songChangeBroadcastMessage;
+ extern HMENU main_menu, top_menu, systray_menu, g_submenus_bookmarks1,
+ g_submenus_bookmarks2, g_submenus_skins1, g_submenus_skins2,
+ g_submenus_vis, g_submenus_options, g_submenus_lang,
+ g_submenus_play, v5_top_menu;
+ extern int unique_loword_command;
+ extern int g_submenus_lang_id;
+ extern char g_audiocdletter[];
+ extern int g_audiocdletters;
+ extern int g_dropaot_timer_set;
+ extern int is_install;
+ extern int g_fsapp;
+ extern int g_restoreaot_timer_set;
+ extern int bNoHwndOther;
+ extern int g_safeMode;
+ void tealike_crappy_code(unsigned long v[2], unsigned long k[4]);
+ void UpdateAudioCDMenus(HMENU hmenu);
+ void MoveOffscreen(HWND hwnd);
+ void ResolveEnvironmentVariables(wchar_t *string, size_t stringSize);
+ extern int g_main_created;
+ extern int g_noreg;
+ extern wchar_t szAppName[64]; // window class name, generated on the fly.
+ extern int g_fullstop;
+ extern int vis_fullscreen;
+ extern int stat_isit; // used for faster version checking
+ extern int g_mm_ffoptionsbase_adj;
+ extern int no_notify_play;
+ extern int last_no_notify_play;
+ extern int disable_skin_cursors;
+ extern int disable_skin_borders;
+ extern int g_exit_disabled;
+ extern UINT g_scrollMsg;
+ LRESULT CALLBACK Main_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+ extern int Ipc_WindowToggle(INT_PTR which, INT_PTR how);
+ extern int eggstat;
+ extern int last_brate, g_need_titleupd, g_need_infoupd;
+ extern int g_stopaftercur;
+ extern int g_has_deleted_current;
+
+ extern int g_has_video_plugin, g_no_video_loaded;
+ extern char *audits[AUDITSIZE];
+ extern int audit_ptr;
+
+ extern HWND hTooltipWindow, hEQTooltipWindow, hVideoTooltipWindow, hPLTooltipWindow/*, hPL2TooltipWindow*/;
+ extern HWND hMainWindow, hEQWindow, hPLWindow, /*hMBWindow, */hVideoWindow;
+ extern HINSTANCE hMainInstance;
+ extern HANDLE hMainThread;
+ extern DWORD mainThreadId;
+ extern int paused;
+ extern int playing;
+ extern wchar_t caption[CAPTION_SIZE];
+ extern wchar_t FileName[FILENAME_SIZE];
+ extern wchar_t FileTitle[FILETITLE_SIZE];
+ extern wchar_t FileTitleNum[FILETITLE_SIZE];
+ extern char *app_date;
+ extern int g_srate, g_brate, g_nch, g_srate_exact;
+
+ extern int g_mm_optionsbase_adj;
+ extern int g_mm_ffwindowsbase_adj;
+ extern HWND g_dialog_box_parent;
+ extern int g_restartonquit;
+ extern char playlist_custom_font[128];
+ extern wchar_t playlist_custom_fontW[128];
+ extern int config_custom_plfont;
+ extern int disable_skin_cursors;
+ LRESULT sendMlIpc(int msg, WPARAM param);
+ extern HWND hExternalVisWindow;
+ int CALLBACK WINAPI BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
+ int CALLBACK WINAPI BrowseCallbackProc_Download(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
+ BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam);
+ int Main_OnClose(HWND hwnd);
+#define DIALOG_PARENT(w) (g_dialog_box_parent?g_dialog_box_parent:w)
+ int CreateMainWindow();
+ void BuildAppName();
+ WPARAM WinampMessageLoop();
+
+
+ /***************
+ *** metrics.c
+ */
+ #define METRICS_EMAIL 0x0001
+ #define METRICS_COUNTRY 0x0002
+ #define METRICS_ANNOUNCEMENTS 0x0003
+ #define METRICS_GENDER 0x0004
+
+ INT GetMetricsValueW(const char *data, const char *pszType, void *pDest, int cbDest);
+ BOOL SetMetricsValueW(const char *data, const char *pszType, const void *pVal, int cbVal);
+ BOOL SendMetrics(const char *data, HWND hwndParent);
+ INT GetMetricsSize(const char *data);
+
+
+ /***************
+ *** verchk.c
+ */
+ void newversioncheck(void);
+ void Ping(const char *url);
+
+ /***************
+ *** ole.cpp
+ */
+ void InitDragDrops();
+ void UninitDragDrops();
+ void Ole_initDragDrop(void);
+ void Ole_uninitDragDrop(void);
+ void *Ole_getDropTarget(void);
+
+ /***************
+ *** options.c
+ */
+#define PREFS_UNICODE ((_prefsDlgRec *)1)
+#define PREFS_ACP ((_prefsDlgRec *)0)
+ extern int g_taskbar_dirty;
+ extern intptr_t prefs_last_page;
+ extern RECT prefs_rect, alt3_rect, ctrle_rect, about_rect,
+ loc_rect, time_rect, load_rect, editinfo_rect;
+ extern HWND prefs_hwnd;
+ void prefs_dialog(int modal);
+ void prefs_liveDlgAdd(prefsDlgRec * p);
+ void prefs_liveDlgRemove(prefsDlgRec * p);
+ void prefs_liveDlgUpdate(prefsDlgRec * p);
+ void SetDialogBoxFromFile(FILE *fp, HWND hwndDlg, int id);
+ /***************
+ *** options_playlist.cpp
+ */
+ void UpdatePlaylistFontSizeText(void);
+ void UpdateManualAdvanceState(void);
+ /***************
+ *** options_skin.cpp
+ */
+ typedef struct _ENUMSKIN
+ {
+ const wchar_t *pszFileName;
+ const wchar_t *pszName;
+ int nType;
+ int bActive;
+ } ENUMSKIN;
+
+ #define SKIN_FILETYPE_EMBED 3
+ #define SKIN_FILETYPE_DIR 0
+ #define SKIN_FILETYPE_ZIP 1
+ #define SKIN_FILETYPE_WSZ 2
+ #define SKIN_FILETYPE_WAL 4
+
+
+ typedef int (CALLBACK *ENUMSKINPROC)(ENUMSKIN* /*pes*/, void * /*user*/); // return 0 to stop enumeration
+ int EnumerateSkins(ENUMSKINPROC fnEnumSkin, void *user);
+ /***************
+ *** options_general.cpp
+ */
+ typedef struct _ENUMLANG
+ {
+ const wchar_t *pszFileName;
+ const wchar_t *pszName;
+ int nType;
+ int bActive;
+ } ENUMLANG;
+
+ //#define LANG_FILETYPE_LNG 1 // DEPRECATED: no longer a supported type
+ #define LANG_FILETYPE_WLZ 2
+ #define LANG_FILETYPE_EMBED 3
+ #define LANG_FILETYPE_ZIP 4 // added 5.66
+ #define LANG_FILETYPE_DIR 0 // added 5.66
+
+ typedef int (CALLBACK *ENUMLANGPROC)(ENUMLANG* /*pel*/, void * /*user*/); // return 0 to stop enumeration
+ int EnumerateLanguages(ENUMLANGPROC fnEnumLang, void *user);
+ void LangSwitchToLangPrompt(HWND hwndDlg, wchar_t* newLang);
+ /***************
+ *** out.c
+ */
+ extern Out_Module *out_modules[32];
+ extern Out_Module *out_mod;
+ void out_init();
+ void out_deinit();
+ void out_setwnd();
+ void out_changed(HINSTANCE hLib, int enabled);
+
+ /***************
+ *** peui.c
+ */
+ void peui_handlemouseevent(HWND hwnd, int x, int y, int type, int stats);
+ void pe_ui_handlecursor(HWND hwnd);
+
+
+ /****************
+ *** play.c
+ */
+ void getNewFile(int, HWND, const wchar_t *);
+ LRESULT getNewLocation(int, HWND); // if the int param is -1, returns a HGLOBAL to the thing instead of acting on it
+ void StartPlaying();
+ void StopPlaying(int);
+ void PausePlaying();
+ void UnPausePlaying();
+ void PlayThing(const char *thing, int clearlist);
+ void BeginPlayback();
+
+
+ /***************
+ *** playlist.c
+ */
+ __declspec(dllexport) extern wchar_t *(*plstring_wcsdup)(const wchar_t *str);
+ __declspec(dllexport) extern wchar_t *(*plstring_malloc)(size_t str_size);
+ __declspec(dllexport) extern void (*plstring_release)(wchar_t *str);
+ __declspec(dllexport) extern void (*plstring_retain)(wchar_t *str);
+
+ int LoadPlaylistByExtension(const wchar_t *fn, const wchar_t *ext, int whattodo, int useBase);
+ int PlayList_getitem2W(int position, wchar_t *filename, wchar_t *filetitle);
+ int PlayList_getitem_jtfW(int position, wchar_t *str);
+ void PlayList_getcurrent_tupdate(wchar_t *FileName, wchar_t *FileTitle);
+ int IsPlaylistExtension(const wchar_t *extension);
+ int IsPlaylistExtensionA(const char *extension);
+ int LoadPlaylist(const wchar_t *filename, int whattodo, int doMIMEcheck); // returns -1 if not a playlist, 0 on success, 1 on failure
+ void plstring_init();
+
+ extern wchar_t playlistStr[19];
+
+ void PlayList_UpdateTitle(const wchar_t *filename);
+ int PlayList_GetNextSelected(int start);
+ int PlayList_GetSelectedCount();
+ void PlayList_updateitem(int position);
+ void PlayList_getcurrent_onstop(wchar_t *filename, wchar_t *filetitle);
+ int PlayList_gethidden(int pos);
+ int PlayList_ishidden(int pos);
+ int PlayList_alldone(int pos);
+ int PlayList_hasanycurtain(int pos);
+ int PlayList_current_hidden(void);
+ const char *PlayList_getcurtain(int pos);
+ const char *PlayList_getExtInf( int pos );
+ //const char *PlayList_getbrowser(int pos);
+ void PlayList_resetcurrent(void);
+ int PlayList_getitem(int position, wchar_t *filename, wchar_t *filetitle);
+ int PlayList_getitem2(int position, char *filename, char *filetitle);
+ int PlayList_getitem3(int position, char *filetitle, char *filelength);
+ int PlayList_getitem3W(int position, wchar_t *filetitle, wchar_t *filelength);
+ int PlayList_getitem_pl(int position, wchar_t *);
+ int PlayList_getlength(void);
+ int PlayList_deleteitem(int item);
+ void PlayList_delete(void);
+ void PlayList_destroy(void);
+ void PlayList_append(const wchar_t *filename, int is_nde_string);
+ void PlayList_appendthing(const wchar_t *url, int doMIMEcheck, int is_nde_string);
+ void PlayList_append_withinfo(const wchar_t *filename, const wchar_t *title, const wchar_t *ext, int length, int is_nde_string);
+ void PlayList_append_withinfo_curtain(const wchar_t *filename, const wchar_t *title, int length, char *curtain, const wchar_t *ext, int is_nde_string);
+ void PlayList_append_withinfo_hidden(const wchar_t *filename, const wchar_t *title, int length, char *curtain/*, char *browser*/);
+ void PlayList_getcurrent(wchar_t *filename, wchar_t *filetitle, wchar_t *filetitlenum);
+ void PlayList_GetCurrentTitle(wchar_t *filetitle, int cchLen);
+ void PlayList_setcurrent(const wchar_t *filename, wchar_t *filetitle);
+ void PlayList_swap(int e1, int e2);
+ int PlayList_setposition(int pos);
+ int PlayList_advance(int byval);
+ int PlayList_getPosition();
+ int PlayList_getNextPosition();
+ void PlayList_addfromdlg(const wchar_t *fns); // replace with api_playlistmanager
+ void PlayList_refreshtitle(void);
+ wchar_t *PlayList_gettitle(const wchar_t *filename, int useID3);
+ const wchar_t *PlayList_GetCachedTitle(const wchar_t *filename);
+ int PlayList_randpos(int);
+ void PlayList_randomize(void);
+ void PlayList_reverse(void);
+ void PlayList_sort(int, int start_p);
+ void PlayList_adddir(const wchar_t *path, int recurse); // returns 0 if path was invalid // replace with api_playlistmanager
+ void PlayList_updaterandpos(void);
+ void PlayList_makerelative(const wchar_t *listfile, wchar_t *filename, int useBase);
+ int PlayList_getsonglength(int x);
+ int PlayList_gettotallength(void);
+ int PlayList_getcurrentlength(void);
+ int PlayList_getselect(int);
+ int PlayList_getselect2(int x, wchar_t *filename);
+ void PlayList_setselect(int, int);
+ void PlayList_setlastlen(int x);
+ void PlayList_setitem(int x, const wchar_t *filename, wchar_t *filetitle);
+ void PlayList_saveend(int start);
+ void PlayList_restoreend(void);
+ void PlayList_setcached(int x, int cached);
+ int PlayList_getcached(int x);
+ void PlayList_SetLastItem_RepeatCount( int count);
+ int PlayList_getrepeatcount(int pos);
+ void PlayList_terminate_lasthidden(void);
+ void PlayList_SetLastItem_Range(unsigned long starttime, unsigned long endtime);
+ unsigned long PlayList_GetItem_Start(int pos);
+ unsigned long PlayList_GetItem_End(int pos);
+ void PlayList_insert(int position, const wchar_t *filename);
+
+ /**************
+ *** pledit.c
+ */
+ LRESULT CALLBACK PE_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+ void pleditDlg(HWND, int);
+ void plEditRefresh(void);
+ void plEditSelect(int song);
+ extern int pledit_disp_offs;
+ void PE_Cmd(windowCommand *wc);
+
+ /***************
+ *** pls.c
+ */
+ void saveplsfn(const wchar_t *fn);
+ int loadpls(HWND, int);
+ int savepls(HWND hwnd);
+
+ /************************
+ *** sa.c
+ */
+ extern volatile int sa_curmode;
+ void SpectralAnalyzer_Create();
+ void SpectralAnalyzer_Destroy();
+ void sa_setthread(int enabled);
+ void sa_deinit(void);
+ void sa_init(int numframes);
+ int sa_add(char *values, int timestamp, int csa);
+ char *sa_get(int timestamp, int csa, char data[75*2 + 8]);
+
+ /************************
+ *** set.c
+ */
+ void set_caption(int alt_cb, wchar_t *format, ...);
+ void set_aot(int);
+ void set_priority(void);
+ void set_taskbar(void);
+ void set_visopts(void);
+ void do_caption_autoscroll(void);
+ void set_pl_wnd_tooltip(void);
+ void set_vid_wnd_tooltip(void);
+
+ /***********************
+ *** shell.cpp
+ */
+ HRESULT ResolveShortCut(HWND hwnd, LPCWSTR pszShortcutFile, LPWSTR pszPath);
+ //void CreateShortCut(HWND hwnd, LPCSTR pszShortcutFile, LPCSTR pszExe, LPCSTR, int);
+ void Shell_Free(void *p);
+
+ /************************
+ *** skins.c
+ */
+ BOOL _cleanupDirW(const wchar_t *dir);
+ extern int g_skinloadedmanually, g_skinmissinggenff;
+ void CreateDirectoryForFileW(wchar_t *fn, wchar_t *base); // shared for use with wlz files
+ void Skin_Random(void);
+ void Skin_Load(void);
+ void Skin_CleanupZip(void);
+ void Skin_CleanupAfterCrash(void);
+ BOOL Skin_Check_Modern_Support();
+ int Skin_GetRegionPointList(int eq, int **points, int **counts);
+ /* The indices of Skin_PLColors:
+ 0 - text color - playlist
+ 1 - text color - currently playing playlist entry
+ 2 - background color - playlist
+ 3 - background color - selected playlist entry
+ 4 - text color - video window info, minibrowser info
+ 5 - background - video window info, minibrowser info */
+ extern int Skin_PLColors[6], Skin_UseGenNums;
+ extern char Skin_PLFont[128];
+ extern wchar_t Skin_PLFontW[128];
+ extern HWND skin_hwnd;
+#define N_CURSORS 29
+ extern HCURSOR Skin_Cursors[N_CURSORS];
+
+
+ /*************************
+ *** splash.c
+ */
+ void splashDlg(int wait_in_ms);
+
+
+ /*************************
+ *** stats.c
+ */
+ void Stats_OnPlay(const wchar_t *playstring);
+ void stats_write(void); // sets some final stats and writes to disk
+ void stats_getuidstr(char *str);
+ void stats_init();
+ void stats_save(); // just writes to disk
+
+ /***********************
+ *** systray.c
+ */
+ extern int systray_intray;
+ void systray_minimize(wchar_t *tip);
+ void systray_restore(void);
+
+ /* ui.c */
+ extern int ui_songposition;
+ extern int ui_songposition_dir;
+ extern int ui_songposition_tts;
+ extern int do_posbar_active;
+
+ void ui_doscrolling();
+ void ui_handlemouseevent(int x, int y, int type, int stats); // x,y, -1=up,0=move,1=down, stats = kbstats
+ void ui_reset();
+ void ui_drawtime(int time_elapsed, int mode); // mode=0 means called from timer, mode=1 forced
+
+ /***********************
+ *** util.c
+ */
+ LPCWSTR RepairMutlilineString(LPWSTR pszBuffer, INT cchBufferMax);
+ void recent_add(const wchar_t *loc);
+ int IsUrl(const char *url);
+ //int IsCharSpace(char digit);
+ //int IsCharSpaceW(wchar_t digit);
+ int IsCharDigit(char digit);
+ int IsCharDigitW(wchar_t digit);
+ void mbprintf(char *file, int line, char *format, ...);
+ void link_handledraw(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ LRESULT link_handlecursor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void link_startsubclass(HWND hwndDlg, UINT id);
+ void myOpenURL(HWND, const wchar_t *url);
+ void myOpenURLWithFallback(HWND, wchar_t *url, wchar_t *fallbackUrl);
+ char *my_strdup(char *s);
+ int geticonid(int x);
+ int isInetAvailable(void);
+ unsigned int getDay(void);
+ const wchar_t *scanstr_backcW(const wchar_t *str, const wchar_t *toscan, const wchar_t *defval);
+ void getViewport(RECT *r, HWND wnd, int full, RECT *sr);
+ BOOL windowOffScreen(HWND hwnd, POINT pt);
+
+ LPCWSTR BuildFullPath(LPCWSTR pszPathRoot, LPCWSTR pszPath, LPWSTR pszDest, INT cchDest); //
+ INT ComparePath(LPCWSTR pszPath1, LPCWSTR pszPath2, LPCWSTR pszPathRoot); //
+ BOOL DisabledWindow_OnMouseClick(HWND hwnd); // call it in WM_SETCURSOR
+
+ /***************
+ *** functions related to uxtheme.dll
+ */
+
+
+ #define ETDT_DISABLE 0x01
+ #define ETDT_ENABLE 0x02
+ #define ETDT_USETABTEXTURE 0x04
+ #define ETDT_ENABLETAB (ETDT_ENABLE | ETDT_USETABTEXTURE)
+ #define ETDT_USEAEROWIZARDTABTEXTURE 0x08
+ #define ETDT_ENABLEAEROWIZARDTAB (ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE)
+ #define ETDT_VALIDBITS (ETDT_DISABLE | ETDT_ENABLE | ETDT_USETABTEXTURE | ETDT_USEAEROWIZARDTABTEXTURE)
+
+ int IsWinXPTheme(void);
+ void DoWinXPStyle(HWND tab);
+ int IsAero(void);
+ BOOL IsVista(void);
+ BOOL IsVistaOrLower(void);
+ BOOL IsWin8(void);
+
+ HRESULT WAEnableThemeDialogTexture(HWND hwnd, DWORD dwFlags);
+
+ /***************
+ *** lang.cpp
+ */
+ HINSTANCE Lang_InitLangSupport(HINSTANCE, const GUID);
+ void Lang_FollowUserDecimalLocale(void);
+ void Lang_CleanupZip(void);
+ void Lang_CleanupAfterCrash(void);
+ void Lang_EndLangSupport(void);
+ HINSTANCE Lang_FakeWinampLangHInst(HINSTANCE adjustedHInst);
+ void Lang_LocaliseAgentOnTheFly(BOOL refresh);
+
+ int extract_wlz_to_dir(wchar_t* readme_only_wlz_extraction, BOOL *skip);
+ char *getString(UINT uID, char *str, size_t maxlen);
+ wchar_t *getGUIDstr(const GUID, wchar_t *target);
+
+ int LPMessageBox(HWND parent, UINT idMessage, UINT idTitle, UINT type);
+ wchar_t *getStringW(UINT uID, wchar_t *str, size_t maxlen);
+ #define LPCreateDialog(id, parent, proc) \
+ LPCreateDialogParam(id, parent, (DLGPROC)proc, 0)
+ HWND LPCreateDialogParam(int id, HWND parent, DLGPROC proc, LPARAM param);
+ #define LPDialogBox(id, parent, proc) \
+ LPDialogBoxParam(id, parent, (DLGPROC)proc, 0)
+ INT_PTR LPDialogBoxParam(int id, HWND parent, DLGPROC proc, LPARAM param);
+ #define LPDialogBoxW(id, parent, proc) \
+ LPDialogBoxParamW(id, parent, (DLGPROC)proc, 0)
+ INT_PTR LPDialogBoxParamW(int id, HWND parent, DLGPROC proc, LPARAM param);
+ #define LPCreateDialogW(id, parent, proc) \
+ LPCreateDialogParamW(id, parent, (DLGPROC)proc, 0)
+ HWND LPCreateDialogParamW(int id, HWND parent, DLGPROC proc, LPARAM param);
+ HMENU LPLoadMenu(UINT id);
+
+ /***************
+ *** video.cpp
+ */
+ extern int g_video_numaudiotracks;
+ extern int g_video_curaudiotrack;
+ void Browser_Create();
+ void Browser_Destroy();
+ extern wchar_t vidoutbuf_save[1024];
+ extern int is_fullscreen_video;
+ int ShowVideoWindow(int init_state);
+ void HideVideoWindow(int autoStop);
+ LRESULT CALLBACK video_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+ int video_isVideoPlaying();
+ int videoIsFullscreen();
+ void videoToggleFullscreen();
+ void videoForceFullscreenOff();
+ HWND video_Create();
+
+ /***************
+ *** video_ipc.cpp
+ */
+ int WINAPI VideoIPCProcedure(int which, WPARAM data, LRESULT *returnValue);
+
+ /***
+ ** videoui.c
+ */
+ void videoui_handlemouseevent(int x, int y, int type, int stats);
+
+ /***********************
+ *** vis.c
+ */
+ int vis_running();
+ void vis_start(HWND, wchar_t*);
+ void vis_stop();
+ void vsa_init(int numframes);
+ void vsa_deinit(void);
+ void vis_setinfo(int srate, int nch);
+ int vsa_getmode(int *sp, int *wa);
+ void vis_setprio(void);
+ int vsa_add(void *data, int timestamp);
+ int sa_add(char *values, int timestamp, int csa);
+ void sa_addpcmdata(void *PCMData, int nch, int bps, int timestamp);
+ void vsa_addpcmdata(void *PCMData, int nch, int bps, int timestamp);
+
+ LRESULT CALLBACK VIS_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+ extern HWND hVisWindow, hPLVisWindow;
+
+ void vis_setextwindow(HWND hwnd);
+
+ /***********************
+ *** rand.cpp
+ */
+ int warand();
+ float warandf();
+
+ /*******************
+ *** ipc.cpp
+ */
+ LRESULT Main_OnIPC(HWND hwnd, int which, WPARAM data);
+ LRESULT wa_register_ipc(WPARAM data);
+
+ /*******************
+ *** fullscreen.cpp
+ */
+ void BeginFullscreenAppMonitor();
+ void EndFullscreenAppMonitor();
+ void restoreAOT();
+ void dropAOT();
+
+ /*******************
+ *** main_mouse.cpp
+ */
+ int Main_OnRButtonUp(HWND hwnd, int x, int y, UINT flags);
+ int Main_OnLButtonUp(HWND hwnd, int x, int y, UINT flags);
+ int Main_OnCaptureChanged(HWND hwnd);
+ int Main_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
+ int Main_OnLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
+ int Main_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
+
+ /*******************
+ *** main_nonclient.cpp
+ */
+ UINT Main_OnNCHitTest(HWND hwnd, int x, int y);
+ BOOL Main_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized);
+ UINT Main_OnNCCalcSize(HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS * lpcsp);
+
+ /*******************
+ *** main_display.cpp
+ */
+ int Main_OnGetText(wchar_t *text, int sizeCch);
+ int Main_OnDisplayChange(HWND hwnd);
+ int Main_OnQueryNewPalette(HWND hwnd);
+ int Main_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange);
+
+ /*******************
+ *** main_buttons.cpp
+ */
+ int Main_OnButton1(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
+ int Main_OnButton2(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
+ int Main_OnButton3(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
+ int Main_OnButton4(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
+ int Main_OnButton5(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
+
+ /*******************
+ *** main_close.cpp
+ */
+ void Main_OnEndSession(HWND hwnd, BOOL fEnding);
+ int Main_OnClose(HWND hwnd);
+ int Main_OnDestroy(HWND hwnd);
+
+ /*******************
+ *** main_init.cpp
+ */
+ void RegisterWinamp();
+ BOOL InitApplication(HINSTANCE hInstance);
+ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
+
+ /*******************
+ *** browser.cpp
+ */
+ /*
+ void LaunchBrowser(const char *url);
+ void OpenBrowser();
+ void Browser_toggleVisible(int showing);
+ void CloseBrowser();
+ void Browser_init();
+ void Browser_kill();
+ */
+
+ /*******************
+ *** ExternalCOM.cpp
+ */
+ DISPID __cdecl JSAPI1_GenerateUniqueDispatchId();
+ HRESULT __cdecl JSAPI1_Initialize();
+ HRESULT __cdecl JSAPI1_Uninitialize();
+ HRESULT __cdecl JSAPI1_SkinChanged();
+ HRESULT __cdecl JSAPI1_CurrentTitleChanged();
+
+ /*******************
+ *** SkinUtils.cpp
+ */
+ const char *GetFontName();
+ const wchar_t *GetFontNameW();
+ int GetFontSize();
+
+ /***
+ *** ASXv2.cpp
+ */
+ void loadasxv2fn(const wchar_t *filename, int whattodo);
+ /*******************
+ *** Wasabi.cpp
+ */
+ void Wasabi_Load();
+ void Wasabi_Unload();
+ void Wasabi_FindSystemServices();
+ void Wasabi_ForgetSystemServices();
+
+ /*******************
+ *** W5S.cpp
+ */
+ void w5s_init();
+ void w5s_deinit();
+
+ /*******************
+ *** vu.cpp
+ */
+ void vu_init(int numframes, int srate);
+ void vu_deinit();
+ void VU_Create();
+ void VU_Destroy();
+ int vu_add(char *values, int timestamp);
+ int export_vu_get(int channel);
+ void calcVuData(unsigned char *out, char *data, const int channels, const int bits);
+
+ // PlayQueue.cpp
+ int PlayQueue_OnEOF();
+
+ // paths.cpp
+ BOOL UtilGetSpecialFolderPath(HWND hwnd, TCHAR *path, int folder);
+
+ // cmdline.cpp
+ void GetParameter(const wchar_t *commandLine, wchar_t *yourBuffer, size_t yourBufferSize);
+
+ // unsorted
+ void readwrite_client_uid(int isWrite, wchar_t uid_str[64]);
+ BOOL read_compatmode();
+
+ extern char metric_plugin_list[];
+ char *export_sa_get_deprecated();
+ char *export_sa_get(char data[75*2 + 8]);
+ void export_sa_setreq(int);
+ extern HWND jump_hwnd, jump_hwnd2;
+ wchar_t *remove_urlcodesW(wchar_t *p);
+ int PlayList_get_lastlen();
+ HBITMAP draw_LBitmap(LPCTSTR bmname, const wchar_t *filename);
+ extern void draw_mb_info(char *t, int erase);
+ extern void FormString(char *in, char *out, int maxlen);
+ extern int plmodified, plcleared, plneedsave;
+ extern int g_has_deleted_current;
+ void peui_reset(HWND hwnd);
+ extern int volatile sa_override;
+ extern int deferring_show;
+ extern int g_showcode;
+
+ extern int eq_startuphack, pe_startuphack;
+ extern int g_skinloadedmanually;
+ void vis_init();
+ void resizeMediaWnd (HWND hwnd);
+ extern int g_skinloadedmanually;
+ int writeEQfile_init(wchar_t *file, char *name, unsigned char *tab);
+ extern int playlist_open(HWND hwnd);
+ extern int setPlRating(int rating);
+ extern int setCurrentRating(int rating);
+ extern int got_ml;
+ int peui_isrbuttoncaptured();
+ extern void makeurlcodes(char *in, char *out);
+ extern HIMAGELIST toolbarIcons;
+ extern struct ITaskbarList3* pTaskbar3;
+ void OnTaskbarButtonCreated(BOOL force);
+ LRESULT Main_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);
+ LRESULT Main_OnWASystray(HWND hwnd, int id);
+ LRESULT Main_OnWAMPEGEOF(HWND hwnd);
+ LRESULT Main_OnSize(HWND hwnd, UINT state, int cx, int cy);
+ LRESULT Main_OnTimer(HWND hwnd, UINT id);
+ LRESULT Main_OnDropFiles(HWND hwnd, HDROP hdrop);
+ LRESULT Main_OnCopyData(HWND hwnd, COPYDATASTRUCT *cds);
+ extern int m_converting;
+ void DoInstall(int is_install);
+ wchar_t *ParseParameters(wchar_t *lpszCmdParam, int *bAdd, int *bBookmark, int *bHandle, int *nCmdShow, int *bCommand, int *bCmdParam, int *bAllowCompat);
+ #ifdef BETA
+ void ParseParametersExpired(wchar_t *lpszCmdParam);
+ #endif
+ void reg_associated_filetypes(int force);
+ wchar_t *FindNextCommand(wchar_t *cmdLine);
+ void parseCmdLine(wchar_t *cmdline, HWND hwnd);
+ wchar_t *CheckFileBase(wchar_t *lpszCmdParam, HWND hwnd_other, int *exit, int mode);
+ #define CheckSkin(lpszCmdParam, hwnd_other, exit) CheckFileBase(lpszCmdParam, hwnd_other, exit, 0)
+ #define CheckLang(lpszCmdParam, hwnd_other, exit) CheckFileBase(lpszCmdParam, hwnd_other, exit, 1)
+
+ void LoadPathsIni();
+ LRESULT Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
+ extern int g_BookmarkTop, g_SkinTop, g_LangTop;
+ extern int g_open_ml_item_in_pe;
+ void RegisterConfigGroups();
+ void CopyExtendedFileInfo(const wchar_t *source, const wchar_t *destination);
+
+ int ResizeComboBoxDropDown(HWND hwndDlg, UINT id, const char* str, int width);
+ int ResizeComboBoxDropDownW(HWND hwndDlg, UINT id, const wchar_t *str, int width);
+
+ // creditsrend.c
+
+ void render_togglecredits();
+ void render_quit(void);
+ void render_render(unsigned char *framebuffer, HDC hdc);
+ void render_init(int w, int h, char *pal);
+
+ // InW.cpp
+ int InW_IsOurFile(In_Module *mod, const wchar_t *filename);
+ int InW_Play(In_Module *mod, const wchar_t *filename);
+ int InW_InfoBox(In_Module *mod, const wchar_t *filename, HWND parent);
+ void InW_GetFileInfo(In_Module *mod, const wchar_t *filename, wchar_t *title, int *length);
+
+ // conversions.cpp
+ void Float32_To_Int16_Clip(void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count);
+ void Float32_To_Int24_Clip(void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count);
+
+ HANDLE DuplicateCurrentThread();
+
+ /* dwm.cpp */
+ extern BOOL atti_present;
+ void DisableVistaPreview();
+ void DoTheVistaVideoDance();
+ void RegisterThumbnailTab(HWND hWnd);
+ void UnregisterThumbnailTab(HWND hWnd);
+ void OnIconicThumbnail(int width, int height);
+ void OnThumbnailPreview();
+ void RefreshIconicThumbnail();
+
+ /* handler.cpp */
+ int HandleFilename(const wchar_t *filename);
+
+ /* IVideoD3DOSD.cpp */
+ HMODULE FindD3DX9();
+
+ /* AlbumArt.cpp */
+ void CleanNameForPath(wchar_t *name);
+
+ /* application.cpp */
+ BOOL IsDirectMouseWheelMessage(const UINT uMsg);
+ BOOL DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable);
+ BOOL DirectMouseWheel_IsConvertToMouseWheelEnabled(HWND hwnd);
+ BOOL DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen);
+ HWND ActiveChildWindowFromPoint(HWND hwnd, POINTS cursor_s, const int *controls, size_t controlsCount);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif \ No newline at end of file
diff --git a/Src/Winamp/MediaCoreCOM.cpp b/Src/Winamp/MediaCoreCOM.cpp
new file mode 100644
index 00000000..3f06c3ef
--- /dev/null
+++ b/Src/Winamp/MediaCoreCOM.cpp
@@ -0,0 +1,398 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author: Ben Allison benski@nullsoft.com
+** Created:
+**/
+#include "main.h"
+#include "MediaCoreCOM.h"
+#include "jsapi.h"
+
+enum
+{
+ DISP_MEDIACORE_ISREGISTEREDEXTENSION = 777,
+ DISP_MEDIACORE_GETMETADATA,
+ DISP_MEDIACORE_REGISTER_CALLBACK,
+ DISP_MEDIACORE_UNREGISTER_CALLBACK,
+ DISP_MEDIACORE_PLAY,
+ DISP_MEDIACORE_ENQUEUE,
+ DISP_MEDIACORE_PAUSE,
+ DISP_MEDIACORE_RESUME,
+ DISP_MEDIACORE_VOLUME,
+};
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT MediaCoreCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ UNREFERENCED_PARAMETER(riid);
+
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("IsRegisteredExtension", DISP_MEDIACORE_ISREGISTEREDEXTENSION)
+ CHECK_ID("GetMetadata", DISP_MEDIACORE_GETMETADATA)
+ CHECK_ID("RegisterCallback", DISP_MEDIACORE_REGISTER_CALLBACK)
+ CHECK_ID("UnregisterCallback", DISP_MEDIACORE_UNREGISTER_CALLBACK)
+ CHECK_ID("Play", DISP_MEDIACORE_PLAY)
+ CHECK_ID("Enqueue", DISP_MEDIACORE_ENQUEUE)
+ CHECK_ID("Pause", DISP_MEDIACORE_PAUSE)
+ CHECK_ID("Resume", DISP_MEDIACORE_RESUME)
+ CHECK_ID("volume", DISP_MEDIACORE_VOLUME)
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT MediaCoreCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ UNREFERENCED_PARAMETER(itinfo);
+ UNREFERENCED_PARAMETER(lcid);
+ UNREFERENCED_PARAMETER(pptinfo);
+ return E_NOTIMPL;
+}
+
+HRESULT MediaCoreCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ UNREFERENCED_PARAMETER(pctinfo);
+ return E_NOTIMPL;
+}
+
+HRESULT MediaCoreCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ UNREFERENCED_PARAMETER(riid);
+ UNREFERENCED_PARAMETER(lcid);
+ UNREFERENCED_PARAMETER(pexecinfo);
+
+ switch (dispid)
+ {
+ case DISP_MEDIACORE_PLAY:
+ {
+ if (pdispparams->cArgs < 1 || pdispparams->cArgs > 3)
+ return DISP_E_BADPARAMCOUNT;
+
+ /* we're probably not on the main thread, so we'll have to get onto the main thread */
+ // TODO: APC this instead of SendMessageW
+ enqueueFileWithMetaStructW s = {0,0,0,0};
+ SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_DELETE);
+
+ switch(pdispparams->cArgs)
+ {
+ case 1:
+ s.filename = pdispparams->rgvarg[0].bstrVal;
+ break;
+ case 2:
+ s.filename = pdispparams->rgvarg[1].bstrVal;
+ s.title = pdispparams->rgvarg[0].bstrVal;
+ break;
+ case 3:
+ s.filename = pdispparams->rgvarg[2].bstrVal;
+ s.title = pdispparams->rgvarg[1].bstrVal;
+ s.length = pdispparams->rgvarg[0].lVal;
+ break;
+ }
+
+ s.ext = NULL;
+
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
+ SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_STARTPLAY);
+ return S_OK;
+ }
+ case DISP_MEDIACORE_ENQUEUE:
+ {
+ if (pdispparams->cArgs < 1 || pdispparams->cArgs > 3)
+ return DISP_E_BADPARAMCOUNT;
+
+ /* we're probably not on the main thread, so we'll have to get onto the main thread */
+ // TODO: APC this instead of SendMessageW
+ enqueueFileWithMetaStructW s = {0,0,0,0};
+
+ switch(pdispparams->cArgs)
+ {
+ case 1:
+ s.filename = pdispparams->rgvarg[0].bstrVal;
+ break;
+ case 2:
+ s.filename = pdispparams->rgvarg[1].bstrVal;
+ s.title = pdispparams->rgvarg[0].bstrVal;
+ break;
+ case 3:
+ s.filename = pdispparams->rgvarg[2].bstrVal;
+ s.title = pdispparams->rgvarg[1].bstrVal;
+ s.length = pdispparams->rgvarg[0].lVal;
+ break;
+ }
+
+ s.ext = NULL;
+
+ SendMessageW( hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_ENQUEUEFILEW );
+
+ return S_OK;
+ }
+ case DISP_MEDIACORE_ISREGISTEREDEXTENSION:
+ {
+ bool isReg = false;
+ if (pdispparams->cArgs == 1)
+ {
+ const wchar_t *filename = pdispparams->rgvarg[0].bstrVal;
+ int start_offs=0;
+ In_Module *i = in_setmod_noplay(filename, &start_offs);
+ if (i)
+ isReg = true;
+ }
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BOOL;
+ V_BOOL(pvarResult) = (false != isReg) ? VARIANT_TRUE : VARIANT_FALSE;
+ return S_OK;
+ }
+ break;
+
+ case DISP_MEDIACORE_GETMETADATA:
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
+
+ JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
+
+ {
+ wchar_t buffer[4096] = {0};
+ extendedFileInfoStructW info = {0};
+
+ info.filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ info.metadata = JSAPI_PARAM(pdispparams, 2).bstrVal;
+ info.ret = buffer;
+ info.retlen = sizeof(buffer)/sizeof(*buffer);
+
+ if (NULL != info.filename &&
+ NULL != info.metadata)
+ {
+ if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ info.ret = NULL;
+
+ JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
+ }
+ else
+ JSAPI_EMPTY_RESULT(pvarResult);
+ }
+ return S_OK;
+
+ case DISP_MEDIACORE_REGISTER_CALLBACK:
+ return coreCallbacks.RegisterFromDispParam(pdispparams, 0, puArgErr);
+
+ case DISP_MEDIACORE_UNREGISTER_CALLBACK:
+ return coreCallbacks.UnregisterFromDispParam(pdispparams, 0, puArgErr);
+
+ case DISP_MEDIACORE_PAUSE:
+ PausePlaying();
+ return S_OK;
+ case DISP_MEDIACORE_RESUME:
+ UnPausePlaying();
+ return S_OK;
+ case DISP_MEDIACORE_VOLUME:
+ {
+ if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
+
+ SendMessageW(hMainWindow, WM_WA_IPC, JSAPI_PARAM(pdispparams, 1).lVal, IPC_SETVOLUME);
+
+ return S_OK;
+ }
+ else if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)-666, IPC_SETVOLUME);
+ return S_OK;
+ }
+ }
+ break;
+
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP MediaCoreCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG MediaCoreCOM::AddRef(void)
+{
+ return 0;
+}
+
+ULONG MediaCoreCOM::Release(void)
+{
+ return 0;
+}
+
+void CallDispatchMethod(IDispatch *dispatch, DISPPARAMS &params, OLECHAR *name)
+{
+ unsigned int ret;
+ DISPID dispid;
+
+ if (NULL == dispatch)
+ return;
+
+ if (!(config_no_visseh&8))
+ {
+ __try
+ {
+ if (SUCCEEDED(dispatch->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
+ dispatch->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ }
+ else
+ {
+ if (SUCCEEDED(dispatch->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
+ dispatch->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+ }
+}
+
+static void Play_NotifyCb(IDispatch *dispatch, void *param)
+{
+ UNREFERENCED_PARAMETER(param);
+
+ DISPPARAMS params;
+
+ if (NULL == dispatch)
+ return;
+
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = 0;
+ params.rgvarg = 0;
+
+ CallDispatchMethod(dispatch, params, L"OnPlay");
+}
+
+struct StopNotifyParam
+{
+ DISPPARAMS params;
+ VARIANT arguments[2];
+
+ StopNotifyParam(int last_time, int fullstop)
+ {
+ VariantInit(&arguments[0]);
+ V_VT(&arguments[0]) = VT_BOOL;
+ V_BOOL(&arguments[0]) = (0 != fullstop) ? VARIANT_TRUE : VARIANT_FALSE;
+
+ VariantInit(&arguments[1]);
+ V_VT(&arguments[1]) = VT_I4;
+ V_I4(&arguments[1]) = last_time;
+
+ params.cArgs = ARRAYSIZE(arguments);
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = NULL;
+ params.rgvarg = arguments;
+ }
+};
+
+static void Stop_NotifyCb(IDispatch *dispatch, void *param)
+{
+ StopNotifyParam *stopParams = (StopNotifyParam*)param;
+
+ if (NULL == dispatch ||
+ NULL == stopParams)
+ {
+ return;
+ }
+
+ CallDispatchMethod(dispatch, stopParams->params, L"OnStop");
+}
+
+static void Stop_FreeCb(void *param)
+{
+ StopNotifyParam *stopParam;
+ stopParam = (StopNotifyParam*)param;
+
+ if (NULL != stopParam)
+ delete(stopParam);
+}
+
+static void Pause_NotifyCb(IDispatch *dispatch, void *param)
+{
+ UNREFERENCED_PARAMETER(param);
+
+ DISPPARAMS params;
+
+ if (NULL == dispatch)
+ return;
+
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = 0;
+ params.rgvarg = 0;
+
+ CallDispatchMethod(dispatch, params, L"OnPause");
+}
+
+static void Resume_NotifyCb(IDispatch *dispatch, void *param)
+{
+ UNREFERENCED_PARAMETER(param);
+
+ DISPPARAMS params;
+
+ if (NULL == dispatch)
+ return;
+
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = 0;
+ params.rgvarg = 0;
+
+ CallDispatchMethod(dispatch, params, L"OnResume");
+}
+
+void MediaCoreCOM::OnPlay()
+{
+ coreCallbacks.Notify(Play_NotifyCb, NULL, NULL);
+}
+
+void MediaCoreCOM::OnStop(int last_time, int fullstop)
+{
+ StopNotifyParam *param;
+
+ param = new StopNotifyParam(last_time, fullstop);
+ if (NULL == param)
+ return;
+
+ coreCallbacks.Notify(Stop_NotifyCb, Stop_FreeCb, param);
+}
+
+void MediaCoreCOM::OnPause()
+{
+ coreCallbacks.Notify(Pause_NotifyCb, NULL, NULL);
+}
+void MediaCoreCOM::OnResume()
+{
+ coreCallbacks.Notify(Resume_NotifyCb, NULL, NULL);
+}
diff --git a/Src/Winamp/MediaCoreCOM.h b/Src/Winamp/MediaCoreCOM.h
new file mode 100644
index 00000000..9b5fa0c0
--- /dev/null
+++ b/Src/Winamp/MediaCoreCOM.h
@@ -0,0 +1,34 @@
+#ifndef NULLSOFT_WINAMP_MEDIACORECOM_H
+#define NULLSOFT_WINAMP_MEDIACORECOM_H
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./dispatchCallback.h"
+
+class MediaCoreCOM : public IDispatch
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+public:
+ void OnPlay();
+ void OnStop(int last_time, int fullstop);
+ void OnPause();
+ void OnResume();
+
+private:
+ DispatchCallbackStore coreCallbacks;
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/MemoryManager.cpp b/Src/Winamp/MemoryManager.cpp
new file mode 100644
index 00000000..22f17978
--- /dev/null
+++ b/Src/Winamp/MemoryManager.cpp
@@ -0,0 +1,69 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "MemoryManager.h"
+#include "api.h"
+
+#include <api/syscb/callbacks/syscb.h>
+#include <api/syscb/callbacks/sysmemcb.h>
+
+void *MemoryManager::Malloc(size_t size)
+{
+ if (size <= 0) return NULL;
+ void *ret = calloc(size, 1);
+ if (ret != NULL)
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SYSMEM, SysMemCallback::ONMALLOC, (intptr_t)ret, size);
+ return ret;
+}
+
+void MemoryManager::Free(void *ptr)
+{
+ if (ptr != NULL)
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SYSMEM, SysMemCallback::ONFREE, (intptr_t)ptr);
+ free(ptr);
+}
+
+void *MemoryManager::Realloc(void *ptr, size_t newsize)
+{
+ void *ptrs[2] = {ptr, 0};
+ void *new_memory = realloc(ptr, newsize);
+ if (new_memory)
+ ptrs[1] = new_memory;
+ else
+ {
+ new_memory = calloc(newsize, 1);
+ if (new_memory)
+ {
+ memcpy(new_memory, ptr, _msize(ptr));
+ ptrs[1] = new_memory;
+ }
+ }
+
+ if (!(ptrs[0] == NULL && ptrs[1] == NULL))
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SYSMEM, SysMemCallback::ONREALLOC, (intptr_t)ptrs, newsize);
+
+ return new_memory;
+}
+
+void MemoryManager::MemChanged(void *ptr)
+{
+ if (ptr == NULL) return ;
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SYSMEM, SysMemCallback::ONCHANGE, (intptr_t)ptr);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS MemoryManager
+START_DISPATCH;
+ CB(API_MEMMGR_SYSMALLOC, Malloc);
+ VCB(API_MEMMGR_SYSFREE, Free);
+ CB(API_MEMMGR_SYSREALLOC, Realloc);
+ VCB(API_MEMMGR_SYSMEMCHANGED, MemChanged);
+END_DISPATCH;
diff --git a/Src/Winamp/MemoryManager.h b/Src/Winamp/MemoryManager.h
new file mode 100644
index 00000000..757f5a77
--- /dev/null
+++ b/Src/Winamp/MemoryManager.h
@@ -0,0 +1,23 @@
+#ifndef __MEMMGRAPI_H
+#define __MEMMGRAPI_H
+
+#include <api/memmgr/api_memmgr.h>
+
+class MemoryManager : public api_memmgr
+{
+public:
+ static const char *getServiceName() { return "Memory Manager"; }
+ static const GUID getServiceGuid() { return memMgrApiServiceGuid; }
+public:
+ void *Malloc(size_t size);
+ void Free(void *ptr);
+ void *Realloc(void *ptr, size_t newsize);
+ void MemChanged(void *ptr);
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern MemoryManager *memoryManager;
+
+#endif
diff --git a/Src/Winamp/MergePlaylist.cpp b/Src/Winamp/MergePlaylist.cpp
new file mode 100644
index 00000000..98bda46c
--- /dev/null
+++ b/Src/Winamp/MergePlaylist.cpp
@@ -0,0 +1,247 @@
+#include "main.h"
+#include "MergePlaylist.h"
+#include <strsafe.h>
+
+merge_pl_entry::merge_pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms )
+{
+ SetFilename( p_filename );
+ SetTitle( p_title );
+ SetLengthMilliseconds( p_length_ms );
+}
+
+merge_pl_entry::~merge_pl_entry()
+{
+ plstring_release( this->filename );
+ plstring_release( this->filetitle );
+}
+
+
+size_t merge_pl_entry::GetFilename( wchar_t *p_filename, size_t filenameCch )
+{
+ if ( !this->filename )
+ return 0;
+
+ if ( !p_filename )
+ return wcslen( this->filename );
+
+ if ( !this->filename[ 0 ] )
+ return 0;
+
+ StringCchCopyW( p_filename, filenameCch, this->filename );
+
+ return 1;
+}
+
+size_t merge_pl_entry::GetTitle( wchar_t *p_title, size_t titleCch )
+{
+ if ( !this->filetitle )
+ return 0;
+
+ if ( !p_title )
+ return wcslen( this->filetitle );
+
+ if ( !this->filetitle[ 0 ] )
+ return 0;
+
+ StringCchCopyW( p_title, titleCch, this->filetitle );
+
+ return 1;
+}
+
+int merge_pl_entry::GetLengthInMilliseconds()
+{
+ return length;
+}
+
+size_t merge_pl_entry::GetExtendedInfo( const wchar_t *metadata, wchar_t *info, size_t infoCch )
+{
+ return 0;
+}
+
+
+void merge_pl_entry::SetFilename( const wchar_t *p_filename )
+{
+ plstring_release( this->filename );
+
+ if ( p_filename && p_filename[ 0 ] )
+ this->filename = plstring_wcsdup( p_filename );
+ else
+ this->filename = 0;
+}
+
+void merge_pl_entry::SetTitle( const wchar_t *p_title )
+{
+ plstring_release( filetitle );
+
+ if ( p_title && p_title[ 0 ] )
+ {
+ this->filetitle = plstring_wcsdup( p_title );
+ this->cached = true;
+ }
+ else
+ filetitle = 0;
+}
+
+void merge_pl_entry::SetLengthMilliseconds( int p_length_ms )
+{
+ if ( p_length_ms <= 0 )
+ this->length = -1000;
+ else
+ this->length = p_length_ms;
+}
+
+
+
+MergePlaylist::MergePlaylist()
+{
+ total_time = 0;
+}
+
+void MergePlaylist::Clear()
+{
+ for ( merge_pl_entry *l_merged_entry : entries )
+ delete l_merged_entry;
+
+ entries.clear();
+}
+
+void MergePlaylist::OnFile( const wchar_t *p_filename, const wchar_t *p_title, int lengthInMS, ifc_plentryinfo *info )
+{
+ if ( lengthInMS > 0 )
+ total_time += lengthInMS;
+
+ entries.push_back( new merge_pl_entry( p_filename, p_title, lengthInMS ) );
+}
+
+void MergePlaylist::AppendWithInfo( const wchar_t *p_filename, const wchar_t *p_title, int lengthInMS )
+{
+ if ( lengthInMS > 0 )
+ total_time += lengthInMS;
+
+ entries.push_back( new merge_pl_entry( p_filename, p_title, lengthInMS ) );
+}
+
+MergePlaylist::~MergePlaylist()
+{
+ Clear();
+}
+
+size_t MergePlaylist::GetNumItems()
+{
+ return entries.size();
+}
+
+size_t MergePlaylist::GetItem( size_t item, wchar_t *p_filename, size_t filenameCch )
+{
+ if ( item >= entries.size() )
+ return 0;
+
+ return entries[ item ]->GetFilename( p_filename, filenameCch );
+}
+
+size_t MergePlaylist::GetItemTitle( size_t item, wchar_t *p_title, size_t titleCch )
+{
+ if ( item >= entries.size() )
+ return 0;
+
+ return entries[ item ]->GetTitle( p_title, titleCch );
+}
+
+const wchar_t *MergePlaylist::ItemTitle( size_t item )
+{
+ if ( item >= entries.size() )
+ return 0;
+
+ return entries[ item ]->filetitle;
+}
+
+const wchar_t *MergePlaylist::ItemName( size_t item )
+{
+ if ( item >= entries.size() )
+ return 0;
+
+ return entries[ item ]->filename;
+}
+
+int MergePlaylist::GetItemLengthMilliseconds( size_t item )
+{
+ if ( item >= entries.size() )
+ return -1;
+
+ return entries[ item ]->GetLengthInMilliseconds();
+}
+
+size_t MergePlaylist::GetItemExtendedInfo( size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch )
+{
+ if ( item >= entries.size() )
+ return 0;
+
+ return entries[ item ]->GetExtendedInfo( metadata, info, infoCch );
+}
+
+
+void MergePlaylist::SetItemFilename( size_t item, const wchar_t *p_filename )
+{
+ if ( item < entries.size() )
+ entries[ item ]->SetFilename( p_filename );
+}
+
+void MergePlaylist::SetItemTitle( size_t item, const wchar_t *p_title )
+{
+ if ( item < entries.size() )
+ entries[ item ]->SetTitle( p_title );
+}
+
+void MergePlaylist::SetItemLengthMilliseconds( size_t item, int p_length_ms )
+{
+ if ( item < entries.size() )
+ entries[ item ]->SetLengthMilliseconds( p_length_ms );
+}
+
+void MergePlaylist::AppendPlaylist( MergePlaylist &copy )
+{
+ for ( merge_pl_entry *l_merged_entry : copy.entries )
+ {
+ if ( l_merged_entry->filename && !HasFilename( l_merged_entry->filename ) )
+ {
+ if ( l_merged_entry->length > 0 )
+ total_time += l_merged_entry->length;
+
+ entries.push_back( l_merged_entry );
+ }
+ }
+
+ copy.entries.clear();
+}
+
+bool MergePlaylist::HasFilename( const wchar_t *p_filename )
+{
+ for ( merge_pl_entry *l_merged_entry : entries )
+ {
+ if ( l_merged_entry->filename && !_wcsicmp( p_filename, l_merged_entry->filename ) )
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS MergePlaylist
+
+START_MULTIPATCH;
+START_PATCH(patch_playlist)
+M_VCB(patch_playlist, ifc_playlist, IFC_PLAYLIST_CLEAR, Clear)
+//M_VCB(patch_playlist, ifc_playlist, IFC_PLAYLIST_APPENDWITHINFO, AppendWithInfo)
+//M_VCB(patch_playlist, ifc_playlist, IFC_PLAYLIST_APPEND, Append)
+M_CB(patch_playlist, ifc_playlist, IFC_PLAYLIST_GETNUMITEMS, GetNumItems)
+M_CB(patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEM, GetItem)
+M_CB(patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEMTITLE, GetItemTitle)
+M_CB(patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, GetItemLengthMilliseconds)
+M_CB(patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEMEXTENDEDINFO, GetItemExtendedInfo)
+NEXT_PATCH(patch_playlistloadercallback)
+M_VCB(patch_playlistloadercallback, ifc_playlistloadercallback, IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile);
+END_PATCH
+END_MULTIPATCH;
diff --git a/Src/Winamp/MergePlaylist.h b/Src/Winamp/MergePlaylist.h
new file mode 100644
index 00000000..5d9be4f1
--- /dev/null
+++ b/Src/Winamp/MergePlaylist.h
@@ -0,0 +1,70 @@
+#pragma once
+#include "../playlist/ifc_playlist.h"
+#include <vector>
+#include <windows.h> // for MAX_PATH
+#include <bfc/multipatch.h>
+#include "../playlist/ifc_playlistloadercallback.h"
+
+class merge_pl_entry
+{
+public:
+ merge_pl_entry() {}
+ merge_pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms );
+ ~merge_pl_entry();
+
+ size_t GetFilename( wchar_t *p_filename, size_t filenameCch );
+ size_t GetTitle( wchar_t *p_title, size_t titleCch );
+ int GetLengthInMilliseconds();
+ size_t GetExtendedInfo( const wchar_t *metadata, wchar_t *info, size_t infoCch );
+
+ void SetFilename( const wchar_t *p_filename );
+ void SetTitle( const wchar_t *p_title );
+ void SetLengthMilliseconds( int p_length_ms );
+
+
+ wchar_t *filename = 0;
+ wchar_t *filetitle = 0;
+ int length = -1;
+ bool cached = false;
+};
+
+enum { patch_playlist, patch_playlistloadercallback };
+
+class MergePlaylist : public MultiPatch<patch_playlist, ifc_playlist>, public MultiPatch<patch_playlistloadercallback, ifc_playlistloadercallback>
+{
+public:
+ MergePlaylist();
+ ~MergePlaylist();
+
+ void Clear();
+ void OnFile( const wchar_t *p_filename, const wchar_t *p_title, int lengthInMS, ifc_plentryinfo *info );
+ void AppendWithInfo( const wchar_t *p_filename, const wchar_t *p_title, int lengthInMS );
+
+ size_t GetNumItems();
+
+ size_t GetItem( size_t item, wchar_t *p_filename, size_t filenameCch );
+ size_t GetItemTitle( size_t item, wchar_t *p_title, size_t titleCch );
+ const wchar_t *ItemTitle( size_t item );
+ const wchar_t *ItemName( size_t item );
+ int GetItemLengthMilliseconds( size_t item );
+ size_t GetItemExtendedInfo( size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch );
+
+ void SetItemFilename( size_t item, const wchar_t *p_filename );
+ void SetItemTitle( size_t item, const wchar_t *p_title );
+ void SetItemLengthMilliseconds( size_t item, int p_length_ms );
+
+ void AppendPlaylist( MergePlaylist &copy );
+
+ bool HasFilename( const wchar_t *p_filename );
+
+ uint64_t total_time;
+
+
+protected:
+ RECVS_MULTIPATCH;
+
+public:
+ //private:
+ typedef std::vector<merge_pl_entry *> PlaylistEntries;
+ PlaylistEntries entries;
+};
diff --git a/Src/Winamp/Metadata.cpp b/Src/Winamp/Metadata.cpp
new file mode 100644
index 00000000..7c316dc5
--- /dev/null
+++ b/Src/Winamp/Metadata.cpp
@@ -0,0 +1,117 @@
+#include "main.h"
+#include "Metadata.h"
+#include "api.h"
+#include <api/service/waservicefactory.h>
+
+/**
+ ** Author: Ben Allison
+ ** original date: April 10, 2006
+ */
+Metadata::~Metadata()
+{
+ for ( wchar_t *l_key : keys )
+ free( l_key );
+
+ keys.clear();
+}
+
+int Metadata::GetExtendedFileInfo(const wchar_t *filename, const wchar_t *tag, wchar_t *data, size_t dataLength)
+{
+ // benski> old way CUT: return in_get_extended_fileinfoW(filename, tag, data, dataLength);
+/*
+ int result = 0; // failure
+ svc_metaTag *metaTag = GetMetaTagObject(filename, METATAG_ALL, 0, 0);
+ if (metaTag)
+ {
+ if (metaTag->metaTag_open(filename) == METATAG_SUCCESS)
+ metaTag->getMetaData(tag, reinterpret_cast<__int8 *>(data), dataLength*sizeof(wchar_t), METATYPE_STRING);
+
+ metaTag->metaTag_close();
+ }
+ else // TODO: we could get rid of this as soon as we make extendedMetaTag (see TODO at end of file)
+ */
+ return in_get_extended_fileinfoW(filename, tag, data, dataLength);
+
+ //return !!(result == METATAG_SUCCESS);
+}
+
+int Metadata::SetExtendedFileInfo(const wchar_t *filename, const wchar_t *tag, const wchar_t *data)
+{
+ return in_set_extended_fileinfoW(filename, tag, const_cast<wchar_t *>(data));
+}
+
+int Metadata::WriteExtendedFileInfo(const wchar_t *filename)
+{
+ return in_write_extended_fileinfo();
+}
+
+inline static bool InList(const GUID guid, GUID *exclude, int numExcludes)
+{
+ if (!exclude)
+ return false;
+ while (numExcludes--)
+ {
+ if (guid == exclude[numExcludes])
+ return true;
+ }
+ return false;
+}
+
+svc_metaTag *Metadata::GetMetaTagObject(const wchar_t *filename, int flags, GUID *exclude, int numExcludes)
+{
+ int i = 0;
+ waServiceFactory *sf = 0;
+ do
+ {
+ sf = WASABI_API_SVC->service_enumService(WaSvc::METATAG, i++);
+ if (sf)
+ {
+ svc_metaTag *metaTag = static_cast<svc_metaTag *>(sf->getInterface());
+ if (metaTag
+ && !InList(metaTag->getGUID(), exclude, numExcludes)
+ && flags & metaTag->getFlags()
+ && metaTag->isOurFile(filename))
+ return metaTag;
+
+ sf->releaseInterface(metaTag);
+ }
+
+ }
+ while (sf);
+ return 0;
+}
+
+svc_metaTag *Metadata::GetMetaTagObjectByGUID(const GUID metaTagGuid)
+{
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(metaTagGuid);
+ if (sf && sf->getServiceType() == WaSvc::METATAG) // just to be safe
+ return static_cast<svc_metaTag *>(sf->getInterface());
+
+ return NULL;
+}
+
+uint32_t Metadata::GenerateKey(const wchar_t *field)
+{
+ Nullsoft::Utility::AutoLock keyLock(keyGuard);
+ // TODO this is hella slow but it'll get the ball rolling on implementing this
+ for (size_t i=0;i!=keys.size();i++)
+ {
+ if (!_wcsicmp(field, keys[i]))
+ return (uint32_t)i;
+ }
+
+ keys.push_back(_wcsdup(field));
+ return (uint32_t)keys.size()-1;
+}
+// TODO: extendedMetaTag, derived from svc_metaTag, that uses getExtendedFileInfo
+
+#define CBCLASS Metadata
+START_DISPATCH;
+CB(API_METADATA_GETEXTENDEDFILEINFO, GetExtendedFileInfo)
+CB(API_METADATA_SETEXTENDEDFILEINFO, SetExtendedFileInfo)
+CB(API_METADATA_WRITEEXTENDEDFILEINFO, WriteExtendedFileInfo)
+CB(API_METADATA_GETMETATAGOBJECT, GetMetaTagObject)
+CB(API_METADATA_GETMETATAGOBJECTBYGUID, GetMetaTagObjectByGUID)
+CB(API_METADATA_GENERATEKEY, GenerateKey)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/Metadata.h b/Src/Winamp/Metadata.h
new file mode 100644
index 00000000..5566a259
--- /dev/null
+++ b/Src/Winamp/Metadata.h
@@ -0,0 +1,33 @@
+#ifndef NULLSOFT_WINAMP_METADATA_H
+#define NULLSOFT_WINAMP_METADATA_H
+/**
+ ** Author: Ben Allison
+ ** original date: April 10, 2006
+ */
+#include "../Agave/Metadata/api_metadata.h"
+#include <vector>
+#include "../nu/AutoLock.h"
+class Metadata : public api_metadata
+{
+public:
+ static const char *getServiceName() { return "Metadata API"; }
+ static const GUID getServiceGuid() { return api_metadataGUID; }
+public:
+ ~Metadata();
+ int GetExtendedFileInfo(const wchar_t *filename, const wchar_t *tag, wchar_t *data, size_t dataLength);
+ int SetExtendedFileInfo(const wchar_t *filename, const wchar_t *tag, const wchar_t *data);
+ int WriteExtendedFileInfo(const wchar_t *filename);
+ svc_metaTag *GetMetaTagObject(const wchar_t *filename, int flags, GUID *exclude, int numExcludes);
+ svc_metaTag *GetMetaTagObjectByGUID(const GUID metaTagGuid);
+ uint32_t GenerateKey(const wchar_t *field);
+protected:
+ RECVS_DISPATCH;
+
+private:
+ // this is hella slow but it'll get the ball rolling on implementing this
+ std::vector<wchar_t*> keys;
+ Nullsoft::Utility::LockGuard keyGuard;
+};
+
+extern Metadata *metadata;
+#endif \ No newline at end of file
diff --git a/Src/Winamp/MoreItems.cpp b/Src/Winamp/MoreItems.cpp
new file mode 100644
index 00000000..3446887e
--- /dev/null
+++ b/Src/Winamp/MoreItems.cpp
@@ -0,0 +1,134 @@
+#include "main.h"
+#include "MoreItems.h"
+
+static const wchar_t g_noentry[] = L"No Entry";
+
+ wchar_t *strFile;
+ size_t cbFile;
+ wchar_t *strTitle;
+ size_t cbTitle;
+ char *strCurtain;
+ size_t cbCurtain;
+ int length;
+ int index;
+ unsigned long starttime; // Start time in MS (0, begin of file)
+ unsigned long endtime; // End time in MS (0, end of file)
+ moreitems *Next; // Next Item in linked list
+
+moreitems::moreitems()
+: strFile(0), cbFile(0), strTitle(0), cbTitle(0),
+ strCurtain(0), cbCurtain(0), length(0), index(0),
+ starttime(0), endtime(0), Next(0)
+{
+}
+
+moreitems::~moreitems()
+{
+ // recursive, find the _tail and remove it, work back to _head
+ delete Next; Next = NULL;
+ delete[] strFile; strFile=NULL;
+ delete[] strTitle;
+ delete[] strCurtain;
+}
+
+const wchar_t *moreitems::GetHiddenFilename(int index)
+{
+ if (this->index == index)
+ return strFile;
+ if (Next == NULL)
+ return g_noentry;
+ return Next->GetHiddenFilename(index);
+}
+
+int moreitems::SetRange(int index, unsigned long start, unsigned long end)
+{
+ if (this->index == index)
+ {
+ this->starttime = start;
+ this->endtime = end;
+ return 1;
+ }
+ if (Next == NULL)
+ return 0;
+ return Next->SetRange(index,start,end);
+}
+
+unsigned long moreitems::GetStart(int index)
+{
+ if (this->index == index)
+ {
+ return this->starttime;
+ }
+ if (Next == NULL)
+ return 0;
+ return Next->GetStart(index);
+}
+
+unsigned long moreitems::GetEnd(int index)
+{
+ if (this->index == index)
+ {
+ return this->endtime;
+ }
+ if (Next == NULL)
+ return 0;
+ return Next->GetEnd(index);
+}
+
+int moreitems::AddHiddenItem(const wchar_t *filename, const wchar_t *title, int length, int index, char *curtain)
+{
+ // Linked list _head
+ moreitems *additem = this;
+ if (additem && index == 1)
+ {
+ // List empty
+ // Use placeholder
+ }
+ else
+ {
+ // Found items, walk to the end
+ while (additem && additem->Next) additem = additem->Next;
+ if (additem)
+ {
+ additem->Next = new moreitems;
+ additem = additem->Next;
+ }
+ }
+ if (additem)
+ {
+ additem->cbFile = lstrlenW(filename) + 1;
+ additem->strFile = new wchar_t[additem->cbFile];
+ StringCchCopyW(additem->strFile , additem->cbFile, filename);
+ additem->cbTitle = (int)lstrlenW(title) + 1;
+ additem->strTitle = new wchar_t[additem->cbFile];
+ StringCchCopyW(additem->strTitle, additem->cbTitle, title);
+ if (curtain && *curtain)
+ {
+ additem->cbCurtain = (int)strlen(curtain) + 1;
+ additem->strCurtain = new char[additem->cbCurtain];
+ StringCchCopyA(additem->strCurtain, additem->cbCurtain, curtain);
+ }
+ else
+ {
+ additem->cbCurtain = 0;
+ additem->strCurtain = NULL;
+ }
+
+ additem->length = length;
+ additem->index = index;
+
+ return 1;
+ }
+ return 0;
+}
+
+const char *moreitems::GetHiddenCurtain(int index)
+{
+ moreitems *where = this;
+ while ( where )
+ {
+ if ( where->index == index && where->cbCurtain ) return where->strCurtain;
+ where = where->Next;
+ }
+ return NULL;
+}
diff --git a/Src/Winamp/MoreItems.h b/Src/Winamp/MoreItems.h
new file mode 100644
index 00000000..a4310a02
--- /dev/null
+++ b/Src/Winamp/MoreItems.h
@@ -0,0 +1,27 @@
+#ifndef NULLSOFT_MOREITEMSH
+#define NULLSOFT_MOREITEMSH
+
+struct moreitems
+{
+ moreitems();
+ ~moreitems();
+ const wchar_t *GetHiddenFilename(int index);
+ int AddHiddenItem(const wchar_t *filename, const wchar_t *title, int length, int index, char *curtain);
+ const char *GetHiddenCurtain(int index);
+ int SetRange(int index, unsigned long start, unsigned long end);
+ unsigned long GetStart(int index);
+ unsigned long GetEnd(int index);
+ wchar_t *strFile;
+ size_t cbFile;
+ wchar_t *strTitle;
+ size_t cbTitle;
+ char *strCurtain;
+ size_t cbCurtain;
+ int length;
+ int index;
+ unsigned long starttime; // Start time in MS (0, begin of file)
+ unsigned long endtime; // End time in MS (0, end of file)
+ moreitems *Next; // Next Item in linked list
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/OUT.H b/Src/Winamp/OUT.H
new file mode 100644
index 00000000..36738975
--- /dev/null
+++ b/Src/Winamp/OUT.H
@@ -0,0 +1,132 @@
+#ifndef NULLSOFT_OUTH
+#define NULLSOFT_OUTH
+// Output plugin interface
+
+#include <windows.h>
+#include <stddef.h>
+
+#define OUT_VER 0x10
+
+// added 5.64+
+#define OUT_VER_U 0x11
+// specify OUT_VER_U if you want to provide a unicode (wchar_t*) description and only work on 5.64+
+// specify OUT_VER to use the original (char*) description as before
+// note: we are using the fact that sizeof(char*) == sizeof(wchar_t*) to be able to allow this
+// so when using OUT_VER_U you will need to cast description to (wchar_t*) to set
+
+typedef struct
+{
+ int version; // module version (OUT_VER)
+ char *description; // description of module, with version string
+ intptr_t id; // module id. each input module gets its own. non-nullsoft modules should be >= 65536
+ // known module ids are (though these may now be deprecated...):
+ // waveout: 32
+ // gapless: 64
+ // xfade: 63
+ // disk: 33
+ // dsound: 38
+ // NULL: 65
+ // mm2: 69
+ // wasapi: 70
+
+ HWND hMainWindow; // winamp's main window (filled in by winamp)
+ HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp)
+
+ void (__cdecl *Config)(HWND hwndParent); // configuration dialog
+ void (__cdecl *About)(HWND hwndParent); // about dialog
+
+ void (__cdecl *Init)(); // called when loaded
+ void (__cdecl *Quit)(); // called when unloaded
+
+ int (__cdecl *Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
+ // this returns >=0 on success, <0 on failure
+
+ // NOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
+ // ... so don't expect the max latency returned to be what you asked for.
+ // returns max latency in ms (0 for diskwriters, etc)
+ // bufferlenms and prebufferms must be in ms. 0 to use defaults.
+ // prebufferms must be <= bufferlenms
+ // pass bufferlenms==-666 to tell the output plugin that it's clock is going to be used to sync video
+ // out_ds turns off silence-eating when -666 is passed
+
+ void (__cdecl *Close)(); // close the ol' output device.
+
+ int (__cdecl *Write)(char *buf, int len);
+ // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
+ // 1 returns not able to write (yet). Non-blocking, always.
+
+ int (__cdecl *CanWrite)(); // returns number of bytes possible to write at a given time.
+ // Never will decrease unless you call Write (or Close, heh)
+
+ int (__cdecl *IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
+ // written (i.e. closing while IsPlaying() returns 1 would truncate the song
+
+ int (__cdecl *Pause)(int pause); // returns previous pause state
+
+ void (__cdecl *SetVolume)(int volume); // volume is 0-255
+ void (__cdecl *SetPan)(int pan); // pan is -128 to 128
+
+ void (__cdecl *Flush)(int t); // flushes buffers and restarts output at time t (in ms) (used for seeking)
+
+ int (__cdecl *GetOutputTime)(); // returns played time in MS
+ int (__cdecl *GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
+
+} Out_Module;
+
+// These are the return values to be used with the uninstall plugin export function:
+// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
+// which determines if Winamp can uninstall the plugin immediately or on winamp restart.
+// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
+//
+// Note: output plugins cannot be uninstalled without a reboot (unlike other plugin types).
+// From Winamp 5.6 and higher, if you do return a non-zero value then it will still be
+// able to uninstall the plug-in (prior to this, returning non-zero prevented uninstall).
+//
+#define OUT_PLUGIN_UNINSTALL_REBOOT 0x0
+//
+// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
+// that it is down to you to ensure that if uninstall now is returned that it will not
+// cause a crash i.e. don't use if you've been subclassing the main window.
+//
+// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
+//
+
+// For a output plugin to be correctly detected by Winamp you need to ensure that
+// the exported winampGetOutModule(..) is exported as an undecorated function
+// e.g.
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+// __declspec(dllexport) Out_Module * __cdecl winampGetOutModule(){ return &plugin; }
+// #ifdef __cplusplus
+// }
+// #endif
+//
+
+
+// added 5.64+
+// this is used to notify a compatible output plug-in when it is being used or not
+// as the currently active output plug-in allowing it to clean up things as needed
+
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+// __declspec(dllexport) void __cdecl winampGetOutModeChange(int mode){ }
+// #ifdef __cplusplus
+// }
+// #endif
+
+// the following are passed to the exported function indicating the state and also
+// where the change has been triggered by:
+
+#define OUT_UNSET 0x0 // no longer the active output
+#define OUT_SET 0x1 // is becoming the active output
+#define OUT_PLAYBACK 0x100 // used when playback begins and an output plug-in
+ // is set for an input plug-in or not based on the
+ // input plug-in settings when the playback begins
+
+// note: it is possible to get seemingly 'repeat' mode changes as changing of the
+// output plug-in via the preferences often is not fully applied until the
+// (re-)starting of playback and the related updating of the input plug-in.
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/OpenFileDialog.cpp b/Src/Winamp/OpenFileDialog.cpp
new file mode 100644
index 00000000..d25c0538
--- /dev/null
+++ b/Src/Winamp/OpenFileDialog.cpp
@@ -0,0 +1,467 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include "resource.h"
+#include "strutil.h"
+#include "../nu/AutoChar.h"
+#include "api.h"
+#include <shlwapi.h>
+#include <shobjidl.h>
+
+/*static wchar_t *inc(wchar_t *p, size_t &size, int extra=0)
+{
+ int len = lstrlenW(p) + extra;
+ size-=len;
+ p+=len;
+ return p;
+}*/
+
+#if 0
+extern std::vector<In_Module*> in_modules;
+void getNewFileVistaPlus(int clearlist, HWND hwnd, const wchar_t *path)
+{
+ IFileOpenDialog *pFileOpen;
+ static int qq;
+ if (qq) return;
+ qq = 1;
+ HRESULT hr = CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen));
+ if (SUCCEEDED(hr))
+ {
+ wchar_t titleStr[128] = {0};
+
+ pFileOpen->SetTitle(getStringW((clearlist ? IDS_OFD_OPEN_FILES : IDS_OFD_ADD_FILES_TO_PLAYLIST),titleStr,128));
+ pFileOpen->SetDefaultExtension(L"");
+ pFileOpen->SetOptions(FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST);
+ if(!clearlist) pFileOpen->SetOkButtonLabel(L"Add");
+
+ IShellItem* shellItem;
+ hr = SHCreateItemFromParsingName((!path ? WASABI_API_APP->path_getWorkingPath() : path), 0, IID_IShellItem, reinterpret_cast<void**>(&shellItem));
+ if (SUCCEEDED(hr))
+ {
+ pFileOpen->SetFolder(shellItem);
+ }
+
+ wchar_t *fsb = in_getfltstrW(TRUE);
+ int filterNum = 0;
+ // allocate enough for the number of input plug-ins plus 'all supported' and 'all files'
+ COMDLG_FILTERSPEC *fileTypes = new COMDLG_FILTERSPEC[in_modules.size() + 2];
+ while(fsb && *fsb && *fsb+1)
+ {
+ int len = lstrlenW(fsb) + 1;
+ wchar_t *fsb2 = fsb + len;
+ fileTypes[filterNum].pszName = fsb;
+ fileTypes[filterNum].pszSpec = fsb2;
+ CharUpperBuffW(fsb2, lstrlenW(fsb2));
+ filterNum++;
+ fsb += len + lstrlenW(fsb2) + 1;
+ }
+
+ pFileOpen->SetFileTypes(filterNum, fileTypes);
+
+ if (hwnd == hMainWindow)
+ UninitDragDrops();
+
+ hr = pFileOpen->Show(hwnd);
+ if (SUCCEEDED(hr))
+ {
+ IShellItemArray *pItems;
+ hr = pFileOpen->GetResults(&pItems);
+ if (SUCCEEDED(hr))
+ {
+ IEnumShellItems *sItems;
+ hr = pItems->EnumItems(&sItems);
+ if (SUCCEEDED(hr))
+ {
+ DWORD numItems = 0;
+ pItems->GetCount(&numItems);
+
+ int sp;
+ if (clearlist)
+ {
+ sp = 0; PlayList_delete();
+ }
+ else sp = PlayList_getlength();
+
+ if(numItems <= 1)
+ {
+ IShellItem *pItem;
+ if(sItems->Next(1, &pItem, NULL) == S_OK)
+ {
+ LPWSTR folderpath = NULL;
+ LPWSTR filepath = NULL;
+ hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &filepath);
+ if (SUCCEEDED(hr))
+ {
+ IShellItem *ppItem;
+ hr = pItem->GetParent(&ppItem);
+ if (SUCCEEDED(hr))
+ {
+ hr = ppItem->GetDisplayName(SIGDN_FILESYSPATH, &folderpath);
+ if (SUCCEEDED(hr))
+ {
+ WASABI_API_APP->path_setWorkingPath(folderpath);
+ }
+ }
+
+ if (LoadPlaylist(filepath, 1, 0) == -1) // if not a playlist file
+ {
+ PlayList_append(filepath, 0);
+ }
+
+ CoTaskMemFree(filepath);
+ CoTaskMemFree(folderpath);
+ }
+ }
+ pItem->Release();
+ }
+ else
+ {
+ size_t size = ((numItems + 1) * MAX_PATH);
+ wchar_t *temp = (wchar_t *)GlobalAlloc(GPTR, size * sizeof(wchar_t)), *p = temp;
+ IShellItem *pItem;
+ while(sItems->Next(1, &pItem, NULL) == S_OK)
+ {
+ LPWSTR folderpath = NULL;
+ LPWSTR filepath = NULL;
+ hr = pItem->GetDisplayName(SIGDN_NORMALDISPLAY, &filepath);
+ if (SUCCEEDED(hr))
+ {
+ // replicate how lpstrFile is filled under a multiple select
+ // -> selected folder followed by each filename \0 separated
+ if(p == temp)
+ {
+ IShellItem *ppItem;
+ hr = pItem->GetParent(&ppItem);
+ if (SUCCEEDED(hr))
+ {
+ hr = ppItem->GetDisplayName(SIGDN_FILESYSPATH, &folderpath);
+ if (SUCCEEDED(hr))
+ {
+ WASABI_API_APP->path_setWorkingPath(folderpath);
+
+ if(StringCchCatW(p, size, folderpath) == S_OK)
+ {
+ int len = lstrlenW(folderpath) + 1;
+ p += len;
+ size -= len;
+ }
+ }
+ }
+ }
+
+ if(StringCchCatW(p, size, filepath) == S_OK)
+ {
+ int len = lstrlenW(filepath) + 1;
+ p += len;
+ size -= len;
+ }
+
+ CoTaskMemFree(filepath);
+ CoTaskMemFree(folderpath);
+ }
+ pItem->Release();
+ }
+
+ PlayList_addfromdlg(temp);
+ if (config_rofiob&1) PlayList_sort(2, sp);
+
+ GlobalFree(temp);
+ }
+
+ if (clearlist)
+ BeginPlayback();
+
+ sItems->Release();
+ }
+ pItems->Release();
+ }
+ }
+ pFileOpen->Release();
+ GlobalFree(fsb);
+
+ if (hwnd == hMainWindow)
+ InitDragDrops();
+ for(;;)
+ {
+ MSG msg;
+ if (!PeekMessage(&msg, hMainWindow, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
+ break;
+ }
+ }
+ qq = 0;
+}
+#endif
+
+void getNewFile(int clearlist, HWND hwnd, const wchar_t *path) // if clearlist is 1, playlist is cleared
+{
+ // TODO - Egg was having stability issues with this so keeping disabled until resolved
+ // on Vista and up use the IFileOpenDialog interface as it
+ // allows us to get around the MAX_PATH file filter issues
+ /*if(IsVista())
+ {
+ getNewFileVistaPlus(clearlist, hwnd, path);
+ return;
+ }*/
+
+ // otherwise revert to using the older pre-Vista methods
+ const int len = 256 * 1024 - 128;
+
+ wchar_t oldCurPath[MAX_PATH] = {0}, titleStr[128] = {0};
+
+ GetCurrentDirectoryW(MAX_PATH, oldCurPath);
+ wchar_t *temp, *fsb;
+ OPENFILENAMEW l = {sizeof(OPENFILENAMEW),0};
+ static int q;
+ if (q) return;
+ q = 1;
+ temp = (wchar_t *)GlobalAlloc(GPTR, len * sizeof(wchar_t));
+ l.lStructSize = sizeof(l);
+ l.hwndOwner = hwnd;
+ l.lpstrFilter = fsb = in_getfltstrW(FALSE);
+
+ l.lpstrFile = temp;
+ l.nMaxFile = len - 1;
+ l.lpstrTitle = getStringW((clearlist ? IDS_OFD_OPEN_FILES : IDS_OFD_ADD_FILES_TO_PLAYLIST),titleStr,128);
+ l.lpstrDefExt = L"";
+ l.lpstrInitialDir = path;
+ if (!l.lpstrInitialDir) l.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();
+
+ l.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ALLOWMULTISELECT
+ | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
+ if (hwnd == hMainWindow)
+ UninitDragDrops();
+ if (GetOpenFileNameW(&l))
+ {
+ wchar_t newCurPath[MAX_PATH] = {0};
+ GetCurrentDirectoryW(MAX_PATH, newCurPath);
+ WASABI_API_APP->path_setWorkingPath(newCurPath);
+ int sp;
+ if (clearlist)
+ {
+ sp = 0; PlayList_delete();
+ }
+ else sp = PlayList_getlength();
+ if (temp[lstrlenW(temp)+1])
+ {
+ PlayList_addfromdlg(temp);
+ if (config_rofiob&1) PlayList_sort(2, sp);
+ }
+ else
+ {
+ if (LoadPlaylist(temp, 1, 0) == -1) // if not a playlist file
+ {
+ PlayList_append(temp, 0);
+ }
+ }
+ if (clearlist)
+ BeginPlayback();
+ }
+ SetCurrentDirectoryW(oldCurPath);
+
+ if (hwnd == hMainWindow)
+ InitDragDrops();
+ for(;;)
+ {
+ MSG msg;
+ if (!PeekMessage(&msg, hMainWindow, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
+ break;
+ }
+ GlobalFree(fsb);
+ GlobalFree(temp);
+ q = 0;
+}
+
+static wchar_t loc[FILENAME_SIZE];
+int ResizeComboBoxDropDown(HWND hwndDlg, UINT id, const char* str, int width){
+ SIZE size = {0};
+ HWND control = GetDlgItem(hwndDlg, id);
+ HDC hdc = GetDC(control);
+ // get and select parent dialog's font so that it'll calculate things correctly
+ HFONT font = (HFONT)SendMessageW(hwndDlg,WM_GETFONT,0,0), oldfont = (HFONT)SelectObject(hdc,font);
+ GetTextExtentPoint32A(hdc, str, lstrlenA(str)+1, &size);
+
+ int ret = width;
+ if(size.cx > width)
+ {
+ SendDlgItemMessage(hwndDlg, id, CB_SETDROPPEDWIDTH, size.cx, 0);
+ ret = size.cx;
+ }
+
+ SelectObject(hdc, oldfont);
+ ReleaseDC(control, hdc);
+ return ret;
+}
+
+int ResizeComboBoxDropDownW(HWND hwndDlg, UINT id, const wchar_t *str, int width){
+ SIZE size = {0};
+ HWND control = GetDlgItem(hwndDlg, id);
+ HDC hdc = GetDC(control);
+ // get and select parent dialog's font so that it'll calculate things correctly
+ HFONT font = (HFONT)SendMessageW(hwndDlg,WM_GETFONT,0,0), oldfont = (HFONT)SelectObject(hdc,font);
+ GetTextExtentPoint32W(hdc, str, (int) wcslen(str)+1, &size);
+
+ int ret = width;
+ if(size.cx > width)
+ {
+ SendDlgItemMessage(hwndDlg, id, CB_SETDROPPEDWIDTH, size.cx, 0);
+ ret = size.cx;
+ }
+
+ SelectObject(hdc, oldfont);
+ ReleaseDC(control, hdc);
+ return ret;
+}
+
+static LRESULT WINAPI locProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ if(lParam) SetWindowTextW(hwndDlg, getStringW(IDS_ADD_URL, NULL, 0));
+ SendDlgItemMessageW(hwndDlg, IDC_URL_NEW, CB_LIMITTEXT, sizeof(loc)/sizeof(*loc) - 1, 0);
+ {
+ int width = 0, x = 0;
+ HWND h = GetDlgItem(hwndDlg, IDC_URL_NEW);
+ SendMessageW(h, CB_SETHORIZONTALEXTENT, 400, 0);
+ while(1)
+ {
+ char s[123] = {0};
+ wchar_t name[FILENAME_SIZE] = {0};
+ StringCchPrintfA(s, 123, "RecentURL%d", x + 1);
+ _r_sW(s, name, 123);
+ if (!name[0]) break;
+ SendMessageW(h, CB_ADDSTRING, 0, (LPARAM)name);
+ width = ResizeComboBoxDropDownW(hwndDlg, IDC_URL_NEW, name, width);
+ x++;
+ }
+
+ // show add / open loc window and restore last position as applicable
+ POINT pt = {loc_rect.left, loc_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, loc_rect.left, loc_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+ }
+
+ SetDlgItemTextW(hwndDlg, IDC_URL_NEW, loc);
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetDlgItemTextW(hwndDlg, IDC_URL_NEW, loc, sizeof(loc)/sizeof(*loc) - 1);
+ {
+ wchar_t *p = loc;
+ while (IsCharSpaceW(*p)) p = CharNextW(p);
+ if (!*p) EndDialog(hwndDlg, 1);
+ else recent_add(loc);
+ }
+ case IDCANCEL:
+ GetWindowRect(hwndDlg, &loc_rect);
+ EndDialog(hwndDlg, (LOWORD(wParam) == IDCANCEL));
+ return FALSE;
+ case IDRESET:
+ if (LPMessageBox(hwndDlg, IDS_RESET_URLS, IDS_RESET_URLS_TITLE, MB_ICONQUESTION | MB_YESNO) == IDYES)
+ {
+ int x = 1;
+ while(1)
+ {
+ char s[123] = {0};
+ wchar_t name[FILENAME_SIZE] = {0};
+ StringCchPrintfA(s, 123, "RecentURL%d", x);
+ _r_sW(s, name, 123);
+ _w_sW(s, 0);
+ if (!name[0]) break;
+ x++;
+ }
+
+ // clear out but keep what's been currently entered so as not to annoy people...
+ GetDlgItemTextW(hwndDlg, IDC_URL_NEW, loc, ARRAYSIZE(loc));
+ SendDlgItemMessage(hwndDlg, IDC_URL_NEW, CB_RESETCONTENT, 0, 0);
+ SetDlgItemTextW(hwndDlg, IDC_URL_NEW, loc);
+ }
+ return FALSE;
+ }
+ return FALSE;
+ case WM_CLOSE:
+ EndDialog(hwndDlg, 2);
+ return FALSE;
+ }
+ return 0;
+}
+
+LRESULT getNewLocation(int clearlist, HWND hwnd) // if clearlist is 1, playlist is cleared
+{
+ static int q;
+ if (q) return 0;
+ q = 1;
+ if (!LPDialogBoxParamW(IDD_OPENLOC, hwnd, (DLGPROC)locProc, !clearlist))
+ {
+ wchar_t *beg = loc;
+ wchar_t *l = loc;
+ wchar_t buf[FILENAME_SIZE] = {0};
+ wchar_t *pEnd;
+
+ while (IsCharSpaceW(*l)) l = CharNextW(l);
+
+ if (!wcsstr(l, L":/") && !wcsstr(l, L":\\"))
+ {
+ StringCchPrintfW(buf, FILENAME_SIZE, L"http://%s", l);
+ l = buf;
+ beg = buf;
+ }
+
+ if (clearlist < 0)
+ {
+ int psize = WideCharToMultiByte(CP_ACP, 0, l, -1, 0, 0, NULL, NULL);
+ char* p = (char*)GlobalAlloc(GPTR, psize);
+ WideCharToMultiByte(CP_ACP, 0, l, -1, p, psize, NULL, NULL);
+
+ //trim any trailing spaces
+ //l = p + lstrlen(p) - 1;
+ if (IsCharSpaceW(*l))
+ {
+ while (IsCharSpaceW(*l))
+ l = CharPrevW(beg, l);
+ *CharNextW(l) = 0;
+ }
+
+ q = 0;
+ return (LRESULT)p;
+ }
+
+ pEnd = GetLastCharacterW(l);
+ if (IsCharSpaceW(*pEnd))
+ {
+ while (IsCharSpaceW(*pEnd))
+ pEnd = CharPrevW(l, pEnd);
+ *CharNextW(pEnd) = 0;
+ }
+
+ /* benski> CUT because 'idir' doesn't seem to be used
+ int idir=0;
+ HANDLE h;
+ WIN32_FIND_DATA d;
+ h = FindFirstFile(l,&d);
+ if (h!=INVALID_HANDLE_VALUE)
+ {
+ FindClose(h);
+ if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ idir=1;
+ }
+ }
+ */
+ if (clearlist)
+ PlayList_delete();
+ PlayList_appendthing(l, 0, 0);
+ if (clearlist)
+ BeginPlayback();
+ }
+ q = 0;
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/Options.cpp b/Src/Winamp/Options.cpp
new file mode 100644
index 00000000..728aea3f
--- /dev/null
+++ b/Src/Winamp/Options.cpp
@@ -0,0 +1,611 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "resource.h"
+#include <malloc.h>
+#include "gen.h"
+#include "Options.h"
+#include <vector>
+#include "./api.h"
+
+//#define DO_COLORS
+std::vector<prefsDlgRec*> g_piprefsdlgs;
+HWND prefs_hwnd = NULL;
+intptr_t prefs_last_page;
+RECT prefs_rect = {-1, -1}, alt3_rect = {-1, -1}, ctrle_rect = {-1, -1},
+ about_rect = {-1, -1}, loc_rect = {-1, -1}, time_rect = {-1, -1},
+ load_rect = {-1, -1}, editinfo_rect = {-1, -1};
+
+static intptr_t pluginids;
+static HANDLE lp_v = NULL;
+static HANDLE _additem(HWND hwnd, HANDLE h, wchar_t *str, int children, intptr_t data)
+{
+ HANDLE h2;
+ TV_INSERTSTRUCTW is = {(HTREEITEM)h, TVI_LAST, {TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN, 0, 0, 0, str, (int)wcslen(str), 0, 0, children ? 1 : 0, data}};
+ h2 = (HTREEITEM)SendMessageW(hwnd, TVM_INSERTITEMW, 0, (LPARAM)&is);
+ if (prefs_last_page == data) lp_v = h2;
+ return h2;
+}
+
+static HANDLE _additem(HWND hwnd, HANDLE h, char *str, int children, intptr_t data)
+{
+ HANDLE h2;
+ TV_INSERTSTRUCTA is = {(HTREEITEM)h, TVI_LAST, {TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN, 0, 0, 0, str, (int)strlen(str), 0, 0, children ? 1 : 0, data}};
+ h2 = TreeView_InsertItem(hwnd, &is);
+ if (prefs_last_page == data) lp_v = h2;
+ return h2;
+}
+
+void do_help(HWND hwnd, UINT id, HWND hTooltipWnd)
+{
+ RECT r;
+ POINT p;
+ GetWindowRect(GetDlgItem(hwnd, id), &r);
+ GetCursorPos(&p);
+ if (p.x >= r.left && p.x < r.right && p.y >= r.top && p.y < r.bottom)
+ {}
+ else
+ {
+ r.left += r.right;
+ r.left /= 2;
+ r.top += r.bottom;
+ r.top /= 2;
+ SetCursorPos(r.left, r.top);
+ }
+ SendMessageW(hTooltipWnd, TTM_SETDELAYTIME, TTDT_INITIAL, 0);
+ SendMessageW(hTooltipWnd, TTM_SETDELAYTIME, TTDT_RESHOW, 0);
+}
+
+//////////////////////////
+// TAB PROCEDURES
+//////////////////////////
+
+int g_taskbar_dirty;
+
+// vis 2tab procedure
+static HANDLE insertRootDialog(HWND hwnd, intptr_t which, HANDLE h, intptr_t* pids)
+{
+ for ( prefsDlgRec *p : g_piprefsdlgs )
+ {
+ if (which == p->where)
+ {
+ HANDLE h2;
+ if (p->next == PREFS_UNICODE) // unicode
+ h2 = _additem(hwnd, h, (wchar_t*)(p->name), 1, p->_id = (p->where < 0 ? (- 1 * p->where) : p->where));
+ else // local code page
+ h2 = _additem(hwnd, h, p->name, 1, p->_id = (p->where < 0 ? (-1 * p->where) : p->where));
+
+ return h2;
+ }
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
+// vis 2tab procedure
+static bool insertDialogs(HWND hwnd, intptr_t which, HANDLE h, intptr_t *pids)
+{
+ bool ret = false;
+ for ( prefsDlgRec *p : g_piprefsdlgs )
+ {
+ if (which == p->where)
+ {
+ size_t j;
+ for (j = 0; j != g_piprefsdlgs.size(); j++)
+ {
+ if (g_piprefsdlgs[j]->where == (intptr_t)p)
+ {
+ break;
+ }
+ }
+ if ((intptr_t)p == prefs_last_page)
+ prefs_last_page = *pids;
+
+ HANDLE h2;
+ if (p->next == PREFS_UNICODE) // unicode
+ h2 = _additem(hwnd, h, (wchar_t *)(p->name), j != g_piprefsdlgs.size(), p->_id = (*pids)++);
+ else // local code page
+ h2 = _additem(hwnd, h, p->name, j!=g_piprefsdlgs.size(), p->_id = (*pids)++);
+
+ ret = true;
+ if (j != g_piprefsdlgs.size() && insertDialogs(hwnd, (intptr_t)p, h2, pids))
+ SendMessageW(hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM)h2);
+ }
+ }
+ return ret;
+}
+
+static HTREEITEM dofindByParam(intptr_t param, HWND treeview, HTREEITEM Tree)
+{
+ HTREEITEM f=TreeView_GetChild(treeview,Tree);
+ do
+ {
+ TVITEM tvi={TVIF_HANDLE|TVIF_PARAM|TVIF_CHILDREN,f,};
+ TreeView_GetItem(treeview,&tvi);
+ if (tvi.lParam==param) return tvi.hItem;
+ if (tvi.cChildren)
+ {
+ HTREEITEM s=dofindByParam(param,treeview,tvi.hItem);
+ if (s) return s;
+ }
+ } while (NULL != (f=TreeView_GetNextItem(treeview,f,TVGN_NEXT)));
+ return NULL;
+}
+
+void prefs_liveDlgAdd(prefsDlgRec * p)
+{
+ if(!IsWindow(prefs_hwnd)) return;
+ HWND htree = GetDlgItem(prefs_hwnd, IDC_TREE1);
+ HTREEITEM parent = NULL;
+ switch(p->where)
+ {
+ case -1: parent = TVI_ROOT; break;
+ case 0: parent = dofindByParam(0,htree,NULL); break;
+ case 1: parent = dofindByParam(30,htree,NULL); break;
+ case 2: parent = dofindByParam(40,htree,NULL); break;
+ case 6: parent = dofindByParam(6, htree, NULL); break;
+ default:
+ {
+ if (p->where < 0)
+ {
+ parent = TVI_ROOT;
+ break;
+ }
+ else if (p->where < 65536)
+ return;
+
+ prefsDlgRec * pa = (prefsDlgRec *)p->where;
+ parent = dofindByParam(pa->_id,htree,NULL);
+ if(!parent) return;
+ TVITEM t = {TVIF_CHILDREN,parent,0};
+ TreeView_GetItem(htree,&t);
+ if(!t.cChildren)
+ {
+ t.cChildren = 1;
+ TreeView_SetItem(htree,&t);
+ }
+ }
+ }
+ if (!parent) return;
+ if (p->next == PREFS_UNICODE) // unicode
+ _additem(htree,parent,(wchar_t *)(p->name), 0, p->_id = pluginids++);
+ else // local code page
+ _additem(htree,parent,p->name, 0, p->_id = pluginids++);
+
+ SendMessageW(htree, TVM_EXPAND, TVE_EXPAND, (LPARAM)parent);
+}
+
+void prefs_liveDlgRemove(prefsDlgRec * p)
+{
+ if(!IsWindow(prefs_hwnd)) return;
+ HWND htree = GetDlgItem(prefs_hwnd, IDC_TREE1);
+ HTREEITEM t = dofindByParam(p->_id,htree,NULL);
+ if(!t) return;
+
+ HTREEITEM tp = TreeView_GetParent(htree, t);
+ TreeView_DeleteItem(htree,t);
+ if (!TreeView_GetChild(htree, tp))
+ {
+ // clears the [+]/[-] box if no children
+ TVITEM t2 = {TVIF_CHILDREN,tp,0};
+ TreeView_GetItem(htree,&t2);
+ t2.cChildren = 0;
+ TreeView_SetItem(htree,&t2);
+ }
+}
+
+void prefs_liveDlgUpdate(prefsDlgRec * p)
+{
+ if(!IsWindow(prefs_hwnd)) return;
+ HWND htree = GetDlgItem(prefs_hwnd, IDC_TREE1);
+ HTREEITEM t = dofindByParam(p->_id,htree,NULL);
+ if(!t) return;
+
+ if (p->next == PREFS_UNICODE)
+ {
+ TVITEMW tvi = {TVIF_TEXT,t,0};
+ tvi.pszText = (wchar_t *)p->name;
+ tvi.cchTextMax = (int)wcslen(tvi.pszText);
+ SendMessageW(htree,TVM_SETITEMW,0,(LPARAM)&tvi);
+ }
+ else
+ {
+ TVITEMA tvi = {TVIF_TEXT,t,0};
+ tvi.pszText = (char *)p->name;
+ tvi.cchTextMax = (int)strlen(tvi.pszText);
+ SendMessageW(htree,TVM_SETITEMA,0,(LPARAM)&tvi);
+ }
+}
+
+HWND _dosetsel(HWND hwndDlg, HWND subwnd, int* last_page, multiPage* pages, int numpages)
+{
+ HWND tabwnd=GetDlgItem(hwndDlg,IDC_TAB1);
+ int sel=TabCtrl_GetCurSel(tabwnd);
+
+ if (sel >= 0 && (sel != *last_page || !subwnd))
+ {
+ *last_page = sel;
+ if (IsWindow(subwnd)) DestroyWindow(subwnd);
+ subwnd=0;
+
+ if (sel < numpages)
+ {
+ int t=0;
+ WNDPROC p;
+
+ t = pages[sel].id;
+ p = pages[sel].proc;
+
+ if (t) subwnd = LPCreateDialogW(t, hwndDlg, p);
+ }
+
+ if (IsWindow(subwnd))
+ {
+ RECT r;
+ GetClientRect(tabwnd,&r);
+ TabCtrl_AdjustRect(tabwnd,FALSE,&r);
+ SetWindowPos(subwnd,HWND_TOP,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOACTIVATE);
+ ShowWindow(subwnd,SW_SHOWNA);
+ }
+
+ if (IsWinXPTheme())
+ {
+ DoWinXPStyle(tabwnd);
+ DoWinXPStyle(subwnd);
+ }
+ }
+ return subwnd;
+}
+
+//////////////////////////
+// OUTER PROCEDURE
+//////////////////////////
+static LRESULT CALLBACK OuterProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND cur_wnd;
+ static HWND prevActiveWindow = NULL;
+ switch (uMsg)
+ {
+#ifdef DO_COLORS
+ case WM_CTLCOLORBTN:
+ if (lParam == (LPARAM)GetDlgItem(hwndDlg, IDOK))
+ {
+ // SetTextColor(wParam,RGB(0,199,0));
+ return (LRESULT)GetStockObject(WHITE_BRUSH);
+ }
+ break;
+ case WM_CTLCOLOREDIT:
+ if (lParam == (LPARAM)GetDlgItem(hwndDlg, IDC_TREE1))
+ {
+ return (LRESULT)GetStockObject(BLACK_BRUSH);
+ }
+ break;
+ case WM_CTLCOLORDLG:
+ return (LRESULT)GetStockObject(DKGRAY_BRUSH);
+#endif
+ case WM_USER + 32:
+ if (cur_wnd) return SendMessageW(cur_wnd, uMsg, wParam, lParam);
+ return 0;
+
+ case WM_USER + 33:
+ // use this to check a specified control on the dialog page (5.59+)
+ CheckDlgButton(cur_wnd, wParam, (lParam ? 1: 0));
+ return 0;
+
+ case WM_INITDIALOG:
+ {
+ // this is a bit of a hack to help gen_nopro.dll
+ if (!IsWindow((HWND)wParam)) prefs_last_page = 35;
+
+ if (g_safeMode) SetWindowTextW(hwndDlg, getStringW(IDS_PREFS_SAFE_MODE, NULL, 0));
+ prefs_hwnd = hwndDlg;
+ pluginids = 60;
+ HWND hwnd = GetDlgItem(hwndDlg, IDC_TREE1);
+ HANDLE h;
+
+ lp_v = NULL;
+
+ h = _additem(hwnd, TVI_ROOT, getStringW(IDS_PREFS_SETUP, NULL, 0), 1, 0);
+ _additem(hwnd, h, getStringW(IDS_PREFS_FT, NULL, 0), 0, 1);
+ _additem(hwnd, h, getStringW(IDS_PREFS_SHUFFLE, NULL, 0), 0, 23);
+ _additem(hwnd, h, getStringW(IDS_PREFS_TITLES, NULL, 0), 0, 21);
+ _additem(hwnd, h, getStringW(IDS_PREFS_PLAYBACK, NULL, 0), 0, 42);
+ //_additem(hwnd, h, getStringW(IDS_STATIONINFOCAPTION, NULL, 0), 0, 41);
+ //insertDialogs(hwnd,4,h,&pluginids);
+ //SendMessageW(hwnd,TVM_EXPAND,TVE_EXPAND,(long)h);
+ //h=_additem(hwnd,TVI_ROOT,getStringW(IDS_PREFS_OPTIONS,NULL,0),1,20);
+ if (g_has_video_plugin || (g_no_video_loaded == 1)) _additem(hwnd, h, getStringW(IDS_PREFS_VIDEO, NULL, 0), 0, 24);
+
+ _additem(hwnd, h, getStringW(IDS_LOCALIZATION, NULL, 0), 0, 25);
+
+ insertDialogs(hwnd, 0, h, &pluginids);
+
+ SendMessageW(hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM)h);
+
+ //media library
+ h = insertRootDialog(hwnd, -6, TVI_ROOT, &pluginids);
+ insertDialogs(hwnd, 6, h, &pluginids);
+ SendMessageW(hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM)h);
+
+ insertDialogs(hwnd, -1, TVI_ROOT, &pluginids); // test
+
+ h = _additem(hwnd, TVI_ROOT, getStringW(IDS_PREFS_SKIN, NULL, 0), 1, 40);
+ _additem(hwnd, h, getStringW(IDS_PREFS_CLASSICSKIN, NULL, 0), 0, 22);
+
+ insertDialogs(hwnd, 2, h, &pluginids);
+ SendMessageW(hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM)h);
+
+ h = _additem(hwnd, TVI_ROOT, getStringW(IDS_PREFS_PLUG, NULL, 0), 1, 30);
+ _additem(hwnd, h, getStringW(IDS_PREFS_PLUG_IN, NULL, 0), 0, 31);
+ _additem(hwnd, h, getStringW(IDS_PREFS_PLUG_OUT, NULL, 0), 0, 32);
+ if (!g_safeMode)
+ {
+ _additem(hwnd, h, getStringW(IDS_PREFS_PLUG_VIS, NULL, 0), 0, 33);
+ _additem(hwnd, h, getStringW(IDS_PREFS_PLUG_DSP, NULL, 0), 0, 34);
+ }
+ _additem(hwnd, h, getStringW(IDS_PREFS_PLUG_GEN, NULL, 0), 0, 35);
+ insertDialogs(hwnd, 1, h, &pluginids);
+
+ insertDialogs(hwnd, -2, TVI_ROOT, &pluginids); // used to force gen_crasher to the bottom (below plug-ins)
+
+ SendMessageW(hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM)h);
+ //h=_additem(hwnd,TVI_ROOT,getStringW(IDS_PREFS_BOOK,NULL,0),1,50);
+ //insertDialogs(hwnd,3,h,&pluginids);
+ //SendMessageW(hwnd,TVM_EXPAND,TVE_EXPAND,(long)h);
+
+ SendMessageW(hwnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM)lp_v);
+ PostMessageW(hwnd, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)lp_v);
+ DirectMouseWheel_EnableConvertToMouseWheel(hwnd, TRUE);
+#ifdef DO_COLORS
+ SendMessageW(hwnd, TVM_SETBKCOLOR, 0, RGB(0, 0, 0));
+ SendMessageW(hwnd, TVM_SETTEXTCOLOR, 0, RGB(0, 220, 0));
+#endif
+ }
+ if (NULL != WASABI_API_APP)
+ WASABI_API_APP->app_registerGlobalWindow(hwndDlg);
+
+ prevActiveWindow = GetActiveWindow();
+ if (NULL != prevActiveWindow &&
+ hMainWindow != GetAncestor(prevActiveWindow, GA_ROOTOWNER))
+ {
+ prevActiveWindow = NULL;
+ }
+
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ }
+ break;
+ case WM_NOTIFY:
+ {
+ NM_TREEVIEW *p;
+ p = (NM_TREEVIEW *)lParam;
+
+ if (p->hdr.code == TVN_SELCHANGEDW)
+ {
+ HANDLE hTreeItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE1));
+ TV_ITEM i = {TVIF_HANDLE, (HTREEITEM)hTreeItem, 0, 0, 0, 0, 0};
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE1), &i);
+ if (i.lParam >= 1024)
+ {}
+ else if (i.lParam >= 256)
+ {}
+ else
+ {
+ int id = -1;
+ DLGPROC proc = NULL;
+ HINSTANCE hinst = NULL;
+ prefs_last_page = i.lParam;
+ LPARAM param = 0;
+ switch (i.lParam)
+ {
+ case 0: id = IDD_NEWSETUP; proc = SetupProc; break; // general
+ case 1: id = (!IsWin8() ? IDD_NEWFTYPES : IDD_WIN8_FTYPES); proc = FtypeProc; break; // filetypes
+// case 2: id=IDD_NEWAGENT; proc=AgentProc; break;
+ case 21: id = IDD_NEWTITLE; proc = TitleProc; break;
+ case 22: id = IDD_PREFS_CLASSICSKIN; proc = classicSkinProc; break;
+ case 23: id = IDD_NEWSHUFFLEOPTS; proc = PlaybackOptionsProc; break; // playlist
+ case 24: id = IDD_NEWVIDEOOPTS; proc = VideoProc; break;
+ case 25: id = IDD_NEWLANG; proc = LangProc; break;
+ case 30: id = IDD_NEWPLUG; proc = PlugProc; break;
+ case 31: id = IDD_NEWINPUT; proc = InputProc; break;
+ case 32: id = IDD_NEWOUTPUT; proc = OutputProc; break;
+ case 33: id = IDD_NEWVIS; proc = VisProc; break;
+ case 34: id = IDD_NEWDSP; proc = DspProc; break;
+ case 35: id = IDD_NEWGEN; proc = GenProc; break;
+ case 40: id = IDD_NEWSKIN; proc = SkinProc; break;
+// case 41: id = IDD_STATIONINFO; proc = StationInfoProc; break;
+ case 42: id = IDD_PREFS_CLASSICSKIN; proc = PlaybackProc; break;
+// case 50: id=IDD_NEWBOOKMARKS; proc = BookProc; break;
+ default:
+ {
+ size_t m;
+ for (m = 0; m != g_piprefsdlgs.size(); m++)
+ {
+ if (g_piprefsdlgs[m]->_id == i.lParam)
+ break;
+ }
+
+ if (m != g_piprefsdlgs.size())
+ {
+ id = g_piprefsdlgs[m]->dlgID;
+ hinst = g_piprefsdlgs[m]->hInst;
+ proc = (DLGPROC)g_piprefsdlgs[m]->proc;
+ param = (LPARAM)g_piprefsdlgs[m];
+ }
+ }
+ }
+
+ if (IsWindow(cur_wnd))
+ {
+ DestroyWindow(cur_wnd);
+ cur_wnd = 0;
+ }
+
+ if (id != -1)
+ {
+ RECT r;
+ if (!hinst) cur_wnd = LPCreateDialogW(id, hwndDlg, (WNDPROC)proc);
+ else cur_wnd = CreateDialogParamW(hinst, MAKEINTRESOURCEW(id), hwndDlg, proc, param);
+
+ extern int prev_wlz_ex_state;
+ if (!IsWindow(cur_wnd) && prev_wlz_ex_state)
+ {
+ // will attempt to find a in-dll version of the resource
+ // if the version from the language pack was not loaded
+ wchar_t filename[MAX_PATH] = {0};
+ if (GetModuleFileNameW(hinst, filename, MAX_PATH))
+ {
+ PathRemoveExtensionW(filename);
+ PathAddExtensionW(filename, L".dll");
+ wchar_t *f = scanstr_backW(filename, L"\\/", filename);
+ if (f && *f)
+ {
+ if (*f == '\\' || *f == '/') f = CharNextW(f);
+ }
+ if (f && *f)
+ {
+ HINSTANCE fallback = GetModuleHandleW(f);
+ if (fallback != GetModuleHandle(NULL))
+ {
+ cur_wnd = CreateDialogParamW(fallback, MAKEINTRESOURCEW(id), hwndDlg, proc, param);
+ }
+ }
+ }
+ }
+
+ // if we get here then show a non-localised fallback page
+ if (!IsWindow(cur_wnd))
+ {
+ cur_wnd = CreateDialogW(hMainInstance, MAKEINTRESOURCEW(IDD_PREFS_FAIL), hwndDlg, 0);
+ }
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_RECT), &r);
+ ScreenToClient(hwndDlg, (LPPOINT)&r);
+ SetWindowPos(cur_wnd, 0, r.left, r.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
+ ShowWindow(cur_wnd, SW_SHOWNA);
+ }
+ }
+ }
+ }
+ break;
+ case WM_DESTROY:
+ if (NULL != WASABI_API_APP)
+ WASABI_API_APP->app_unregisterGlobalWindow(hwndDlg);
+
+ {
+ HWND treeWindow;
+ treeWindow = GetDlgItem(hwndDlg, IDC_TREE1);
+ if (NULL != treeWindow)
+ DirectMouseWheel_EnableConvertToMouseWheel(treeWindow, FALSE);
+ }
+
+ GetWindowRect(hwndDlg, &prefs_rect);
+ if (cur_wnd) DestroyWindow(cur_wnd);
+ cur_wnd = 0;
+ //prefs_hwnd = NULL;
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_PREFS, MF_UNCHECKED);
+ PostMessageW(hMainWindow, WM_WA_IPC, 0, IPC_WRITECONFIG);
+
+ if (NULL != prevActiveWindow)
+ {
+ if (IsWindowVisible(prevActiveWindow) &&
+ IsWindowEnabled(prevActiveWindow))
+ {
+ SetActiveWindow(prevActiveWindow);
+ }
+ prevActiveWindow = NULL;
+ }
+
+ break;
+ case WM_ACTIVATE:
+ if (NULL != WASABI_API_APP)
+ {
+ if (WA_INACTIVE == LOWORD(wParam))
+ WASABI_API_APP->ActiveDialog_Unregister(hwndDlg);
+ else
+ WASABI_API_APP->ActiveDialog_Register(hwndDlg);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+HTREEITEM FindParameter(HWND treeHWND, HTREEITEM node, int findParameter)
+{
+ if (!node)
+ return 0;
+
+ /* first, see if the passed node matches */
+ TVITEM pv;
+ pv.mask = TVIF_HANDLE | TVIF_PARAM;
+ pv.hItem = node;
+ if (TreeView_GetItem(treeHWND, &pv)
+ && pv.lParam == findParameter)
+ return node;
+
+ /* now do breadth-first search */
+ HTREEITEM found = NULL;
+
+ /* search next sibling */
+ found = FindParameter(treeHWND, TreeView_GetNextSibling(treeHWND, node), findParameter);
+
+ /* search the first child
+ * the child's sibling search should help the rest of this node's children ... */
+ if (!found)
+ found = FindParameter(treeHWND, TreeView_GetChild(treeHWND, node), findParameter);
+
+ return found;
+}
+
+void prefs_dialog(int modal)
+{
+ if (IsWindow(prefs_hwnd) && modal)
+ {
+ HTREEITEM hti;
+ HTREEITEM lp_v = NULL;
+ HWND hwndTV = GetDlgItem(prefs_hwnd, IDC_TREE1);
+
+ //CT> update prefs_last_page to the correct value if its a plugin pref
+ for ( prefsDlgRec *p : g_piprefsdlgs )
+ {
+ if ( (intptr_t)p == prefs_last_page )
+ {
+ prefs_last_page = p->_id;
+ break;
+ }
+ }
+
+ //hti=TreeView_GetFirstVisible(hwndTV);
+ hti = TreeView_GetRoot(hwndTV);
+ if (hti)
+ lp_v = FindParameter(hwndTV, hti, prefs_last_page);
+
+ if (lp_v) SendMessageW(hwndTV, TVM_SELECTITEM, TVGN_CARET, (LPARAM)lp_v);
+ SetForegroundWindow(prefs_hwnd);
+ return ;
+ }
+ if (IsWindow(prefs_hwnd))
+ {
+ SendMessageW(prefs_hwnd, WM_COMMAND, IDOK, 0);
+ return ;
+ }
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_PREFS, MF_CHECKED);
+ prefs_hwnd = (HWND)LPCreateDialogW(IDD_NEWPREFS, DIALOG_PARENT(hMainWindow), OuterProc);
+ // show prefs window and restore last position as applicable
+ POINT pt = {prefs_rect.left, prefs_rect.top};
+ if (!windowOffScreen(prefs_hwnd, pt))
+ SetWindowPos(prefs_hwnd, HWND_TOP, prefs_rect.left, prefs_rect.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
+ else
+ ShowWindow(prefs_hwnd, SW_SHOW);
+} \ No newline at end of file
diff --git a/Src/Winamp/Options.h b/Src/Winamp/Options.h
new file mode 100644
index 00000000..be99c676
--- /dev/null
+++ b/Src/Winamp/Options.h
@@ -0,0 +1,105 @@
+#ifndef NULLSOFT_OPTIONSH
+#define NULLSOFT_OPTIONSH
+#pragma once
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <shlobj.h>
+
+typedef struct { int id, id2; } hi;
+
+typedef struct { UINT id; WNDPROC proc; } multiPage;
+HWND _dosetsel(HWND hwndDlg, HWND subwnd, int* last_page, multiPage* pages, int numpages);
+
+INT_PTR CALLBACK PlaybackProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+//INT_PTR CALLBACK StationInfoProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DspProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK GenProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK VisProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK VideoProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK PlaybackOptionsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK TitleProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK SetupProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK FtypeProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK SkinProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK classicSkinProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK OutputProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK InputProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK PlugProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK LangProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+
+void do_help(HWND hwnd, UINT id, HWND hTooltipWnd);
+#ifdef DO_COLORS
+#define C_BLAH \
+ if (uMsg == WM_CTLCOLORDLG) return GetStockObject(DKGRAY_BRUSH); \
+ if (uMsg == WM_CTLCOLORSTATIC) { \
+ SetTextColor(wParam,RGB(220,220,220)); SetBkColor(wParam,RGB(64,64,64)); \
+ return GetStockObject(DKGRAY_BRUSH);} \
+ if (uMsg == WM_CTLCOLORLISTBOX) { \
+ SetTextColor(wParam,RGB(0,220,0)); SetBkColor(wParam,RGB(0,0,0)); \
+ return GetStockObject(BLACK_BRUSH);} \
+ if (uMsg == WM_CTLCOLOREDIT) { \
+ SetTextColor(wParam,RGB(0,220,0)); SetBkColor(wParam,RGB(0,0,0)); \
+ return GetStockObject(BLACK_BRUSH);}
+#else
+#define C_BLAH
+#endif
+
+#define DO_HELP() \
+ static HWND hTooltipWnd; \
+ C_BLAH \
+ if (uMsg == WM_HELP) { \
+ HELPINFO *hi=(HELPINFO *)(lParam); \
+ if (hi->iContextType == HELPINFO_WINDOW) { do_help(hwndDlg,hi->iCtrlId,hTooltipWnd);} \
+ return TRUE; \
+ } \
+ if (uMsg == WM_NOTIFY) { LPNMHDR t=(LPNMHDR)lParam; if (t->code == TTN_POP) { SendMessageW(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,1000); SendMessageW(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,1000); } } \
+ if (uMsg == WM_DESTROY && IsWindow(hTooltipWnd)) { DestroyWindow(hTooltipWnd); hTooltipWnd=NULL; } \
+ if (uMsg == WM_INITDIALOG) { \
+ int x; \
+ hTooltipWnd = CreateWindowW(TOOLTIPS_CLASSW,(LPCWSTR)NULL,TTS_ALWAYSTIP, \
+ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hwndDlg,NULL,GetModuleHandle(NULL),NULL); \
+ SendMessageW(hTooltipWnd,TTM_SETMAXTIPWIDTH,0,587); \
+ SendMessageW(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,1000); \
+ SendMessageW(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,1000); \
+ for (x = 0; x < sizeof(helpinfo)/sizeof(helpinfo[0]); x ++) { \
+ TOOLINFOW ti; ti.cbSize = sizeof(ti); ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND; \
+ ti.uId=(UINT_PTR)GetDlgItem(hwndDlg,helpinfo[x].id); ti.hwnd=hwndDlg; ti.lpszText=getStringW(helpinfo[x].id2,NULL,0); \
+ SendMessageW(hTooltipWnd,TTM_ADDTOOLW,0,(LPARAM) &ti); \
+ } \
+ }
+
+#define ListView_InsertColumnW(hwnd, iCol, pcol) \
+ (int)SNDMSG((hwnd), LVM_INSERTCOLUMNW, (WPARAM)(int)(iCol), (LPARAM)(const LV_COLUMNW *)(pcol))
+
+#define ListView_InsertItemW(hwnd, pitem) \
+ (int)SNDMSG((hwnd), LVM_INSERTITEMW, 0, (LPARAM)(const LV_ITEMW *)(pitem))
+
+#define ListView_SetItemTextW(hwndLV, i, iSubItem_, pszText_) \
+{ LV_ITEMW _macro_lvi;\
+ _macro_lvi.iSubItem = (iSubItem_);\
+ _macro_lvi.pszText = (pszText_);\
+ SNDMSG((hwndLV), LVM_SETITEMTEXTW, (WPARAM)(i), (LPARAM)(LV_ITEMW *)&_macro_lvi);\
+}
+
+#define ListView_SetItemW(hwnd, pitem) \
+ (BOOL)SNDMSG((hwnd), LVM_SETITEMW, 0, (LPARAM)(LV_ITEMW *)(pitem))
+
+#define ListView_GetItemW(hwnd, pitem) \
+ (BOOL)SNDMSG((hwnd), LVM_GETITEMW, 0, (LPARAM)(LV_ITEMW *)(pitem))
+
+#define ListView_GetItemTextW(hwndLV, i, iSubItem_, pszText_, cchTextMax_) \
+{ LV_ITEMW _macro_lvi;\
+ _macro_lvi.iSubItem = (iSubItem_);\
+ _macro_lvi.cchTextMax = (cchTextMax_);\
+ _macro_lvi.pszText = (pszText_);\
+ SNDMSG((hwndLV), LVM_GETITEMTEXTW, (WPARAM)(i), (LPARAM)(LV_ITEMW *)&_macro_lvi);\
+}
+
+
+#endif
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Out.cpp b/Src/Winamp/Out.cpp
new file mode 100644
index 00000000..53ccd659
--- /dev/null
+++ b/Src/Winamp/Out.cpp
@@ -0,0 +1,119 @@
+#include "Main.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+
+extern LARGE_INTEGER freq;
+Out_Module* out_modules[32] = { 0 };
+Out_Module* out_mod = 0;
+
+typedef struct _PLUGINORDER
+{
+ LPCWSTR name;
+ bool found;
+} PLUGINORDER;
+
+static PLUGINORDER preload[] =
+{
+ { L"out_ds.dll", false },
+ { L"out_wave.dll", false },
+ { L"out_disk.dll", false }
+};
+
+int LoadOutputPlugin(const wchar_t* plugin_filename, int index)
+{
+ wchar_t file[MAX_PATH] = { 0 };
+ PathCombineW(file, PLUGINDIR, plugin_filename);
+
+ HINSTANCE hLib = LoadLibraryW(file);
+ if ( hLib == NULL )
+ return index;
+
+
+ Out_Module* (*pr)();
+ pr = (Out_Module * (__cdecl*)(void)) GetProcAddress(hLib, "winampGetOutModule");
+ if ( !pr )
+ return index;
+
+
+ Out_Module* mod = pr();
+ if ( mod && (mod->version == OUT_VER || mod->version == OUT_VER_U) )
+ {
+ AutoChar narrowFn(plugin_filename);
+ size_t fileNameSize = lstrlenA(narrowFn);
+
+ if ( g_safeMode )
+ {
+ if ( !(mod->id == 1471482036 || mod->id == 426119909 || mod->id == 203968848) )
+ {
+ FreeModule(hLib);
+ return index;
+ }
+ }
+
+ mod->hDllInstance = hLib;
+ mod->hMainWindow = hMainWindow;
+ mod->id = (intptr_t)GlobalAlloc(GPTR, fileNameSize + 1);
+
+ StringCchCopyA((char*)mod->id, fileNameSize + 1, narrowFn);
+
+ mod->Init();
+ out_modules[index] = mod;
+
+ return index + 1;
+ }
+
+
+ return index;
+}
+
+void out_init()
+{
+ int index = 0, i = 0, count = sizeof(preload) / sizeof(PLUGINORDER);
+ for ( ; i < count; i++ ) index = LoadOutputPlugin(preload[i].name, index);
+
+ WIN32_FIND_DATAW d = { 0 };
+ wchar_t dirstr[MAX_PATH] = { 0 };
+ PathCombineW(dirstr, PLUGINDIR, L"OUT_*.DLL");
+ HANDLE h = FindFirstFileW(dirstr, &d);
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ for ( i = 0; i < count && (preload[i].found || lstrcmpiW(preload[i].name, d.cFileName)); i++ );
+ if ( i == count ) index = LoadOutputPlugin(d.cFileName, index);
+ else preload[i].found = true;
+ } while ( FindNextFileW(h, &d) && index < 31 );
+ FindClose(h);
+ }
+}
+
+void out_setwnd(void)
+{
+ for ( int x = 0; out_modules[x]; x++ )
+ {
+ out_modules[x]->hMainWindow = hMainWindow;
+ }
+}
+
+void out_changed(HINSTANCE hLib, int enabled)
+{
+ typedef void(__cdecl* OutModeChange)(int);
+ OutModeChange modeChange = (OutModeChange)GetProcAddress(hLib, "winampGetOutModeChange");
+ if ( modeChange )
+ {
+ modeChange(enabled);
+ }
+}
+
+void out_deinit()
+{
+ for ( int x = 0; out_modules[x]; x++ )
+ {
+ //HINSTANCE hLib = out_modules[x]->hDllInstance;
+ out_modules[x]->Quit();
+ GlobalFree((HGLOBAL)out_modules[x]->id);
+ out_modules[x]->id = 0;
+ //FreeLibrary(hLib); // benski> we're just going to let it leak because it might be subclassing
+ out_modules[x] = 0;
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/OutputPluginAudioStream.cpp b/Src/Winamp/OutputPluginAudioStream.cpp
new file mode 100644
index 00000000..f724aad1
--- /dev/null
+++ b/Src/Winamp/OutputPluginAudioStream.cpp
@@ -0,0 +1,270 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "OutputPluginAudioStream.h"
+#include "out.h"
+#include "api.h"
+#include "WinampAttributes.h"
+
+int m_converting = 0;
+static volatile int streamsInUse = 0;
+static void * volatile streamBuffer = 0;
+static volatile size_t streamCanWrite = 0;
+static volatile HANDLE streamWait = 0;
+static volatile HANDLE streamGo = 0;
+static volatile HANDLE streamKill = 0;
+
+static volatile bool streamPlaying = false;
+static volatile AudioParameters *streamParameters = 0;
+static In_Module * volatile streamIn = 0;
+static volatile int opens = 0;
+
+void ConvertEOF()
+{
+ streamPlaying = false;
+ //if (--opens==0)
+ SetEvent(streamWait);
+}
+
+static int StreamOpen(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms)
+{
+ streamParameters->bitsPerSample = bitspersamp;
+ streamParameters->channels = numchannels;
+ streamParameters->sampleRate = samplerate;
+ streamParameters->sizeBytes = (size_t) - 1;
+
+ // we will try to use GetFileInfo to get a length
+ int lengthMS;
+ InW_GetFileInfo(streamIn, 0, 0, &lengthMS);
+ if (lengthMS > 0)
+ {
+ streamParameters->sizeBytes = MulDiv(lengthMS, numchannels * bitspersamp * samplerate, 8000);
+ }
+
+ streamPlaying = true;
+
+ return 0;
+}
+
+static void StreamClose()
+{
+ streamPlaying = false;
+ // SetEvent(streamWait);
+}
+
+static int StreamWrite(char *buf, int len)
+{
+
+again:
+ // null buffer means EOF
+ if (buf == NULL)
+ {
+ streamPlaying = false;
+ //SetEvent(streamWait);
+ return 0;
+ }
+
+ if (streamCanWrite == 0)
+ {
+ //Sleep(10); // input plugin isn't checking StreamCanWrite() properly, so we'll sleep for them
+ //return 1;
+ }
+
+ // copy into user-supplied buffer
+ int toCopy = min((int)streamCanWrite, len);
+ memcpy(streamBuffer, buf, toCopy);
+ streamCanWrite -= toCopy;
+ streamBuffer = ((char *)streamBuffer) + toCopy;
+
+ // the input plugin may have given us too much data, so we'll have to check that
+ // increment the user's stuff
+ len -= toCopy;
+ buf += toCopy;
+ if (len) // len>0 implies streamCanWrite == 0
+ {
+ ResetEvent(streamGo);
+ SetEvent(streamWait);
+
+ /* benski> this Sleep() code causes a major slowdown,
+ probably because of high thread priorities in some plugins
+ while (streamCanWrite == 0)
+ Sleep(100);
+ */
+ HANDLE events[2] = {streamKill, streamGo};
+ switch (WaitForMultipleObjects(2, events, FALSE, INFINITE))
+ {
+ case WAIT_OBJECT_0 + 1:
+ goto again;
+ default:
+ return 0;
+ }
+ }
+
+ // signal event to let ReadAudio() return, if the buffer is full
+ if (streamCanWrite == 0)
+ SetEvent(streamWait);
+ return 0;
+}
+
+
+static int StreamCanWrite()
+{
+ if (streamCanWrite)
+ return 65536;
+ else
+ return 0;
+}
+
+static int StreamIsPlaying()
+{
+ return 0;
+}
+
+static void StreamSet(int nothing)
+{}
+
+static int StreamGetOutputTime()
+{
+ return 0;
+}
+
+static int StreamGetWrittenTime()
+{
+ return 0;
+}
+
+static Out_Module streamOut =
+ {
+ OUT_VER,
+ "dummy output",
+ 14000,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ StreamOpen,
+ StreamClose,
+ StreamWrite,
+ StreamCanWrite,
+ StreamIsPlaying,
+ NULL, //pause
+ StreamSet, //setvolume
+ StreamSet, //setpan
+ StreamSet, //flush
+ StreamGetOutputTime,
+ StreamGetWrittenTime,
+ };
+
+OutputPluginAudioStream::OutputPluginAudioStream()
+{
+ oldBits=config_audio_bits;
+ oldSurround=config_audio_surround;
+ oldMono=config_audio_mono;
+ oldRG=config_replaygain;
+}
+
+bool OutputPluginAudioStream::Open(In_Module *in, const wchar_t *filename, AudioParameters *parameters)
+{
+ // set some globals, since winamp output plugins don't have user data/context pointers
+ opens++;
+ m_converting = 1;
+
+ // this will ask the input plugin to produce our output format (not a guarantee, though)
+ config_audio_bits = parameters->bitsPerSample;
+ config_audio_surround = (parameters->channels > 2);
+ config_audio_mono = (parameters->channels == 1);
+ config_replaygain=false;
+
+ streamWait = CreateEvent(NULL, FALSE, FALSE, NULL);
+ streamGo = CreateEvent(NULL, FALSE, FALSE, NULL);
+ streamKill = CreateEvent(NULL, TRUE, FALSE, NULL);
+ streamCanWrite = 0;
+ streamBuffer = 0;
+ streamPlaying = false;
+ streamParameters = parameters;
+ streamIn = in;
+
+ in->outMod = &streamOut;
+
+ int ret = InW_Play(in, filename);
+ if (ret)
+ {
+ parameters->errorCode = API_DECODEFILE_FAILURE;
+ opens--;
+ return false;
+ }
+
+ if (in->UsesOutputPlug&IN_MODULE_FLAG_USES_OUTPUT_PLUGIN)
+ {
+ int cnt = 5000;
+ while (!streamPlaying && cnt > 0)
+ {
+ MSG msg;
+ if (PeekMessage(&msg, NULL, 0, 0, FALSE))
+ WASABI_API_APP->app_messageLoopStep();
+ else
+ {
+ Sleep(1);
+ cnt--;
+ }
+ }
+ }
+ else
+ {
+ parameters->errorCode = API_DECODEFILE_NO_INTERFACE;
+ opens--;
+ return false;
+ }
+
+ if (!streamPlaying)
+ {
+ parameters->errorCode = API_DECODEFILE_FAILURE;
+ opens--;
+ return false;
+ }
+
+ return true;
+}
+
+size_t OutputPluginAudioStream::ReadAudio(void *buffer, size_t sizeBytes)
+{
+ streamBuffer = buffer;
+ streamCanWrite = sizeBytes;
+ SetEvent(streamGo);
+ HANDLE events[2] = {streamKill, streamWait};
+ switch (WaitForMultipleObjects(2, events, FALSE, INFINITE))
+ {
+ case WAIT_OBJECT_0 + 1: // streamWait, which gets triggered when buffer is full or output is done
+ return sizeBytes - streamCanWrite; // streamCanWrite will be >0 if there was a partial write, e.g. on EOF
+ default:
+ return 0; // no point
+ }
+
+ return sizeBytes - streamCanWrite;
+}
+
+OutputPluginAudioStream::~OutputPluginAudioStream()
+{
+ SetEvent(streamKill);
+ streamIn->Stop();
+ DeleteObject(streamWait);
+ DeleteObject(streamGo);
+ DeleteObject(streamKill);
+ streamWait = 0;
+ config_audio_bits = oldBits;
+ config_audio_surround = oldSurround;
+ config_audio_mono=oldMono;
+ config_replaygain=oldRG;
+}
+
+#define CBCLASS OutputPluginAudioStream
+START_DISPATCH;
+CB(IFC_AUDIOSTREAM_READAUDIO, ReadAudio)
+END_DISPATCH;
diff --git a/Src/Winamp/OutputPluginAudioStream.h b/Src/Winamp/OutputPluginAudioStream.h
new file mode 100644
index 00000000..6120e6dd
--- /dev/null
+++ b/Src/Winamp/OutputPluginAudioStream.h
@@ -0,0 +1,24 @@
+#ifndef NULLSOFT_WINAMP_OUTPUTPLUGINAUDIOSTREAM_H
+#define NULLSOFT_WINAMP_OUTPUTPLUGINAUDIOSTREAM_H
+
+#include "../Agave/DecodeFile/ifc_audiostream.h"
+#include "in2.h"
+#include "../Agave/DecodeFile/api_decodefile.h"
+#include "CommonReader.h"
+
+class OutputPluginAudioStream : public CommonReader
+{
+public:
+ OutputPluginAudioStream();
+ ~OutputPluginAudioStream();
+ bool Open(In_Module *in, const wchar_t *filename, AudioParameters *parameters);
+ size_t ReadAudio(void *buffer, size_t sizeBytes);
+
+protected:
+ RECVS_DISPATCH;
+
+ size_t oldBits;
+ bool oldSurround, oldMono, oldRG;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/PaletteManager.cpp b/Src/Winamp/PaletteManager.cpp
new file mode 100644
index 00000000..451c14c0
--- /dev/null
+++ b/Src/Winamp/PaletteManager.cpp
@@ -0,0 +1,458 @@
+#include "api.h"
+#include "PaletteManager.h"
+#include <api/skin/skinparse.h>
+
+#define COLOR_WHITE (0xffffff)
+#define COLOR_BLACK (0x000000)
+#define COLOR_ERROR (0xff00ff)
+
+
+static ARGB32 parseColor(const wchar_t *color, int *error)
+{
+ if (color == NULL || *color == '\0') { if (error) *error = 1; return COLOR_ERROR; }
+ if (!WCSICMP(color, L"white")) return COLOR_WHITE;
+ if (!WCSICMP(color, L"black")) return COLOR_BLACK;
+ if (wcschr(color, ','))
+ {
+ int r = 0, g = 0, b = 0;
+ if (swscanf(color, L"%d,%d,%d", &r, &g, &b) != 3) return COLOR_ERROR;
+ return RGB(r, g, b); // our colors are reversed internally
+ }
+ if (*color == '#')
+ {
+ int r = 0, g = 0, b = 0;
+ if (swscanf(color, L"#%02x%02x%02x", &r, &g, &b) != 3) return COLOR_ERROR;
+ return RGB(r, g, b);
+ }
+ if (error) *error = 1;
+ return COLOR_ERROR;
+}
+#pragma warning(push)
+#pragma warning(disable : 4355)
+PaletteManager::PaletteManager() : paletteGC(this)
+{
+ skinpart_iterator = 1;
+ genericcounter = 0;
+ WASABI_API_SYSCB->syscb_registerCallback(&paletteGC);
+ WASABI_API_SVC->service_register(&gammaFilterFactory);
+}
+#pragma warning(pop)
+
+PaletteManager::~PaletteManager()
+{
+ WASABI_API_SVC->service_deregister(&gammaFilterFactory);
+ WASABI_API_SYSCB->syscb_deregisterCallback(&paletteGC);
+}
+
+void PaletteManager::StartTransaction()
+{
+ skinColorList.setAutoSort(FALSE);
+ skinAliasList.setAutoSort(FALSE);
+ skinCursorList.setAutoSort(FALSE);
+ skinBitmapList.setAutoSort(FALSE);
+}
+
+void PaletteManager::EndTransaction()
+{
+ skinAliasList.sort();
+ skinColorList.sort();
+ skinCursorList.sort();
+ skinBitmapList.sort();
+}
+
+const int *PaletteManager::getSkinPartIteratorPtr()
+{
+ return &skinpart_iterator;
+}
+
+int PaletteManager::newSkinPart()
+{
+ return ++skinpart_iterator;
+}
+
+int PaletteManager::getSkinPartIterator()
+{
+ return skinpart_iterator;
+}
+
+void PaletteManager::AddAlias(const wchar_t *id, const wchar_t *target)
+{
+ // TODO: benski, in transaction, set some transaction_iterator = skinpart_iterator?
+ skinAliasList.addItem(new SkinElementAlias(id, target, skinpart_iterator, genericcounter++));
+}
+
+void PaletteManager::Reset()
+{
+ skinAliasList.deleteAll();
+ skinColorList.deleteAll();
+ skinCursorList.deleteAll();
+ skinBitmapList.deleteAll();
+ skinAliasList.setAutoSort(FALSE);
+ skinColorList.setAutoSort(FALSE);
+ skinCursorList.setAutoSort(FALSE);
+ skinBitmapList.setAutoSort(FALSE);
+}
+
+const wchar_t *PaletteManager::getElementAlias(const wchar_t *alias)
+{
+ if (alias == NULL) return NULL;
+ int pos;
+ SkinElementAlias *sea = skinAliasList.findLastItem(alias, &pos);
+ if (sea == NULL) return NULL;
+ return skinAliasList.enumItem(pos)->getTargetId();
+}
+
+void PaletteManager::UnloadElements(int skinpart)
+{
+ for (int i = 0;i < skinAliasList.getNumItems();i++)
+ {
+ if (skinAliasList.enumItem(i)->getSkinPartId() == skinpart)
+ {
+ delete skinAliasList.enumItem(i);
+ skinAliasList.removeByPos(i);
+ i--;
+ }
+ }
+ for (int i = 0;i < skinColorList.getNumItems();i++)
+ {
+ if (skinColorList.enumItem(i)->getSkinPartId() == skinpart)
+ {
+ delete skinColorList.enumItem(i);
+ skinColorList.removeByPos(i);
+ i--;
+ }
+ }
+ for (int i = 0;i < skinCursorList.getNumItems();i++)
+ {
+ if (skinCursorList.enumItem(i)->getScriptId() == skinpart)
+ {
+ delete skinCursorList.enumItem(i);
+ skinCursorList.removeByPos(i);
+ i--;
+ }
+ }
+ for (int i = 0;i < skinBitmapList.getNumItems();i++)
+ {
+ if (skinBitmapList.enumItem(i)->getSkinPartId() == skinpart)
+ {
+ delete skinBitmapList.enumItem(i);
+ skinBitmapList.removeByPos(i);
+ i--;
+ }
+ }
+
+}
+
+SkinItem *PaletteManager::getAliasAncestor(SkinItem *item)
+{
+ SkinElementAlias *elem = static_cast<SkinElementAlias *>(item);
+ int pos = skinAliasList.searchItem(elem);
+ if (pos <= 0) return NULL;
+ const wchar_t *it = elem->getAliasName();
+ pos--;
+ SkinElementAlias *aelem = skinAliasList.enumItem(pos);
+ if (aelem == NULL) return NULL;
+ const wchar_t *ait = aelem->getAliasName();
+ if (!WCSICMP(it, ait)) return aelem;
+ return NULL;
+}
+
+void PaletteManager::AddColor(const wchar_t *id, ARGB32 value, const wchar_t *colorgroup, const wchar_t *path, ifc_xmlreaderparams *params)
+{
+ skinColorList.addItem(new SkinColorElement(id, value, skinpart_iterator, genericcounter++, colorgroup, path, params));
+}
+
+int PaletteManager::getNumColorElements()
+{
+ return skinColorList.getNumItems();
+}
+
+const wchar_t *PaletteManager::enumColorElement(int n)
+{
+ return skinColorList.enumItem(n)->getId();
+}
+
+ARGB32 *PaletteManager::getColorElementRef(const wchar_t *type, const wchar_t **grp)
+{
+ const wchar_t *alias = getElementAlias(type);
+ if (alias != NULL)
+ type = alias;
+
+ if (grp != NULL) *grp = NULL;
+ SkinColorElement *sce = skinColorList.findLastItem(type);
+ if (sce == NULL) return NULL;
+ if (grp != NULL) *grp = sce->getColorGroup();
+ return (unsigned long *)(sce->getColorRef());
+}
+
+SkinItem *PaletteManager::getColorAncestor(SkinItem *item)
+{
+ SkinColorElement *elem = static_cast<SkinColorElement *>(item);
+ int pos = skinColorList.searchItem(elem);
+ if (pos <= 0) return NULL;
+ const wchar_t *it = elem->getId();
+ pos--;
+ SkinColorElement *aelem = skinColorList.enumItem(pos);
+ if (aelem == NULL) return NULL;
+ const wchar_t *ait = aelem->getId();
+ if (!WCSICMP(it, ait)) return aelem;
+ return NULL;
+}
+
+ARGB32 PaletteManager::getColorElement(const wchar_t *type, const wchar_t **grp)
+{
+ const wchar_t *alias = getElementAlias(type);
+ if (alias != NULL)
+ type = alias;
+ ARGB32 *v = getColorElementRef(type, grp);
+ if (!v)
+ {
+ int err = 0;
+ ARGB32 r = parseColor(type, &err);
+ if (!err) return r;
+ }
+ return v ? *v : RGB(255, 0, 255);
+}
+
+void PaletteManager::AddCursor(const wchar_t *id, const wchar_t *bitmapid, int x, int y, const wchar_t *path, ifc_xmlreaderparams *params)
+{
+ skinCursorList.addItem(new SkinCursorElement(id, bitmapid, x, y, skinpart_iterator, genericcounter++, path, params));
+}
+
+OSCURSOR PaletteManager::getCursor(const wchar_t *id)
+{
+ int pos = getCursorElement(id);
+ if (pos >= 0)
+ {
+ SkinCursorElement *sce = enumCursorElement(pos);
+ return sce->getCursor();
+ }
+ return INVALIDOSCURSORHANDLE;
+}
+
+int PaletteManager::getCursorElement(const wchar_t *id)
+{
+ const wchar_t *alias = getElementAlias(id);
+ if (alias != NULL)
+ id = alias;
+
+ int pos;
+ SkinCursorElement *sce = skinCursorList.findLastItem(id, &pos);
+ if (sce == NULL) return 0;
+ return pos;
+}
+
+SkinCursorElement *PaletteManager::enumCursorElement(int n)
+{
+ return skinCursorList.enumItem(n);
+}
+
+int PaletteManager::getNumSkinCursorElements()
+{
+ return skinCursorList.getNumItems();
+}
+
+SkinItem *PaletteManager::getCursorAncestor(SkinItem *item)
+{
+ SkinCursorElement *elem = static_cast<SkinCursorElement *>(item);
+ int pos = skinCursorList.searchItem(elem);
+ if (pos <= 0) return NULL;
+ const wchar_t *it = elem->getId();
+ pos--;
+ SkinCursorElement *aelem = skinCursorList.enumItem(pos);
+ if (aelem == NULL) return NULL;
+ const wchar_t *ait = aelem->getId();
+ if (!WCSICMP(it, ait)) return aelem;
+ return NULL;
+}
+
+const wchar_t *PaletteManager::getSkinCursorBitmapId(const wchar_t *cursor)
+{
+ int pos = getCursorElement(cursor);
+ if (pos < 0) return NULL;
+ SkinCursorElement *sce = enumCursorElement(pos);
+ return sce->getBitmapId();
+}
+
+void PaletteManager::AddBitmap(const wchar_t *id, const wchar_t *filename, const wchar_t *path, int x, int y, int w, int h, ifc_xmlreaderparams *params, const wchar_t *colorgroup)
+{
+ skinBitmapList.addItem(new SkinBitmapElement(id, filename, path, x, y, w, h, params, skinpart_iterator, genericcounter++, colorgroup));
+}
+
+
+int PaletteManager::getBitmapElement(const wchar_t *type)
+{
+ if (type == NULL)
+ return -1;
+ const wchar_t *alias = getElementAlias(type);
+ if (alias != NULL)
+ {
+ int pos;
+ SkinBitmapElement *sbe = skinBitmapList.findLastItem(alias, &pos);
+ if (sbe == NULL) return -1;
+ return pos;
+ }
+ else
+ {
+ int pos;
+ SkinBitmapElement *sbe = skinBitmapList.findLastItem(type, &pos);
+ if (sbe == NULL) return -1;
+ return pos;
+ }
+}
+
+RegionServer *PaletteManager::requestSkinRegion(const wchar_t *id)
+{
+ int n = getBitmapElement(id);
+ if (n == -1) return NULL;
+
+ SkinBitmapElement *el = skinBitmapList.enumItem(n);
+ // if (el->region != NULL) el->region->getRegion()->debug();
+ return el->getRegionServer();
+}
+
+void PaletteManager::cacheSkinRegion(const wchar_t *id, api_region *r)
+{
+ int n = getBitmapElement(id);
+ if (n == -1) return ;
+ SkinBitmapElement *el = skinBitmapList.enumItem(n);
+ ASSERT(el != NULL);
+ if (el->getRegionServer() != NULL)
+ {
+ DebugString("Trying to cache a region but cache is already set!\n");
+ return ;
+ }
+ el->setRegionServer(new ElementRegionServer(r));
+ //el->region->getRegion()->debug();
+}
+
+SkinItem *PaletteManager::getBitmapAncestor(SkinItem *item)
+{
+ SkinBitmapElement *elem = static_cast<SkinBitmapElement *>(item);
+ int pos = skinBitmapList.searchItem(elem);
+ if (pos <= 0) return NULL;
+ const wchar_t *it = elem->getId();
+ pos--;
+ SkinBitmapElement *aelem = skinBitmapList.enumItem(pos);
+ if (aelem == NULL) return NULL;
+ const wchar_t *ait = aelem->getId();
+ if (!WCSICMP(it, ait)) return aelem;
+ return NULL;
+}
+
+SkinBitmapElement *PaletteManager::enumBitmapElement(int n)
+{
+ return skinBitmapList.enumItem(n);
+}
+
+int PaletteManager::getNumBitmapElement()
+{
+ return skinBitmapList.getNumItems();
+}
+
+const wchar_t *PaletteManager::getSkinBitmapFilename(const wchar_t *id, int *x, int *y, int *w, int *h, const wchar_t **root_path, ifc_xmlreaderparams **params)
+{
+ int i = getBitmapElement(id); // can return skinBitmapList.getNumItems(), check for that.
+ if (i < 0) return id;
+
+ SkinBitmapElement *sbe = skinBitmapList.enumItem(i);
+
+ if (i < skinBitmapList.getNumItems() && !WCSICMP(id, sbe->getId()))
+ {
+ if (x) *x = sbe->getX();
+ if (y) *y = sbe->getY();
+ if (w) *w = sbe->getW();
+ if (h) *h = sbe->getH();
+ if (params) *params = sbe->getParams();
+ if (root_path) *root_path = sbe->getXmlRootPath();
+ return sbe->getFilename();
+ }
+ return id; //FUCKO: const
+}
+
+
+
+
+
+const wchar_t *PaletteManager::getGammaGroupFromId(const wchar_t *id)
+{
+ int i = getBitmapElement(id);
+ if (i < 0)
+ return NULL;
+ return skinBitmapList[i]->getParams()->getItemValue(L"gammagroup");
+}
+
+int PaletteManager::getLayerFromId(const wchar_t *id)
+{
+ int i = getBitmapElement(id);
+ if (i < 0) return 0;
+ const wchar_t *a = skinBitmapList[i]->getParams()->getItemValue(L"layer");
+ if (a == NULL) return 0;
+ return WTOI(a);
+}
+
+void PaletteManager::onGarbageCollect()
+{
+ for (int i = 0;i < regsrvGC.getNumItems();i++)
+ {
+ ElementRegionServer *srv = regsrvGC.enumItem(i);
+ if (srv->getNumRefs() == 0)
+ {
+ delete srv;
+ regsrvGC.removeByPos(i);
+ i--;
+ }
+ }
+}
+
+void PaletteManager::garbageCollectRegionServer(ElementRegionServer *rs)
+{
+ if (rs->getNumRefs() == 0)
+ {
+ delete rs;
+ return ;
+ }
+ regsrvGC.addItem(rs);
+}
+
+
+int PaletteGC::gccb_onGarbageCollect()
+{
+ parent->onGarbageCollect();
+ return 1;
+}
+
+#define CBCLASS PaletteManager
+START_DISPATCH;
+VCB(API_PALETTE_STARTTRANSACTION, StartTransaction)
+VCB(API_PALETTE_ENDTRANSACTION, EndTransaction)
+VCB(API_PALETTE_RESET, Reset)
+CB(API_PALETTE_GETSKINPARTITERATORPTR,getSkinPartIteratorPtr)
+CB(API_PALETTE_NEWSKINPART,newSkinPart)
+CB(API_PALETTE_GETSKINPARTITERATOR,getSkinPartIterator)
+VCB(API_PALETTE_UNLOADELEMENTS,UnloadElements)
+VCB(API_PALETTE_ADDALIAS,AddAlias)
+CB(API_PALETTE_GETELEMENTALIAS,getElementAlias)
+CB(API_PALETTE_GETALIASANCESTOR,getAliasAncestor)
+VCB(API_PALETTE_ADDCOLOR,AddColor)
+CB(API_PALETTE_GETNUMCOLORELEMENTS,getNumColorElements)
+CB(API_PALETTE_ENUMCOLORELEMENT,enumColorElement)
+CB(API_PALETTE_GETCOLORELEMENTREF,getColorElementRef)
+CB(API_PALETTE_GETCOLORANCESTOR,getColorAncestor)
+CB(API_PALETTE_GETCOLORELEMENT,getColorElement)
+VCB(API_PALETTE_ADDCURSOR,AddCursor)
+CB(API_PALETTE_GETCURSORELEMENT,getCursorElement)
+CB(API_PALETTE_GETCURSOR,getCursor)
+CB(API_PALETTE_GETCURSORANCESTOR,getCursorAncestor)
+CB(API_PALETTE_GETSKINCURSORBITMAPID,getSkinCursorBitmapId)
+VCB(API_PALETTE_ADDBITMAP,AddBitmap)
+CB(API_PALETTE_GETBITMAPELEMENT,getBitmapElement)
+CB(API_PALETTE_GETBITMAPANCESTOR,getBitmapAncestor)
+CB(API_PALETTE_GETNUMBITMAPELEMENT,getNumBitmapElement)
+CB(API_PALETTE_GETSKINBITMAPFILENAME,getSkinBitmapFilename)
+CB(API_PALETTE_GETGAMMAGROUPFROMID,getGammaGroupFromId)
+CB(API_PALETTE_GETLAYERFROMID,getLayerFromId)
+CB(API_PALETTE_REQUESTSKINREGION,requestSkinRegion)
+VCB(API_PALETTE_CACHESKINREGION,cacheSkinRegion)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/PaletteManager.h b/Src/Winamp/PaletteManager.h
new file mode 100644
index 00000000..9f2ee904
--- /dev/null
+++ b/Src/Winamp/PaletteManager.h
@@ -0,0 +1,100 @@
+#pragma once
+#include "SkinElementAlias.h"
+#include "SkinColorElement.h"
+#include "SkinCursorElement.h"
+#include "SkinBitmapElement.h"
+#include <api/syscb/callbacks/gccb.h>
+#include <api/skin/api_palette.h>
+#include <bfc/ptrlist.h>
+#include "GammaFilter.h"
+
+class PaletteManager;
+class PaletteGC : public GarbageCollectCallbackI
+{
+public:
+ PaletteGC(PaletteManager *_parent)
+ {
+ parent = _parent;
+ }
+private:
+ int gccb_onGarbageCollect();
+ PaletteManager *parent;
+};
+class PaletteManager : public api_palette
+{
+public:
+ static const char *getServiceName() { return "Skin Palette API"; }
+ static const GUID getServiceGuid() { return PaletteManagerGUID; }
+ PaletteManager();
+ ~PaletteManager();
+
+ void StartTransaction();
+ void EndTransaction();
+
+ void Reset();
+
+ const int *getSkinPartIteratorPtr();
+ int newSkinPart();
+ int getSkinPartIterator();
+
+ void UnloadElements(int skinpart);
+
+ /* Aliases */
+ void AddAlias(const wchar_t *id, const wchar_t *target);
+ const wchar_t *getElementAlias(const wchar_t *alias);
+ SkinItem *getAliasAncestor(SkinItem *item);
+
+ /* Colors */
+ void AddColor(const wchar_t *id, ARGB32 value, const wchar_t *colorgrp = NULL, const wchar_t *path = NULL, ifc_xmlreaderparams *p = NULL);
+ int getNumColorElements();
+ const wchar_t *enumColorElement(int n);
+ ARGB32 *getColorElementRef(const wchar_t *type, const wchar_t **grp = NULL);
+ SkinItem *getColorAncestor(SkinItem *item);
+ ARGB32 getColorElement(const wchar_t *type, const wchar_t **grp = NULL);
+
+ /* Cursors */
+ void AddCursor(const wchar_t *id, const wchar_t *bitmapid, int x, int y, const wchar_t *path = NULL, ifc_xmlreaderparams *params = NULL);
+ int getCursorElement(const wchar_t *id);
+ OSCURSOR getCursor(const wchar_t *id);
+ SkinItem *getCursorAncestor(SkinItem *item);
+ const wchar_t *getSkinCursorBitmapId(const wchar_t *cursor);
+
+ /* Bitmaps */
+ void AddBitmap(const wchar_t *id, const wchar_t *filename, const wchar_t *path, int x, int y, int w, int h, ifc_xmlreaderparams *params = NULL, const wchar_t *colorgroup = NULL);
+ int getBitmapElement(const wchar_t *type);
+ SkinItem *getBitmapAncestor(SkinItem *item);
+ SkinBitmapElement *enumBitmapElement(int n);
+ int getNumBitmapElement();
+ const wchar_t *getSkinBitmapFilename(const wchar_t *id, int *x, int *y, int *w, int *h, const wchar_t **rootpath, ifc_xmlreaderparams **params);
+ const wchar_t *getGammaGroupFromId(const wchar_t *id);
+ int getLayerFromId(const wchar_t *id);
+
+ /* Region Server (part of Bitmaps) */
+ RegionServer *requestSkinRegion(const wchar_t *id);
+ void cacheSkinRegion(const wchar_t *id, api_region *r);
+ void onGarbageCollect();
+ void garbageCollectRegionServer(ElementRegionServer *rs);
+
+protected:
+ RECVS_DISPATCH;
+private:
+ SkinCursorElement *enumCursorElement(int n);
+ int getNumSkinCursorElements();
+
+ int skinpart_iterator;
+ int genericcounter;
+
+ typedef PtrListQuickMultiSorted<SkinElementAlias, SortSkinElementAlias> SkinAliasList;
+ SkinAliasList skinAliasList;
+ typedef PtrListQuickMultiSorted<SkinColorElement, SortSkinColorElement> SkinColorList;
+ SkinColorList skinColorList;
+ typedef PtrListQuickMultiSorted<SkinCursorElement, SortSkinCursorElement> SkinCursorList;
+ SkinCursorList skinCursorList;
+ typedef PtrListQuickMultiSorted<SkinBitmapElement, SortSkinBitmapElement> SkinBitmapList;
+ SkinBitmapList skinBitmapList;
+
+ PtrList<ElementRegionServer> regsrvGC;
+ PaletteGC paletteGC;
+ GammaFilterFactory gammaFilterFactory;
+};
+
diff --git a/Src/Winamp/ParamList.cpp b/Src/Winamp/ParamList.cpp
new file mode 100644
index 00000000..0118ecd0
--- /dev/null
+++ b/Src/Winamp/ParamList.cpp
@@ -0,0 +1,124 @@
+#include "ParamList.h"
+
+ParamList::~ParamList()
+{
+ //parms_list.deleteAll();
+ for (auto obj : parms_list)
+ {
+ delete obj;
+ }
+ parms_list.clear();
+}
+
+const wchar_t *ParamList::getItemName(int i)
+{
+ if(((size_t)i)>=getNbItems())
+ return L"";
+ return
+ parms_list[i]->parm;
+}
+
+
+const wchar_t *ParamList::getItemValueIndex(int i)
+{
+ if(((size_t)i)>=getNbItems())
+ return L"";
+ return
+ parms_list[i]->value;
+}
+
+const wchar_t *ParamList::getItemValue(const wchar_t *name)
+{
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!WCSICMP(parms_list[i]->parm, name))
+ return parms_list[i]->value;
+ return NULL;
+}
+
+const wchar_t *ParamList::enumItemValues(const wchar_t *name, int nb)
+{
+ int f=0;
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!WCSICMP(parms_list[i]->parm, name))
+ if(f==nb)
+ return parms_list[i]->value;
+ else f++;
+ return NULL;
+}
+
+int ParamList::getItemValueInt(const wchar_t *name, int def)
+{
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!WCSICMP(parms_list[i]->parm, name))
+ {
+ // TODO: benski> do we want to return "def" when there's an empty value?
+ return WTOI(parms_list[i]->value);
+ }
+ return def;
+}
+
+
+size_t ParamList::getNbItems()
+{
+ return parms_list.size();
+}
+
+void ParamList::addItem(const wchar_t *parm, const wchar_t *value)
+{
+ parms_struct *p= new parms_struct;
+ p->parm = WCSDUP(parm);
+ p->ownValue = true;
+ p->value = value;
+ parms_list.push_back(p);
+}
+
+void ParamList::removeItem(const wchar_t *parm)
+{
+ for (size_t i=0; i!=parms_list.size(); i++)
+ {
+ parms_struct *s = parms_list[i];
+ if (!WCSICMP(parm, s->parm))
+ {
+ delete s;
+ parms_list.erase(parms_list.begin() + i);
+ i--;
+ }
+ }
+}
+
+void ParamList::replaceItem(const wchar_t *parm, const wchar_t *value)
+{
+ if (!value)
+ {
+ removeItem(parm);
+ return;
+ }
+
+ StringW s = value; // if we were passed our current value's pointer ...
+
+ const wchar_t *curval = getItemValue(parm);
+ if (s.isequal(value) && curval) return; // (hey, if we're replacing with same value, forget about it, but only if we did have that value, because isequal will return true if curval is NULL and we pass it ("") )
+
+ removeItem(parm); // ... then this call would make the value param invalid ...
+
+ addItem(parm, s); // ... so we're sending a saved buffer instead
+}
+
+int ParamList::findItem(const wchar_t *parm)
+{
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!WCSICMP(parms_list[i]->parm, parm))
+ return (int)i;
+ return -1;
+}
+
+#define CBCLASS ParamList
+START_DISPATCH;
+CB(XMLREADERPARAMS_GETITEMNAME, getItemName)
+CB(XMLREADERPARAMS_GETITEMVALUE, getItemValueIndex)
+CB(XMLREADERPARAMS_GETITEMVALUE2, getItemValue)
+CB(XMLREADERPARAMS_ENUMITEMVALUES, enumItemValues)
+CB(XMLREADERPARAMS_GETITEMVALUEINT, getItemValueInt)
+CB(XMLREADERPARAMS_GETNBITEMS, getNbItems)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/ParamList.h b/Src/Winamp/ParamList.h
new file mode 100644
index 00000000..4baa2257
--- /dev/null
+++ b/Src/Winamp/ParamList.h
@@ -0,0 +1,42 @@
+#pragma once
+#include "../xml/ifc_xmlreaderparams.h"
+#include <vector>
+#include <bfc/string/stringw.h>
+#include <bfc/wasabi_std.h>
+
+class ParamList : public ifc_xmlreaderparams
+{
+public:
+ ParamList() {}
+ ~ParamList();
+
+ const wchar_t *getItemName(int i);
+ const wchar_t *getItemValueIndex(int i);
+ const wchar_t *getItemValue(const wchar_t *name);
+ const wchar_t *enumItemValues(const wchar_t *name, int nb);
+ int getItemValueInt(const wchar_t *name, int def = 0);
+ size_t getNbItems();
+
+ void addItem(const wchar_t *parm, const wchar_t *value);
+ void removeItem(const wchar_t *parm);
+ void replaceItem(const wchar_t *parm, const wchar_t *value);
+ int findItem(const wchar_t *parm);
+
+protected:
+ RECVS_DISPATCH;
+private:
+ struct parms_struct
+ {
+ parms_struct() : parm(0), ownValue(false)
+ {}
+ ~parms_struct()
+ {
+ if (ownValue)
+ FREE((wchar_t *)parm);
+ }
+ const wchar_t *parm;
+ StringW value;
+ bool ownValue;
+ };
+ std::vector<parms_struct*> parms_list;
+}; \ No newline at end of file
diff --git a/Src/Winamp/PathsINI.cpp b/Src/Winamp/PathsINI.cpp
new file mode 100644
index 00000000..e0c59f0e
--- /dev/null
+++ b/Src/Winamp/PathsINI.cpp
@@ -0,0 +1,64 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+
+#include "main.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+
+void LoadPathsIni()
+{
+ wchar_t pathsini[MAX_PATH] = {0};
+ wchar_t dir[1024] = {0};
+
+ PathCombineW(pathsini, PROGDIR, L"paths.ini");
+
+ GetPrivateProfileStringW(L"Winamp", L"inidir", L"", dir, 1024, pathsini);
+ if (dir[0])
+ {
+ ResolveEnvironmentVariables(dir, 1024);
+ config_setinidir(dir);
+ }
+
+ GetPrivateProfileStringW(L"Winamp", L"m3udir", L"", dir, 1024, pathsini);
+ if (dir[0])
+ {
+ ResolveEnvironmentVariables(dir, 1024);
+ config_setm3udir(dir);
+ }
+
+ GetPrivateProfileStringW(L"Winamp", L"m3ubase", L"", dir, 1024, pathsini);
+ if (dir[0])
+ {
+ ResolveEnvironmentVariables(dir, 1024);
+ config_setm3ubase(dir);
+ }
+
+ GetPrivateProfileStringW(L"Winamp", L"inifile", L"", dir, 1024, pathsini);
+ if (dir[0])
+ {
+ ResolveEnvironmentVariables(dir, 1024);
+ config_setinifile(dir);
+ }
+
+ GetPrivateProfileStringW(L"Winamp", L"class", L"", dir, 1024, pathsini);
+ if (dir[0])
+ {
+ ResolveEnvironmentVariables(dir, 1024);
+ StringCchCopyW(szAppName, 64, dir);
+ }
+
+ GetPrivateProfileStringW(L"Winamp", L"cwd", L"", dir, 1024, pathsini);
+ if (dir[0])
+ {
+ ResolveEnvironmentVariables(dir, 1024);
+ StringCchCopyW(config_cwd, MAX_PATH, dir);
+ //MultiByteToWideCharSZ(CP_ACP, 0, dir, -1, config_cwd, MAX_PATH);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/Peui.cpp b/Src/Winamp/Peui.cpp
new file mode 100644
index 00000000..822075b9
--- /dev/null
+++ b/Src/Winamp/Peui.cpp
@@ -0,0 +1,791 @@
+#include "Main.h"
+
+#define inreg(x,y,x2,y2) \
+ ((mouse_x <= ( x2 ) && mouse_x >= ( x ) && \
+ mouse_y <= ( y2 ) && mouse_y >= ( y )))
+
+static int mouse_x, mouse_y, mouse_type, mouse_stats;
+
+static int which_cap=0;
+enum { NO_CAP,TITLE_CAP,TB_CAP, SZ_CAP, VS_CAP, LB_CAP, VSB_CAP, ADD_CAP, REM_CAP, SEL_CAP, MISC_CAP, FILE_CAP, TD_CAP, MB_CAP };
+
+static void do_titlebar(HWND hwnd);
+static void do_titlebuttons();
+static void do_size(HWND hwnd);
+static void do_vscroll(HWND hwnd);
+static void do_lb(HWND hwnd);
+static void do_vsb(HWND hwnd);
+static void do_addbut(HWND hwnd);
+static void do_rembut(HWND hwnd);
+static void do_selbut(HWND hwnd);
+static void do_miscbut(HWND hwnd);
+static void do_filebut(HWND hwnd);
+static void do_timedisplay();
+static void do_mb();
+
+int peui_isrbuttoncaptured()
+{
+ if (which_cap >= ADD_CAP && which_cap <= FILE_CAP) return 1;
+ return 0;
+}
+
+void peui_reset(HWND hwnd)
+{
+ if (which_cap>=ADD_CAP && which_cap <= FILE_CAP)
+ InvalidateRect(hwnd,NULL,0);
+ which_cap=0;
+}
+
+//#include "../gen_ml/ml_ipc_0313.h"
+void peui_handlemouseevent(HWND hwnd, int x, int y, int type, int stats)
+{
+ mouse_x = x;
+ mouse_y = y;
+ mouse_type = type;
+ mouse_stats = stats;
+ if (!which_cap)
+ {
+ if (playing && mouse_type == 1 && config_pe_height != 14 && config_pe_width >= 350 &&
+ inreg(config_pe_width-150-75,config_pe_height-26,config_pe_width-150,config_pe_height-8))
+ {
+ config_sa++;
+ if (config_sa > 2) config_sa = 0;
+ set_visopts();
+ sa_setthread(config_sa);
+ return;
+ }
+ }
+ switch (which_cap)
+ {
+ case MB_CAP: do_mb(); return;
+ case TD_CAP: do_timedisplay(); return;
+ case MISC_CAP: do_miscbut(hwnd); return;
+ case FILE_CAP: do_filebut(hwnd); return;
+ case SEL_CAP: do_selbut(hwnd); return;
+ case ADD_CAP: do_addbut(hwnd); return;
+ case REM_CAP: do_rembut(hwnd); return;
+ case VSB_CAP:do_vsb(hwnd);return;
+ case LB_CAP: do_lb(hwnd);return;
+ case TITLE_CAP: do_titlebar(hwnd);return;
+ case TB_CAP: do_titlebuttons();return;
+ case SZ_CAP: do_size(hwnd); return;
+ case VS_CAP: do_vscroll(hwnd); return;
+ default: break;
+ }
+ if (config_pe_height != 14)
+ {
+ do_mb();
+ do_timedisplay();
+ do_filebut(hwnd);
+ do_miscbut(hwnd);
+ do_selbut(hwnd);
+ do_addbut(hwnd);
+ do_rembut(hwnd);
+ do_vsb(hwnd);
+ do_lb(hwnd);
+ do_vscroll(hwnd);
+ }
+ do_titlebuttons();
+ do_size(hwnd);
+ do_titlebar(hwnd);
+
+ // TODO make this not go weird / cause WM_MOUSEWHEEL to fail, etc
+ #if 0
+ if(!mouse_type)
+ {
+ int t = (mouse_y - 22) / pe_fontheight;
+ if (t < 0) t = 0;
+ else if (t > (config_pe_height - 38 - 22) / pe_fontheight) t = PlayList_getlength();
+ //else t += pledit_disp_offs;
+
+ // TODO alignment isn't 100% correct at times
+ RECT rs = {0};
+ rs.left = 12;
+ rs.right = config_pe_width - 20;
+ rs.top = 22+(pe_fontheight*t);
+ rs.bottom = rs.top + pe_fontheight;
+
+ if(rs.bottom <= config_pe_height - 38)
+ {
+ TOOLINFOW ti = {0};
+ RECT r_main;
+ EstPLWindowRect(&r_main);
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_SUBCLASS|TTF_TRANSPARENT;
+ ti.hwnd = hPLWindow;
+
+ ti.uId = (UINT_PTR)hPL2TooltipWindow;
+ ti.lpszText = (wchar_t*)LPSTR_TEXTCALLBACK;
+ ti.uId = 17;
+ ti.rect = rs;
+
+ // TODO need to get this to show the actual playlist item
+
+ t = (mouse_y - 22) / pe_fontheight;
+ if (t < 0) t = 0;
+ else if (t > (config_pe_height - 38 - 22) / pe_fontheight) t = PlayList_getlength();
+ else t += pledit_disp_offs;
+
+ wchar_t ft[FILETITLE_SIZE], *ftp = ft;
+ PlayList_getitem_pl(t,ft);
+ while(ftp && *ftp)
+ {
+ if(*ftp != ' ') break;
+ ftp = CharNextW(ftp);
+ }
+ ti.lpszText=ftp;
+ ///*if (c)*/
+ SendMessageW(hPLTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ //if (config_ttips)
+ SendMessageW(hPL2TooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+
+ // TODO need to get the skinning code from gen_ml into winamp.exe or split it out...
+ static bool skinned;
+ if(!skinned)
+ {
+ typedef BOOL (__cdecl *MLSKINWINDOWEX)(HWND /*hwnd*/, INT /*type*/, UINT /*style*/);
+ MLSKINWINDOWEX mlSkinWindowEx = (MLSKINWINDOWEX)GetProcAddress(GetModuleHandle("gen_ml.dll"), "MlSkinWindowEx");
+ unsigned int skinStyle = SWS_USESKINCOLORS;
+ skinStyle |= ((SWS_USESKINFONT | SWS_USESKINCURSORS)/* & style*/);
+ mlSkinWindowEx(hPL2TooltipWindow, SKINNEDWND_TYPE_TOOLTIP, skinStyle);
+ skinned = true;
+ }
+ }
+ }
+ #endif
+}
+
+
+static void __do_buttons(int which)
+{
+ int m = WINAMP_BUTTON1 + which;
+ if (which == 5)
+ {
+ if (mouse_stats & MK_CONTROL) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_LOC,0);
+ else if (mouse_stats & MK_SHIFT) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_DIR,0);
+ else SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_PLAY,0);
+ }
+ else
+ {
+ if (mouse_stats & MK_SHIFT) m += 100;
+ else if (mouse_stats & MK_CONTROL) m += 110;
+ SendMessageW(hMainWindow,WM_COMMAND,m,0);
+ }
+}
+
+static void do_mb()
+{
+ if (!which_cap && mouse_type == 1 && inreg(config_pe_width-144,config_pe_height-15,config_pe_width-91,config_pe_height-8))
+ {
+ int t=config_pe_width-144;
+ int which = 5 - (mouse_x < 45+t) - (mouse_x < 36+t) - (mouse_x < 27+t) - (mouse_x < 17+t) - (mouse_x < 7+t);
+ which_cap = MB_CAP;
+ __do_buttons(which);
+
+ }
+ if (which_cap == MB_CAP && mouse_type == -1)
+ which_cap=0;
+}
+
+
+
+static void do_timedisplay()
+{
+ if (!which_cap && mouse_type == 1 && inreg(config_pe_width-87,config_pe_height-18,config_pe_width-53,config_pe_height-9))
+ {
+ which_cap = TD_CAP;
+ config_timeleftmode = !config_timeleftmode;
+ if (!config_timeleftmode)
+ {
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_ELAPSED,MF_CHECKED);
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_REMAINING,MF_UNCHECKED);
+ }
+ else
+ {
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_ELAPSED,MF_UNCHECKED);
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_REMAINING,MF_CHECKED);
+ }
+ SendMessageW(hMainWindow,WM_TIMER,UPDATE_DISPLAY_TIMER+4,0);
+ }
+ if (which_cap == TD_CAP && mouse_type == -1)
+ which_cap=0;
+}
+
+static void do_filebut(HWND hwnd)
+{
+ int lwc=which_cap;
+ if (!which_cap && mouse_type == 1 && inreg(config_pe_width-44,config_pe_height-30,config_pe_width-44+22,config_pe_height-12))
+ {
+ which_cap = FILE_CAP;
+ }
+
+ if (which_cap == FILE_CAP)
+ {
+ int doit=-1;
+ if (inreg(config_pe_width-44,config_pe_height-30,config_pe_width-44+22,config_pe_height-12)) doit=0;
+ else if (inreg(config_pe_width-44,config_pe_height-30-18,config_pe_width-44+22,config_pe_height-12-18)) doit=1;
+ else if (inreg(config_pe_width-44,config_pe_height-30-18*2,config_pe_width-44+22,config_pe_height-12-18*2)) doit=2;
+ draw_pe_iobut(doit);
+
+ if ((config_ospb&&mouse_type==-1) || (mouse_type == 1 && lwc==FILE_CAP))
+ {
+ RECT r={config_pe_width-44-5,config_pe_height-12-18*3,config_pe_width-44+22,config_pe_height-12};
+ InvalidateRect(hwnd,&r,FALSE);
+ which_cap=0;
+ switch (doit)
+ {
+ case 0: SendMessageW(hwnd,WM_COMMAND,ID_PE_OPEN,0); break;
+ case 1: SendMessageW(hwnd,WM_COMMAND,ID_PE_SAVEAS,0); break;
+ case 2: SendMessageW(hwnd,WM_COMMAND,ID_PE_CLEAR,0); break;
+ }
+ }
+ }
+}
+
+
+
+static void do_miscbut(HWND hwnd)
+{
+ int lwc=which_cap;
+ if (!which_cap && mouse_type == 1 && inreg(101,config_pe_height-30,122,config_pe_height-12))
+ {
+ which_cap = MISC_CAP;
+ }
+
+ if (which_cap == MISC_CAP)
+ {
+ int doit=-1;
+ if (inreg(101,config_pe_height-30,122,config_pe_height-12)) doit=0;
+ else if (inreg(101,config_pe_height-30-18,122,config_pe_height-12-18)) doit=1;
+ else if (inreg(101,config_pe_height-30-18*2,122,config_pe_height-12-18*2)) doit=2;
+ draw_pe_miscbut(doit);
+ if ((config_ospb&&mouse_type==-1) || (mouse_type == 1 && lwc==MISC_CAP))
+ {
+ RECT r={97,config_pe_height-12-18*3,123,config_pe_height-12};
+ which_cap=0;
+ switch (doit)
+ {
+ case 1:
+ {
+ POINT p={122,config_pe_height-30-18};
+ ClientToScreen(hwnd,&p);
+ DoTrackPopup(GetSubMenu(GetSubMenu(GetSubMenu(top_menu,2),0),0),TPM_LEFTALIGN,p.x,p.y,hwnd);
+ }
+ break;
+ case 2:
+ {
+ POINT p={122,config_pe_height-30-18*2};
+ ClientToScreen(hwnd,&p);
+ DoTrackPopup(GetSubMenu(GetSubMenu(GetSubMenu(top_menu,2),0),1),TPM_LEFTALIGN,p.x,p.y,hwnd);
+ }
+ break;
+ case 0:
+ {
+ POINT p={122,config_pe_height-30};
+ ClientToScreen(hwnd,&p);
+ DoTrackPopup(GetSubMenu(GetSubMenu(GetSubMenu(top_menu,2),0),2),TPM_LEFTALIGN,p.x,p.y,hwnd);
+ }
+ break;
+ }
+ InvalidateRect(hwnd,&r,FALSE);
+ }
+ }
+}
+
+
+static void do_selbut(HWND hwnd)
+{
+ int lwc=which_cap;
+ if (!which_cap && mouse_type == 1 && inreg(72,config_pe_height-30,93,config_pe_height-12))
+ {
+ which_cap = SEL_CAP;
+ }
+
+ if (which_cap == SEL_CAP)
+ {
+ int doit=-1;
+ if (inreg(72,config_pe_height-30,93,config_pe_height-12)) doit=0;
+ else if (inreg(72,config_pe_height-30-18,93,config_pe_height-12-18)) doit=1;
+ else if (inreg(72,config_pe_height-30-18*2,93,config_pe_height-12-18*2)) doit=2;
+ draw_pe_selbut(doit);
+ if ((config_ospb&&mouse_type==-1) || (mouse_type == 1 && lwc==SEL_CAP))
+ {
+ RECT r={68,config_pe_height-12-18*3,95,config_pe_height-12};
+ InvalidateRect(hwnd,&r,FALSE);
+ which_cap=0;
+ switch (doit)
+ {
+ case 0: SendMessageW(hwnd,WM_COMMAND,ID_PE_SELECTALL,0); break;
+ case 1: SendMessageW(hwnd,WM_COMMAND,ID_PE_NONE,0); break;
+ case 2: SendMessageW(hwnd,WM_COMMAND,IDC_SELECTINV,0); break;
+ }
+ }
+ }
+}
+
+static void do_rembut(HWND hwnd)
+{
+ int lwc=which_cap;
+ if (!which_cap && mouse_type == 1 && inreg(43,config_pe_height-30,64,config_pe_height-12))
+ {
+ which_cap = REM_CAP;
+ }
+
+ if (which_cap == REM_CAP)
+ {
+ int doit=-1;
+ if (inreg(43,config_pe_height-30,64,config_pe_height-12)) doit=0;
+ else if (inreg(43,config_pe_height-30-18,64,config_pe_height-12-18)) doit=1;
+ else if (inreg(43,config_pe_height-30-18*2,64,config_pe_height-12-18*2)) doit=2;
+ else if (inreg(43,config_pe_height-30-18*3,64,config_pe_height-12-18*3)) doit=3;
+ draw_pe_rembut(doit);
+ if ((config_ospb&&mouse_type==-1) || (mouse_type == 1 && lwc==REM_CAP))
+ {
+ RECT r={39,config_pe_height-12-18*4,65,config_pe_height-12};
+ which_cap=0;
+ switch (doit)
+ {
+ case 0: SendMessageW(hwnd,WM_COMMAND,IDC_PLAYLIST_REMOVEMP3,0); break;
+ case 1: SendMessageW(hwnd,WM_COMMAND,IDC_PLAYLIST_CROP,0); break;
+ case 2: SendMessageW(hwnd,WM_COMMAND,ID_PE_CLEAR,0); break;
+ case 3:
+ {
+ POINT p={64,config_pe_height-30-18*3};
+ ClientToScreen(hwnd,&p);
+ DoTrackPopup(GetSubMenu(GetSubMenu(GetSubMenu(top_menu,2),2),3),TPM_LEFTALIGN,p.x,p.y,hwnd);
+ }
+ break;
+ }
+ InvalidateRect(hwnd,&r,FALSE);
+ }
+ }
+}
+
+static void do_addbut(HWND hwnd)
+{
+ int lwc=which_cap;
+ if (!which_cap && mouse_type == 1 && inreg(14,config_pe_height-30,35,config_pe_height-12))
+ {
+ which_cap = ADD_CAP;
+ }
+
+ if (which_cap == ADD_CAP)
+ {
+ int doit=-1;
+ if (inreg(14,config_pe_height-30,35,config_pe_height-12)) doit=0;
+ else if (inreg(14,config_pe_height-30-18,35,config_pe_height-12-18)) doit=1;
+ else if (inreg(14,config_pe_height-30-18*2,35,config_pe_height-12-18*2)) doit=2;
+ draw_pe_addbut(doit);
+ if ((config_ospb&&mouse_type==-1) || (mouse_type == 1 && lwc==ADD_CAP))
+ {
+ RECT r={11,config_pe_height-12-18*3,36,config_pe_height-12};
+ InvalidateRect(hwnd,&r,FALSE);
+ which_cap=0;
+ switch (doit)
+ {
+ case 0: SendMessageW(hwnd,WM_COMMAND,IDC_PLAYLIST_ADDMP3,0); break;
+ case 1: SendMessageW(hwnd,WM_COMMAND,IDC_PLAYLIST_ADDDIR,0); break;
+ case 2: SendMessageW(hwnd,WM_COMMAND,IDC_PLAYLIST_ADDLOC,0); break;
+ }
+ }
+ }
+
+}
+
+static void do_vsb(HWND hwnd)
+{
+ if (!which_cap && mouse_type == 1 && inreg(config_pe_width-15,config_pe_height-36,config_pe_width-7,config_pe_height-32))
+ {
+ SendMessageW(hwnd,WM_COMMAND,ID_PE_SCROLLUP,0);
+ which_cap = VSB_CAP;
+ }
+ if (!which_cap && mouse_type == 1 && inreg(config_pe_width-15,config_pe_height-31,config_pe_width-7,config_pe_height-27))
+ {
+ SendMessageW(hwnd,WM_COMMAND,ID_PE_SCROLLDOWN,0);
+ which_cap = VSB_CAP;
+ }
+
+ if (which_cap == VSB_CAP && mouse_type == -1) which_cap=0;
+}
+
+int shiftsel_1=-1;
+
+static void do_lb(HWND hwnd)
+{
+ static int move_mpos,stt;
+
+ if (!which_cap && mouse_type == 1 && inreg(12,20,config_pe_width-20,config_pe_height-38))
+ {
+ int wh=(mouse_y-22)/pe_fontheight + pledit_disp_offs;
+ if (!(mouse_stats & MK_CONTROL) && !PlayList_getselect(wh))
+ {
+ int x,t=PlayList_getlength();
+ for (x = 0; x < t; x ++)
+ PlayList_setselect(x,0);
+ }
+ if (mouse_stats & MK_SHIFT)
+ {
+ if (shiftsel_1 != -1)
+ {
+ int x,t=max(min(PlayList_getlength(),shiftsel_1),min(PlayList_getlength(),wh));
+ if (!(mouse_stats & MK_CONTROL) && PlayList_getselect(wh))
+ {
+ int x,t=PlayList_getlength();
+ for (x = 0; x < t; x ++)
+ PlayList_setselect(x,0);
+ }
+ for (x = min(shiftsel_1,wh); x <=t; x ++)
+ {
+ PlayList_setselect(x,1);
+ }
+ stt=1;
+ }
+ }
+ else
+ {
+ if (PlayList_getselect(wh) && mouse_stats & MK_CONTROL) PlayList_setselect(wh,0);
+ else
+ {
+ int y = wh-pledit_disp_offs;
+ if (y < PlayList_getlength()-pledit_disp_offs && y < (config_pe_height-38-20-2)/pe_fontheight)
+ {
+ PlayList_setselect(wh,1);
+ }
+ }
+ shiftsel_1=wh;
+ }
+
+ {
+ RECT r1={12,22,config_pe_width-20,config_pe_height-38};
+ RECT r2={12,20+(wh-pledit_disp_offs)*pe_fontheight,config_pe_width-20,20+(wh+1-pledit_disp_offs)*pe_fontheight};
+ if (!(mouse_stats & MK_CONTROL) || (mouse_stats & MK_SHIFT))
+ InvalidateRect(hwnd,&r1,FALSE);
+ else
+ InvalidateRect(hwnd,&r2,FALSE);
+ }
+ move_mpos=(mouse_y-22)/pe_fontheight+pledit_disp_offs;
+ which_cap=LB_CAP;
+ }
+ if (which_cap == LB_CAP)
+ {
+ extern int g_has_deleted_current;
+ int m=(mouse_y-22)/pe_fontheight+pledit_disp_offs;
+ if (m!=move_mpos)
+ {
+ int v,x;
+ v = PlayList_getlength();
+ x=1;
+ while (m>move_mpos)
+ {
+ if (!PlayList_getselect(v-1)) for (x = v-2; x >= 0; x --)
+ {
+ if (!PlayList_getselect(x))
+ {
+ continue;
+ }
+ if (shiftsel_1 == x) shiftsel_1=x+1;
+ PlayList_swap(x,x+1);
+ if (x == PlayList_getPosition())
+ PlayList_advance(1);
+ else if (x+1 == PlayList_getPosition())
+ PlayList_advance(-1);
+ }
+ move_mpos++;
+ }
+ while (m<move_mpos)
+ {
+ if (!PlayList_getselect(0)) for (x = 1; x < v; x ++)
+ {
+ if (!PlayList_getselect(x)) continue;
+ if (shiftsel_1 == x) shiftsel_1=x-1;
+ PlayList_swap(x,x-1);
+ if (x == PlayList_getPosition())
+ PlayList_advance(-1);
+ else if (x-1 == PlayList_getPosition())
+ PlayList_advance(1);
+ }
+ move_mpos--;
+ }
+
+ if (mouse_y < 10)
+ {
+ RECT r={0,0,config_pe_width,config_pe_height-37};
+// move_mpos++;
+ pledit_disp_offs --;
+ if (pledit_disp_offs < 0) { pledit_disp_offs=0; move_mpos=0;}
+ InvalidateRect(hwnd,&r,FALSE);
+ }
+ else if (mouse_y > config_pe_height-28)
+ {
+ RECT r={0,0,config_pe_width,config_pe_height-37};
+ int num_songs=(config_pe_height-38-20-2)/pe_fontheight;
+ int t=PlayList_getlength()-num_songs;
+ // move_mpos--;
+ pledit_disp_offs ++;
+ if (pledit_disp_offs > t) { pledit_disp_offs=max(t,0); move_mpos=PlayList_getlength(); }
+ InvalidateRect(hwnd,&r,FALSE);
+ }
+ else {
+ RECT r1={12,22,config_pe_width-20,config_pe_height-38};
+ InvalidateRect(hwnd,&r1,FALSE);
+ }
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName,FileTitle,FileTitleNum);
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ }
+ }
+
+ if (mouse_type == -1)
+ {
+ if (!stt)
+ {
+ int wh=(mouse_y-22)/pe_fontheight + pledit_disp_offs;
+ if (!(mouse_stats & MK_CONTROL) && PlayList_getselect(wh))
+ {
+ int x,t=PlayList_getlength();
+ for (x = 0; x < t; x ++)
+ PlayList_setselect(x,0);
+ PlayList_setselect(wh,1);
+ {
+ RECT r1={12,22,config_pe_width-20,config_pe_height-38};
+ InvalidateRect(hwnd,&r1,FALSE);
+ }
+ }
+
+ }
+ stt=0;
+ which_cap=0;
+ }
+ }
+}
+
+
+static void do_titlebar(HWND hwnd)
+{
+#ifdef FFSKIN
+ if ((GetParent(hwnd) == NULL) && (which_cap == TITLE_CAP || (!which_cap && (config_easymove || mouse_y < 14))))
+#else
+ if (which_cap == TITLE_CAP || (!which_cap && (config_easymove || mouse_y < 14)))
+#endif
+ {
+ static int clickx, clicky;
+ switch (mouse_type)
+ {
+ case 1:
+ which_cap=TITLE_CAP;
+ clickx=mouse_x;
+ clicky=mouse_y;
+ break;
+ case -1:
+ which_cap=0;
+ break;
+ case 0:
+ if (which_cap == TITLE_CAP && mouse_stats & MK_LBUTTON)
+ {
+ POINT p = { mouse_x,mouse_y};
+ ClientToScreen(hwnd,&p);
+ config_pe_wx = p.x-clickx;
+ config_pe_wy = p.y-clicky;
+ if ((!!config_snap) ^ (!!(mouse_stats & MK_SHIFT)))
+ {
+ RECT outrc;
+ EstPLWindowRect(&outrc);
+ SnapWindowToAllWindows(&outrc,hwnd);
+ SetPLWindowRect(&outrc);
+ }
+
+ SetWindowPos(hwnd,0,config_pe_wx,config_pe_wy,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ break;
+ }
+ }
+}
+
+static void do_titlebuttons()
+{
+ int w=0;
+ w=inreg(config_pe_width-10,3,config_pe_width-1,3+9)?1:w;
+ w=inreg(config_pe_width-20,3,config_pe_width-11,3+9)?2:w;
+
+ if (w) // kill button
+ {
+ if (mouse_type == -1 && which_cap == TB_CAP)
+ {
+ which_cap=0;
+ draw_pe_tbutton(0,0,0);
+ SendMessageW(hMainWindow,WM_COMMAND,w==1?WINAMP_OPTIONS_PLEDIT:WINAMP_OPTIONS_WINDOWSHADE_PL,0);
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ which_cap=TB_CAP;
+ draw_pe_tbutton(w==2?1:0,w==1?1:0,config_pe_height==14?1:0);
+ }
+ }
+ else if (which_cap == TB_CAP)
+ {
+ which_cap=0;
+ draw_pe_tbutton(0,0,config_pe_height==14?1:0);
+ }
+
+}
+
+static void do_size(HWND hwnd)
+{
+ if (which_cap == SZ_CAP || (config_pe_height != 14 && !which_cap &&
+ mouse_x > config_pe_width-20 && mouse_y > config_pe_height-20 &&
+ ((config_pe_width-mouse_x + config_pe_height-mouse_y) <= 30))
+ ||
+ (config_pe_height == 14 && !which_cap && mouse_x > config_pe_width-29 && mouse_x < config_pe_width-20)
+ )
+ {
+ static int dx,dy;
+ if (!which_cap && mouse_type == 1)
+ {
+ dx=config_pe_width-mouse_x;
+ dy=config_pe_height-mouse_y;
+ which_cap=SZ_CAP;
+ }
+ if (which_cap == SZ_CAP)
+ {
+ int x,y;
+ if (mouse_type == -1)
+ {
+ which_cap=0;
+ }
+ x=mouse_x + dx;
+ y=mouse_y + dy;
+// if (x >= GetSystemMetrics(SM_CXSCREEN)) x = GetSystemMetrics(SM_CXSCREEN)-24;
+// if (y >= GetSystemMetrics(SM_CYSCREEN)) y = GetSystemMetrics(SM_CYSCREEN)-28;
+ if (!config_embedwnd_freesize)
+ {
+ x += 24;
+ x -= x%25;
+ y += 28;
+ y -= y%29;
+ }
+ if (x < 275) x = 275;
+ if (y < 20+38+29+29) y = 20+38+29+29;
+ config_pe_width = x;
+ if (config_pe_height != 14) config_pe_height= y;
+ SetWindowPos(hwnd,0,0,0,config_pe_width,config_pe_height,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
+ if (hPLVisWindow)
+ {
+ int x,y,w,h;
+ x=config_pe_width-150-75+2;
+ y=config_pe_height-26;
+ w=(config_pe_width >= 350 && config_pe_height != 14 ? 72 : 0);
+ h=16;
+ SetWindowPos(hPLVisWindow,0,x,y,w,h,SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ }
+ }
+
+}
+
+static void do_vscroll(HWND hwnd)
+{
+ int top=20,bottom=config_pe_height-38;
+ int num_songs=(config_pe_height-38-20-2)/pe_fontheight;
+ int xoffs=config_pe_width-15,w=8;
+
+ if (inreg(xoffs,top,xoffs+w,bottom) || which_cap == VS_CAP)
+ {
+ if ((!which_cap && mouse_type == 1) || which_cap == VS_CAP)
+ {
+ int d;
+ int p;
+ static int click_yoffs=9;
+ int a=PlayList_getlength()-num_songs;
+ {
+ if (a < 1) p = top;
+ else
+ {
+ p = top + ((config_pe_height-38-20-18)*pledit_disp_offs) / a;
+ }
+ }
+ if (mouse_type == 1 && mouse_y >= p && mouse_y < p + 20)
+ {
+ click_yoffs=mouse_y - p -1;
+ } else if (mouse_type == 1) click_yoffs=9;
+
+ d=((mouse_y-click_yoffs-top)*a)/(config_pe_height-38-20-18);
+
+
+ pledit_disp_offs = d;
+ if (pledit_disp_offs > a) pledit_disp_offs = a;
+
+ draw_pe_vslide(hwnd, NULL, 1,pledit_disp_offs);
+ {
+ RECT r={12,22,config_pe_width-19,config_pe_height-37};
+ InvalidateRect(hwnd,&r,FALSE);
+ }
+
+ if (mouse_type == -1)
+ {
+ draw_pe_vslide(hwnd, NULL, 0,pledit_disp_offs);
+ which_cap=0;
+ } else
+ {
+ which_cap = VS_CAP;
+ }
+ }
+ }
+}
+
+ static const RECT b_normal[] =
+ {
+ {-(275-254),3,-(275-262),12},//wshade
+ {-(275-264),3,-(275-272),12},//close
+ {0,0,-1,13},// titelbar
+ {-15,20,-7,-38},
+ {-20,-20,-1,-1},
+ },
+ b_windowshade[] =
+ {
+ {-(275-254),3,-(275-262),12},//wshade
+ {-(275-264),3,-(275-272),12},//close
+ {-29,3,-20,12},//size
+ };
+
+void pe_ui_handlecursor(HWND hwnd)
+{
+ int mouse_x, mouse_y;
+ POINT p;
+ const RECT *b;
+ int b_len;
+ int x;
+
+ if (!config_usecursors || disable_skin_cursors) return;
+ GetCursorPos(&p);
+ ScreenToClient(hwnd,&p);
+ mouse_x=p.x;
+ mouse_y=p.y;
+ if (config_pe_height == 14)
+ {
+ b=b_windowshade;
+ b_len = sizeof(b_windowshade)/sizeof(b_windowshade[0]);
+ }
+ else
+ {
+ b=b_normal;
+ b_len = sizeof(b_normal)/sizeof(b_normal[0]);
+ }
+ for (x = 0; x < b_len; x ++)
+ {
+ int l,r,t,bo;
+ l=b[x].left;r=b[x].right;t=b[x].top;bo=b[x].bottom;
+ if (l < 0) l += config_pe_width;
+ if (r < 0) r += config_pe_width;
+ if (t < 0) t += config_pe_height;
+ if (bo < 0) bo += config_pe_height;
+ if (inreg(l,t,r,bo)) break;
+ }
+
+ if (config_pe_height == 14) x+=21;
+ else x+=15;
+
+ if (Skin_Cursors[x]) SetCursor(Skin_Cursors[x]);
+ else SetCursor(LoadCursor(NULL,IDC_ARROW));
+
+}
diff --git a/Src/Winamp/Play.cpp b/Src/Winamp/Play.cpp
new file mode 100644
index 00000000..342165fa
--- /dev/null
+++ b/Src/Winamp/Play.cpp
@@ -0,0 +1,322 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include "resource.h"
+#include "strutil.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoCharFn.h"
+#include "MediaCoreCOM.h"
+#include "externalCOM.h"
+#include "JSAPI2_CallbackManager.h"
+
+static int in_play;
+extern int no_notify_play;
+
+
+void Play(const wchar_t *playstring)
+{
+ int i = -31337;
+ static int a = -2;
+ AutoCharFn charFn(playstring);
+
+ // added in 5.64 - this helps to keep the currently playing file after
+ // a tag update to stay playing correctly when it is no longer in the
+ // main playlist editor - this helps to keep a consistent ui experience
+ bool restart = false;
+ if (no_notify_play && playstring && *playstring && !PlayList_getlength())
+ {
+ PlayList_insert(0, playstring);
+ restart = true;
+ }
+
+ in_play = 1;
+
+ g_video_numaudiotracks = 1;
+ g_video_curaudiotrack = 0;
+
+ g_stopaftercur = 0;
+ CheckMenuItem(main_menu, WINAMP_BUTTON4_CTRL, MF_UNCHECKED);
+ CheckMenuItem(GetSubMenu(top_menu, 3), WINAMP_BUTTON4_CTRL, MF_UNCHECKED);
+
+ g_has_deleted_current = 0;
+ Skin_Random();
+
+ Stats_OnPlay(playstring);
+
+ // has cropped up in a few crash reports where app_name is null which causes the update to bork
+ // when receiving a 'stop' command and we try to send an update via JSAPI1_CurrentTitleChanged()
+ if (!app_name || app_name && !*app_name || (unsigned int)(ULONG_PTR)app_name < 65536)
+ BuildAppName();
+
+ set_caption(0, L"%s - %S", (config_dotasknum?FileTitleNum:FileTitle), app_name); // TODO: benski> get rid of FileTitle here
+ eq_autoload(charFn);
+
+ if (a == -2)
+ a = PlayList_getlength();
+
+ if (!*playstring || (i = in_open(playstring)))
+ {
+ if (*playstring && i != -31337 && --a) //-31337 == no_sound_card
+ {
+ PostMessageW(hMainWindow, WM_WA_MPEG_EOF, 0, 0);
+ }
+ else
+ {
+ if (i == -31337) in_mod = 0;
+ StopPlaying(0);
+ a = -2;
+ }
+ in_play = 0;
+ return ;
+ }
+ else
+ {
+ a = -2;
+ }
+
+ SendMessageW(hMainWindow, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ PlayList_refreshtitle();
+ PlayList_GetCurrentTitle(FileTitle, FILETITLE_SIZE); // TODO: benski> don't want to be using global FileTitle here
+ // has cropped up in a few crash reports where app_name is null which causes the update to bork
+ // when receiving a 'stop' command and we try to send an update via JSAPI1_CurrentTitleChanged()
+ if (!app_name || app_name && !*app_name || (unsigned int)(ULONG_PTR)app_name < 65536) BuildAppName();
+ set_caption(0, L"%s - %S", (config_dotasknum?FileTitleNum:FileTitle), app_name);
+ if (in_mod && in_mod->is_seekable) draw_positionbar(0, 0);
+ plEditSelect(PlayList_getPosition());
+ SetTimer(hMainWindow, UPDATE_DISPLAY_TIMER, 100, NULL);
+ playing = 1;
+ draw_playicon(1);
+ ui_songposition = 0;
+ draw_songname(FileTitle, &ui_songposition, in_getlength());
+ if (config_visplugin_autoexec && !vis_running())
+ vis_start(hMainWindow, NULL);
+ if (!dsp_isactive()) dsp_init();
+ paused = 0;
+
+ // added in 5.64
+ if(restart) PlayList_deleteitem(0);
+
+ if (!no_notify_play)
+ {
+ // don't tell anyone we're playing the file is there are hidden items or there's an ad curtain
+ if (PlayList_hasanycurtain(PlayList_getPosition()) == 0 && PlayList_ishidden(PlayList_getPosition()) == 0)
+ {
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)(char *)charFn, IPC_PLAYING_FILE);
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)playstring, IPC_PLAYING_FILEW);
+ SendNotifyMessage(HWND_BROADCAST, songChangeBroadcastMessage, 0, 0);
+ }
+ }
+
+ in_play = 0;
+
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_STATUS, IPC_CB_MISC);
+
+ MediaCoreCOM *mediaCore;
+ if (SUCCEEDED(JSAPI1_GetMediaCoreCOM(&mediaCore)))
+ {
+ mediaCore->OnPlay();
+ mediaCore->Release();
+ }
+
+ JSAPI2::callbackManager.OnPlay(FileName);
+}
+
+void StartPlaying()
+{
+ // reset this flag when we start playing otherwise
+ // it can cause it to be incorrectly applied later
+ plcleared = 0;
+ if (playing) StopPlaying(0);
+ if (in_play) return ;
+ {
+ // Check if we have the media library , if we do check to see if we have and ad curtain
+ // If we do, and the current item is the first item, display it
+ const char *adcurtain = PlayList_getcurtain(PlayList_getPosition());
+ if (adcurtain && *adcurtain)
+ {
+ if (*adcurtain == 'a')
+ {
+ // 'a' means it's an Ad, so pop out of fullscreen.
+ if ( videoIsFullscreen() ) videoForceFullscreenOff();
+ adcurtain = CharNextA(adcurtain); // get past the a in ahttp://....
+ }
+ }
+ }
+
+ if (!no_notify_play)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ }
+ Play(FileName);
+}
+
+/* -------- Stoppping -------- */
+
+// TODO: avoid passing g_quit
+void ClassicSkin_OnStop(int g_quit)
+{
+ if (playing)
+ {
+ KillTimer(hMainWindow, UPDATE_DISPLAY_TIMER);
+ }
+
+ if (!g_quit)
+ {
+ sa_setthread(0);
+ if (!no_notify_play)
+ {
+ PlayList_getcurrent_onstop(FileName, FileTitle);
+ if (*FileTitle)
+ {
+ wchar_t titleStr[64] = {0};
+ set_caption(0, getStringW(IDS_TITLE_ON_STOP,titleStr,64), (config_dotasknum?FileTitleNum:FileTitle), app_name);
+ }
+ else
+ {
+ // has cropped up in a few crash reports where app_name is null which causes the update to bork
+ // when receiving a 'stop' command and we try to send an update via JSAPI1_CurrentTitleChanged()
+ if (!app_name || app_name && !*app_name || (unsigned int)(ULONG_PTR)app_name < 65536) BuildAppName();
+ set_caption(0, L"%S %S", (!app_name || app_name && !*app_name ? "Winamp" : app_name), app_version_string);
+ }
+
+ plEditSelect(PlayList_getPosition());
+ }
+
+ draw_setnoupdate(1);
+ draw_clear();
+ draw_monostereo(0);
+ draw_clutterbar(0);
+ draw_playicon(2);
+ draw_shuffle(config_shuffle, 0);
+ draw_eject(0);
+ draw_eqplbut(config_eq_open, 0, config_pe_open, 0);
+ draw_repeat(config_repeat, 0);
+ draw_volumebar(config_volume, 0);
+ draw_panbar(config_pan, 0);
+ draw_buttonbar( -1);
+ if (config_pe_height != 14)
+ draw_pe_timedisp(NULL, 0, 0, 0, 1);
+ draw_songname(FileTitle, &ui_songposition, PlayList_getcurrentlength());
+ draw_setnoupdate(0);
+ last_brate = -1;
+ }
+}
+
+void StopPlaying(int g_quit)
+{
+ if (in_play) return ;
+ in_play = 1;
+ g_has_deleted_current = 0;
+
+ int last_time = 0;
+ if (!g_fullstop) // if this wasn't an EOF situation, grab the current time so that the callback can be told the stop time.
+ last_time = in_getouttime();
+
+ if (playing)
+ {
+ paused = 0;
+ playing = 0;
+ g_video_numaudiotracks = 1;
+ g_video_curaudiotrack = 0;
+ in_close();
+ }
+
+ ClassicSkin_OnStop(g_quit);
+
+ in_play = 0;
+
+ stopPlayingInfoStruct infoStruct;
+ infoStruct.g_fullstop = g_fullstop;
+ infoStruct.last_time = last_time;
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&infoStruct, IPC_STOPPLAYING);
+
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_STATUS, IPC_CB_MISC);
+
+ MediaCoreCOM *mediaCore;
+ if (SUCCEEDED(JSAPI1_GetMediaCoreCOM(&mediaCore)))
+ {
+ mediaCore->OnStop(last_time, g_fullstop);
+ mediaCore->Release();
+ }
+
+ JSAPI2::callbackManager.OnStop(last_time, g_fullstop);
+}
+
+void Skin_OnPause()
+{
+ wchar_t titleStr[64] = {0};
+ set_caption(0, getStringW(IDS_TITLE_ON_PAUSE,titleStr,64), (config_dotasknum?FileTitleNum:FileTitle), app_name);
+ draw_playicon(4);
+}
+
+void Skin_OnUnpause()
+{
+ // has cropped up in a few crash reports where app_name is null which causes the update to bork
+ // when receiving a 'stop' command and we try to send an update via JSAPI1_CurrentTitleChanged()
+ if (!app_name || app_name && !*app_name || (unsigned int)(ULONG_PTR)app_name < 65536) BuildAppName();
+ set_caption(0, L"%s - %S", (config_dotasknum?FileTitleNum:FileTitle), app_name);
+ draw_playicon(1);
+}
+
+/* -------- Pausing -------- */
+void PausePlaying()
+{
+ if (!playing || paused) return ;
+
+ paused = 1;
+ in_pause(1);
+
+ Skin_OnPause();
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_STATUS, IPC_CB_MISC);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_PAUSE, IPC_CB_MISC);
+
+ MediaCoreCOM *mediaCore;
+ if (SUCCEEDED(JSAPI1_GetMediaCoreCOM(&mediaCore)))
+ {
+ mediaCore->OnPause();
+ mediaCore->Release();
+ }
+
+ JSAPI2::callbackManager.OnPause(true);
+}
+
+void UnPausePlaying()
+{
+ if (!playing || !paused) return ;
+
+ in_pause(0);
+ paused = 0;
+
+ Skin_OnUnpause();
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_STATUS, IPC_CB_MISC);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_UNPAUSE, IPC_CB_MISC);
+
+ MediaCoreCOM *mediaCore = 0;
+ if (SUCCEEDED(JSAPI1_GetMediaCoreCOM(&mediaCore)) && mediaCore)
+ {
+ mediaCore->OnResume();
+ mediaCore->Release();
+ }
+
+ JSAPI2::callbackManager.OnPause(false);
+}
+
+
+void PlayThing(const char *thing, int clearlist)
+{
+}
+
+void BeginPlayback()
+{
+ PlayList_setposition(0);
+ if (config_shuffle)
+ PlayList_randpos( -BIGINT);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+} \ No newline at end of file
diff --git a/Src/Winamp/PlayList.cpp b/Src/Winamp/PlayList.cpp
new file mode 100644
index 00000000..c2659066
--- /dev/null
+++ b/Src/Winamp/PlayList.cpp
@@ -0,0 +1,2126 @@
+#include "Main.h"
+#include <assert.h>
+#include "MoreItems.h"
+#include "AdData.h"
+#include "../nu/AutoLock.h"
+#include "strutil.h"
+#include "../nu/AutoCharFn.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+#include "../nu/ns_wc.h"
+#include "WinampPlaylist.h"
+#include <algorithm>
+#include "api.h"
+
+#include "../WAT/WAT.h"
+
+using namespace Nullsoft::Utility;
+
+LockGuard playlistGuard(512);
+
+#define MALLOC_CHUNK 512
+
+static int _lastlen = -1;
+extern "C"
+{
+ static wchar_t *_plstring_wcsdup( const wchar_t *str )
+ {
+ if ( !str )
+ return 0;
+
+ size_t len = wcslen( str );
+ size_t *self = (size_t *)malloc( sizeof( size_t ) + ( len + 1 ) * sizeof( wchar_t ) );
+ *self = 1;
+ wchar_t *new_str = (wchar_t *)( ( (int8_t *)self ) + sizeof( size_t ) );
+ memcpy( new_str, str, ( len + 1 ) * sizeof( wchar_t ) );
+
+ return new_str;
+ }
+
+ static wchar_t *_plstring_malloc( size_t str_size )
+ {
+ size_t *self = (size_t *)malloc( sizeof( size_t ) + ( str_size ) );
+ *self = 1;
+ wchar_t *new_str = (wchar_t *)( ( (int8_t *)self ) + sizeof( size_t ) );
+
+ return new_str;
+ }
+
+ static void _plstring_release( wchar_t *str )
+ {
+ if ( str )
+ {
+ size_t *self = (size_t *)( ( (int8_t *)str ) - sizeof( size_t ) );
+ ( *self )--;
+ if ( *self == 0 )
+ {
+ free( self );
+ }
+ }
+ }
+
+ static void _plstring_retain( wchar_t *str )
+ {
+ if ( str )
+ {
+ size_t *self = (size_t *)( ( (int8_t *)str ) - sizeof( size_t ) );
+ ( *self )++;
+ }
+ }
+
+ __declspec( dllexport ) wchar_t *( *plstring_wcsdup )( const wchar_t *str ) = _plstring_wcsdup;
+ __declspec( dllexport ) wchar_t *( *plstring_malloc )( size_t str_size ) = _plstring_malloc;
+ __declspec( dllexport ) void ( *plstring_release )( wchar_t *str ) = _plstring_release;
+ __declspec( dllexport ) void ( *plstring_retain )( wchar_t *str ) = _plstring_retain;
+}
+
+static bool ndestring_tried_load = false;
+
+void plstring_init()
+{
+ if ( !ndestring_tried_load )
+ {
+ wchar_t path[ MAX_PATH ] = { 0 };
+ PathCombineW( path, SHAREDDIR, L"nde.dll" );
+
+ HMODULE ndelib = LoadLibraryW( path );
+ if ( ndelib )
+ {
+ FARPROC ndestring_wcsdup = GetProcAddress( ndelib, "ndestring_wcsdup" );
+ FARPROC ndestring_malloc = GetProcAddress( ndelib, "ndestring_malloc" );
+ FARPROC ndestring_release = GetProcAddress( ndelib, "ndestring_release" );
+ FARPROC ndestring_retain = GetProcAddress( ndelib, "ndestring_retain" );
+
+ if ( ndestring_wcsdup && ndestring_malloc && ndestring_release && ndestring_retain )
+ {
+ *(FARPROC *)&plstring_wcsdup = ndestring_wcsdup;
+ *(FARPROC *)&plstring_malloc = ndestring_malloc;
+ *(FARPROC *)&plstring_release = ndestring_release;
+ *(FARPROC *)&plstring_retain = ndestring_retain;
+ }
+ }
+
+ ndestring_tried_load = true;
+ }
+}
+
+#define CHECK_STUFF()
+/* { \
+if (list_pos >= list_size && list_size>0) { MessageBox(NULL,"SHIT2!","a",0); } \
+if (list_size > malloced_size) MessageBox(NULL,"SHIT!","a",0); }
+*/
+static void Playlist_notifyModified();
+
+struct pl_entry
+{
+ pl_entry();
+
+ void Free();
+ void Create( int length, const wchar_t *filename, const wchar_t *title, const char *curtain, const wchar_t *ext, int is_nde_string = 0 );
+ void CreateMore( int length, const wchar_t *filename, const wchar_t *title, const char *curtain/*, const char *browser*/ );
+ void SetTitle( const wchar_t *title );
+ void SetFile( const wchar_t *file );
+
+ wchar_t *strFile = 0; // file name oct-17-2005-maksim
+ wchar_t *strTitle = 0; // title oct-17-2005-maksim
+ wchar_t *strExt = 0;
+ size_t cbTitle = 0; // title length oct-17-2005-maksim
+ int length = 0;
+ int8_t selected:1;
+ int8_t cached:1;
+ int8_t tmp:1;
+ int more = 0; // number of subitems in the playlist (or 0 for none) mar-16-2005-benski
+ int curitems = 0; // number of hidden items in this entry
+ int curindex = 0; // Current index of item we're playing (0 for 1st/none hidden item)
+ int repeatCount = 0; // number of times to repeat
+ int repeatCurrent = 0; // where we're at...
+ unsigned long starttime = 0; // Start time in MS (0, begin of file)
+ unsigned long endtime = 0; // End time in MS (0, end of file)
+ moreitems *moreStuff = NULL; // added for subitems in a playlist mar-16-2005-benski
+ ad_data *ads = NULL; // advertisement struct oct-17-2005-maksim
+};
+
+void pl_entry::Free()
+{
+ more = 0;
+ if ( moreStuff )
+ {
+ delete moreStuff;
+ moreStuff = NULL;
+ }
+
+ if ( ads )
+ {
+ delete ads;
+ ads = 0;
+ }
+
+ plstring_release( strFile );
+ strFile = 0;
+
+ plstring_release( strExt );
+ strExt = 0;
+
+ plstring_release( strTitle );
+ strTitle = 0;
+
+ cbTitle = 0;
+}
+
+pl_entry::pl_entry()
+{}
+
+void pl_entry::Create( int length, const wchar_t *filename, const wchar_t *title, const char *curtain, const wchar_t *ext, int is_nde_string )
+{
+ assert( filename );
+ assert( title );
+
+ if ( is_nde_string & 1 )
+ {
+ strFile = plstring_wcsdup( filename );
+ }
+ else
+ {
+ while ( filename && *filename && IsCharSpaceW( *filename ) )
+ filename = CharNextW( filename );
+
+ strFile = plstring_wcsdup( filename );
+
+ wchar_t *end = GetLastCharacterW( strFile );
+ while ( end && IsCharSpaceW( *end ) )
+ {
+ *end = 0;
+ end = CharPrevW( strFile, end );
+ }
+ }
+
+ cbTitle = wcslen( title ) + 1;
+ strTitle = _wcsdup( title );
+
+ if ( ext && *ext )
+ strExt = _wcsdup( ext );
+
+ if ( ( curtain && curtain[ 0 ] ) /*|| (browser && browser[0])*/ )
+ {
+ ads = new ad_data;
+ if ( curtain && curtain[ 0 ] != 0 )
+ {
+ ads->cbCurtain = (int)strlen( curtain ) + 1;
+ ads->strCurtain = new char[ ads->cbCurtain ];
+ StringCchCopyA( ads->strCurtain, ads->cbCurtain, curtain );
+ }
+ }
+ else
+ {
+ ads = NULL;
+ }
+
+ this->length = length;
+ selected = 0;
+ cached = 1;
+ more = 0;
+ curindex = 0;
+ curitems = 0;
+ moreStuff = NULL;
+ repeatCount = 0;
+ repeatCurrent = 0;
+}
+
+void pl_entry::CreateMore( int length, const wchar_t *filename, const wchar_t *title, const char *curtain/*, const char *browser*/ )
+{
+ Create( length, filename, title, curtain, L""/*, browser*/);
+
+ more = 1;
+ moreStuff = new moreitems;
+}
+
+void pl_entry::SetTitle( const wchar_t *title )
+{
+ size_t newSize = wcslen( title ) + 1;
+ if ( newSize > cbTitle )
+ {
+ delete[] strTitle;
+ strTitle = new wchar_t[ newSize ];
+ }
+
+ cbTitle = newSize;
+ StringCchCopyW( strTitle, cbTitle, title );
+}
+
+void pl_entry::SetFile( const wchar_t *file )
+{
+ plstring_release( strFile );
+
+ while ( file && *file && IsCharSpaceW( *file ) )
+ file = CharNextW( file );
+
+ strFile = plstring_wcsdup( file );
+
+ wchar_t *end = GetLastCharacterW( strFile );
+ while ( end && IsCharSpaceW( *end ) )
+ {
+ *end = 0;
+ end = CharPrevW( strFile, end );
+ }
+}
+
+static pl_entry *list = 0;
+static int list_size = 0;
+static int list_pos = 0;
+static int malloced_size = 0;
+
+static pl_entry *tlist = 0;
+static int t_len = 0;
+
+static int rnd_listmodified = 1;
+static int rnd_lastls = -1023;
+static int rnd_i = 0;
+static int *rnd_rtable;
+
+extern "C"
+{
+ int PlayList_get_lastlen()
+ {
+ return _lastlen;
+ }
+
+ static void Playlist_rnd_deleteitem(int item);
+ static void Playlist_rnd_additem();
+ wchar_t *remove_urlcodesW(wchar_t *p)
+ {
+ assert(p);
+
+ if (!config_fixtitles)
+ return p;
+
+ wchar_t buf[FILENAME_SIZE] = {0}, *i = buf, *p2 = p;
+
+ StringCchCopyW(buf, FILENAME_SIZE, p);
+ while (i && *i)
+ {
+ if (*i == L'_' && (config_fixtitles&2))
+ {
+ *p = L' ';
+ i = CharNextW(i);
+ }
+ else if (!StrCmpNW(i, L"%20", 3) && (config_fixtitles&1))
+ {
+ *p = L' ';
+ i += 3;
+ }
+ else
+ {
+ CopyCharW(p, i);
+ i = CharNextW(i);
+ }
+
+ p = CharNextW(p);
+ }
+
+ *p = 0;
+
+ return p2;
+ }
+
+ static void PlayList_allocmem(int newsize);
+
+ void PlayList_resetcurrent( void )
+ {
+ AutoLock lock( playlistGuard );
+ if ( list_pos < 0 || list_pos >= list_size )
+ return;
+
+ if ( list )
+ list[ list_pos ].curindex = 0;
+ }
+
+ void PlayList_saveend( int start )
+ {
+ AutoLock lock( playlistGuard );
+ if ( tlist )
+ {
+ // scan and remove subitems in a playlist mar-16-2005-benski
+ for ( int i = 0; i < t_len; i++ )
+ tlist[ i ].Free();
+
+ delete[] tlist;
+ tlist = 0;
+ }
+
+ if ( start < list_size )
+ {
+ t_len = ( list_size - start );
+ assert( t_len > 0 );
+ tlist = new pl_entry[ t_len ];
+ memcpy( tlist, list + start, sizeof( pl_entry ) * t_len );
+ list_size = start;
+ }
+ }
+
+ void PlayList_restoreend( void )
+ {
+ AutoLock lock( playlistGuard );
+ if ( tlist )
+ {
+ if ( t_len )
+ {
+ PlayList_allocmem( list_size + t_len );
+ memcpy( list + list_size, tlist, t_len * sizeof( pl_entry ) );
+ list_size += t_len;
+ }
+
+ delete[] tlist; // note: we *don't* want to clean up the moreStuff linked list here
+ tlist = NULL;
+ t_len = 0;
+ }
+ }
+
+ int PlayList_getselect( int x )
+ {
+ AutoLock lock( playlistGuard );
+ if ( x < 0 || x >= list_size )
+ return 0;
+
+ CHECK_STUFF();
+
+ return list[ x ].selected;
+ }
+
+ int PlayList_getselect2( int x, wchar_t *filename )
+ {
+ AutoLock lock( playlistGuard );
+ if ( x < 0 || x >= list_size )
+ return 0;
+
+ CHECK_STUFF();
+
+ if ( filename )
+ lstrcpynW( filename, list[ x ].strFile, FILENAME_SIZE );
+
+ return list[ x ].selected;
+ }
+
+ int PlayList_GetNextSelected( int start )
+ {
+ AutoLock lock( playlistGuard );
+ start++;
+ if ( start < 0 || start >= list_size )
+ return -1;
+
+ while ( start < list_size )
+ {
+ if ( list[ start ].selected )
+ return start;
+
+ start++;
+ }
+
+ return -1;
+ }
+
+ int PlayList_GetSelectedCount()
+ {
+ AutoLock lock( playlistGuard );
+ int num = 0;
+ for ( int i = 0; i < list_size; i++ )
+ {
+ if ( list[ i ].selected )
+ num++;
+ }
+
+ return num;
+ }
+
+ void PlayList_setselect( int x, int sel )
+ {
+ AutoLock lock( playlistGuard );
+ if ( x < 0 || x >= list_size )
+ return;
+
+ CHECK_STUFF();
+
+ list[ x ].selected = sel;
+ }
+
+ int PlayList_getcached( int x )
+ {
+ AutoLock lock( playlistGuard );
+ if ( x < 0 || x >= list_size )
+ return 0;
+
+ CHECK_STUFF();
+
+ return list[ x ].cached;
+ }
+
+ void PlayList_setcached( int x, int cached )
+ {
+ AutoLock lock( playlistGuard );
+ if ( x < 0 || x >= list_size )
+ return;
+
+ CHECK_STUFF();
+
+ list[ x ].cached = cached;
+ }
+
+ int PlayList_getsonglength( int x )
+ {
+ AutoLock lock( playlistGuard );
+ if ( x < 0 || x >= list_size )
+ return -1;
+
+ CHECK_STUFF();
+
+ return list[ x ].length;
+ }
+
+ int PlayList_gettotallength( void )
+ {
+ AutoLock lock( playlistGuard );
+ int l = 0;
+
+ CHECK_STUFF();
+
+ for ( int x = 0; x < list_size; x++ )
+ {
+ if ( list[ x ].length >= 0 )
+ l += list[ x ].length;
+ else
+ return -1;
+ }
+
+ return l;
+ }
+
+ int PlayList_getcurrentlength( void )
+ {
+ AutoLock lock( playlistGuard );
+ return ( PlayList_getsonglength( list_pos ) );
+ }
+
+ static void PlayList_allocmem( int newsize )
+ {
+ assert( newsize );
+
+ int os = malloced_size;
+
+ if ( newsize > malloced_size )
+ malloced_size = newsize + MALLOC_CHUNK;
+ else if ( newsize < malloced_size - MALLOC_CHUNK )
+ malloced_size = newsize;
+ else return;
+
+ if ( !malloced_size )
+ {
+ if ( list )
+ {
+ delete[] list;
+ list = 0;
+ }
+ }
+ else if ( list )
+ {
+ pl_entry *ol = list;
+
+ assert( malloced_size > 0 );
+
+ list = new pl_entry[ malloced_size ];
+
+ assert( min( os, malloced_size ) > 0 );
+ assert( min( os, malloced_size ) <= malloced_size );
+
+ memcpy( list, ol, min( os, malloced_size ) * sizeof( pl_entry ) );
+ delete[] ol;
+ }
+ else
+ {
+ assert( malloced_size > 0 );
+ list = new pl_entry[ malloced_size ];
+ memset( list, 0, sizeof( pl_entry ) * ( malloced_size ) );
+ }
+ }
+
+ int PlayList_gethidden( int pos )
+ {
+ AutoLock lock( playlistGuard );
+ if ( pos < 0 || pos >= list_size )
+ return 0;
+
+ if ( list )
+ return list[ pos ].curitems;
+ else
+ return 0;
+ }
+
+ int PlayList_ishidden( int pos )
+ {
+ AutoLock lock( playlistGuard );
+ if ( pos < 0 || pos >= list_size )
+ return 0;
+
+ if ( list )
+ if ( list[ pos ].curitems )
+ {
+ if ( list[ pos ].curindex != list[ pos ].curitems )
+ return 1;
+ }
+
+ return 0;
+ }
+
+ int PlayList_alldone( int pos )
+ {
+ AutoLock lock( playlistGuard );
+ if ( pos < 0 || pos >= list_size )
+ return 1;
+
+ if ( list )
+ {
+ if ( list[ pos ].curitems )
+ {
+ if ( list[ pos ].curindex == 0 )
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ int PlayList_hasanycurtain( int pos )
+ {
+ AutoLock lock( playlistGuard );
+ if ( pos < 0 || pos >= list_size )
+ return 0;
+
+ if ( list )
+ {
+ if ( list[ pos ].ads && list[ pos ].ads->strCurtain )
+ return 1;
+ }
+
+ return 0;
+ }
+
+ const char *PlayList_getcurtain( int pos )
+ {
+ AutoLock lock( playlistGuard );
+ if ( pos < 0 || pos >= list_size )
+ return NULL;
+
+ if ( list )
+ {
+ if ( list[ pos ].ads && list[ pos ].ads->strCurtain && list[ pos ].curindex == 0 )
+ return list[ pos ].ads->strCurtain;
+
+ if ( list[ pos ].curindex && list[ pos ].curitems )
+ return list[ pos ].moreStuff->GetHiddenCurtain( list[ pos ].curindex );
+ }
+
+ return NULL;
+ }
+
+ const char *PlayList_getExtInf( int pos )
+ {
+ AutoLock lock( playlistGuard );
+
+ if ( pos < 0 || pos >= list_size )
+ return NULL;
+
+ if ( list )
+ {
+ pl_entry l_entry = list[ pos ];
+
+ if ( l_entry.strExt && *l_entry.strExt )
+ {
+ wa::strings::wa_string l_ext_inf( " ext=\"" );
+ l_ext_inf.append( l_entry.strExt );
+ l_ext_inf.append( "\"" );
+
+ return _strdup( l_ext_inf.GetA().c_str() );
+ }
+ }
+
+ return NULL;
+ }
+
+ /*
+ const char *PlayList_getbrowser(int pos)
+ {
+ AutoLock lock (playlistGuard);
+ if (pos < 0 || pos >= list_size) return NULL;
+ if ( list )
+ {
+ if ( list[pos].ads && list[pos].ads->cbBrowser ) return list[pos].ads->strBrowser;
+ }
+ return NULL;
+ }
+ */
+
+ int PlayList_current_hidden( void )
+ {
+ AutoLock lock( playlistGuard );
+ if ( list_pos < 0 || list_pos >= list_size )
+ return 0;
+
+ if ( list && list[ list_pos ].curitems )
+ {
+ if ( list[ list_pos ].curitems && list[ list_pos ].curindex < list[ list_pos ].curitems )
+ {
+ list[ list_pos ].curindex++;
+
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ int PlayList_getitem( int position, wchar_t *filename, wchar_t *filetitle )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list || position < 0 || position >= list_size )
+ return 1;
+
+ CHECK_STUFF();
+
+ if ( filename )
+ StringCchCopyW( filename, FILENAME_SIZE, list[ position ].strFile );
+
+ if ( filetitle )
+ StringCchPrintfW( filetitle, FILETITLE_SIZE, L"%d. %s", position + 1, list[ position ].strTitle );
+
+ if ( list[ position ].length >= 0 )
+ {
+ wchar_t tmp[ 512 ] = { 0 };
+ StringCchPrintfW( tmp, 512, L" - [%d:%02d]", list[ position ].length / 60, list[ position ].length % 60 );
+ if ( filetitle )
+ StringCchCatW( filetitle, FILETITLE_SIZE, tmp );
+ }
+
+ return 0;
+ }
+
+ /* this function call specifically has 256 characters max because of the data structure in ipc_pe.h (fileinfo2) */
+ int PlayList_getitem3( int position, char *filetitle, char *filelength )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list || position < 0 || position >= list_size )
+ return 1;
+
+ CHECK_STUFF();
+
+ if ( filetitle )
+ WideCharToMultiByteSZ( CP_ACP, 0, list[ position ].strTitle, -1, filetitle, 256, 0, 0 );
+
+ if ( filelength && list[ position ].length >= 0 )
+ StringCchPrintfA( filelength, 16, "%d:%02d", list[ position ].length / 60, list[ position ].length % 60 );
+
+ return 0;
+ }
+
+ /* this function call specifically has 256 characters max because of the data structure in ipc_pe.h (fileinfo2) */
+ int PlayList_getitem3W( int position, wchar_t *filetitle, wchar_t *filelength )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list || position < 0 || position >= list_size )
+ return 1;
+
+ CHECK_STUFF();
+
+ if ( filetitle )
+ lstrcpynW( filetitle, list[ position ].strTitle, 256 );
+
+ if ( filelength && list[ position ].length >= 0 )
+ StringCchPrintfW( filelength, 16, L"%d:%02d", list[ position ].length / 60, list[ position ].length % 60 );
+
+ return 0;
+ }
+
+ void PlayList_updateitem( int position )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list || position < 0 || position >= list_size )
+ return;
+
+ _lastlen = -1;
+
+ wchar_t *str = remove_urlcodesW( PlayList_gettitle( list[ position ].strFile, 1 ) );
+ list[ position ].SetTitle( str );
+ PlayList_setcached( position, 1 );
+
+ if ( _lastlen != -1 )
+ list[ position ].length = _lastlen;
+ }
+
+ int PlayList_getitem_pl( int position, wchar_t *filetitle )
+ {
+ AutoLock lock( playlistGuard );
+ // static int i;
+ CHECK_STUFF();
+ if ( !list || position < 0 || position >= list_size )
+ return 1;
+ /*
+ if (!PlayList_getcached(position) && config_riol==0 && !i)
+ {
+ i=1;
+ _lastlen=-1;
+ lstrcpy(list[position].filetitle,remove_urlcodes(PlayList_gettitle(list[position].filename,1)));
+ PlayList_setcached(position,1);
+ if (_lastlen != -1) list[position].length = _lastlen;
+ i=0;
+ }
+ */
+
+ if ( filetitle && config_shownumsinpl )
+ {
+ if ( list_size >= 10000 )
+ StringCchPrintfW( filetitle, FILETITLE_SIZE, ( config_zeropadplnum ? L"%05u. %s" : L"%5u. %s" ), position + 1, list[ position ].strTitle );
+ else if ( list_size >= 1000 )
+ StringCchPrintfW( filetitle, FILETITLE_SIZE, ( config_zeropadplnum ? L"%04u. %s" : L"%4u. %s" ), position + 1, list[ position ].strTitle );
+ else if ( list_size >= 100 )
+ StringCchPrintfW( filetitle, FILETITLE_SIZE, ( config_zeropadplnum ? L"%03u. %s" : L"%3u. %s" ), position + 1, list[ position ].strTitle );
+ else if ( list_size >= 10 )
+ StringCchPrintfW( filetitle, FILETITLE_SIZE, ( config_zeropadplnum ? L"%02u. %s" : L"%2u. %s" ), position + 1, list[ position ].strTitle );
+ else
+ StringCchPrintfW( filetitle, FILETITLE_SIZE, L"%1u. %s", position + 1, list[ position ].strTitle );
+ }
+ else if ( filetitle )
+ StringCchCopyW( filetitle, FILETITLE_SIZE, list[ position ].strTitle );
+
+ return 0;
+ }
+
+ int PlayList_getitem2( int position, char *filename, char *filetitle )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list || position < 0 || position >= list_size )
+ return 1;
+
+ CHECK_STUFF();
+
+ if ( filename )
+ StringCchCopyA( filename, FILENAME_SIZE, AutoCharFn( list[ position ].strFile ) );
+
+ if ( filetitle )
+ WideCharToMultiByteSZ( CP_ACP, 0, list[ position ].strTitle, -1, filetitle, FILETITLE_SIZE, 0, 0 );
+
+ return 0;
+ }
+
+ int PlayList_getitem2W( int position, wchar_t *filename, wchar_t *filetitle )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list || position < 0 || position >= list_size )
+ return 1;
+
+ CHECK_STUFF();
+
+ if ( filename )
+ {
+ if ( list[ position ].strFile )
+ StringCchCopyW( filename, FILENAME_SIZE, list[ position ].strFile );
+ else
+ return 1;
+ }
+
+ if ( filetitle )
+ {
+ if ( list[ position ].strTitle )
+ StringCchCopyW( filetitle, FILETITLE_SIZE, list[ position ].strTitle );
+ else
+ return 1;
+ }
+
+ return 0;
+ }
+
+ int PlayList_getitem_jtfW( int position, wchar_t *str )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list || position < 0 || position >= list_size )
+ return 1;
+
+ CHECK_STUFF();
+
+ StringCchPrintfW( str, FILENAME_SIZE + FILETITLE_SIZE + 1, L"%s %s", list[ position ].strFile, list[ position ].strTitle );
+
+ return 0;
+ }
+
+ int PlayList_getlength( void )
+ {
+ AutoLock lock( playlistGuard );
+ return list_size;
+ }
+
+ int plmodified = 0, plcleared = 0, plneedsave = 0;
+
+ int g_has_deleted_current;
+ // returns:
+ // 1, last item in list
+ // 0 not
+ // -1 no items in list
+ int PlayList_deleteitem( int item )
+ {
+ AutoLock lock( playlistGuard );
+ if ( !list ) return -1;
+ CHECK_STUFF();
+ if ( item < 0 || item >= list_size ) return -1;
+
+ list[ item ].Free();
+
+ list_size--;
+ if ( list_size != item )
+ memmove( list + item, list + item + 1, sizeof( list[ 0 ] ) * ( list_size - item ) );
+ if ( item == list_pos )
+ g_has_deleted_current = 1;
+
+ if ( item <= list_pos )
+ list_pos--;
+
+ if ( list_pos < 0 ) list_pos = 0;
+
+ PlayList_allocmem( list_size + 1 );
+ Playlist_notifyModified();
+ Playlist_rnd_deleteitem( item );
+
+ return list ? 0 : 1;
+ }
+
+ void PlayList_delete( void )
+ {
+ AutoLock lock( playlistGuard );
+
+ CHECK_STUFF();
+
+ //if (GetPrivateProfileIntW(L"Winamp", L"rmudhack", 0, INI_FILE) == 666) return ;
+
+ if ( list )
+ {
+ // code to cleanup subitems in a playlist entry mar-16-2005-benski
+ for ( int i = 0; i < list_size; i++ )
+ list[ i ].Free();
+
+ // delete[] list;
+ }
+
+ // list=0;
+ list_size = 0;
+ list_pos = 0;
+ plcleared = 1;
+ // malloced_size=0;
+
+ Playlist_notifyModified();
+ }
+
+ void PlayList_destroy(void)
+ {
+ AutoLock lock (playlistGuard);
+ PlayList_delete();
+ delete[] list;
+ list = 0;
+ }
+
+ void PlayList_setlastlen(int x)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ if (x >= 0 && x < list_size) list[x].length = _lastlen;
+ }
+
+ static wchar_t *GetFileInfo(const wchar_t *filename, wchar_t *title, size_t titleCch)
+ {
+ In_Module *mod = in_setmod_noplay(filename, 0);
+ _lastlen = -1;
+ if (!mod)
+ {
+ StringCchCopyW(title, GETFILEINFO_TITLE_LENGTH, filename);
+ return title;
+ }
+ InW_GetFileInfo(mod, (filename == FileName) ? 0 : filename, title, &_lastlen);
+ if (!title[0])
+ {
+ StringCchCopyW(title, titleCch, filename);
+ if (!PathIsURLW(filename))
+ {
+ PathStripPathW(title);
+ PathRemoveExtensionW(title);
+ }
+ }
+
+ if (_lastlen != -1) _lastlen /= 1000;
+ return 0;
+ }
+
+ static wchar_t *GetExtendedTitle( const wchar_t *filename, wchar_t *title, size_t titleCch, bool active = false )
+ {
+ AutoCharFn narrowFile( filename );
+ // make sure the title is inited otherwise it'll be filled/set with rubbish noticeable
+ // on 5.3+ due to nothing internally using this api now and a retval = 1 done for it
+ // basically for 3rd party/legacy handling now - 13 May 07
+ char narrowTitle[ GETFILEINFO_TITLE_LENGTH ] = { 0 };
+ waHookTitleStruct hts = { 0 };
+ hts.filename = narrowFile;
+ hts.length = -1;
+ hts.title = narrowTitle;
+
+ if ( PathIsURLW( filename ) )
+ {
+ wchar_t buf[ 32 ] = { 0 };
+ extendedFileInfoStructW s = { filename, L"streammetadata", buf, sizeof( buf ) / sizeof( wchar_t ) };
+
+ if ( 0 != SendMessageW( hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE ) && L'1' == buf[ 0 ] )
+ {
+ hts.force_useformatting = 1;
+ }
+ }
+
+ /*
+ wchar_t buf[32]=L"";
+ if (PathIsURLW(filename) && in_get_extended_fileinfoW(filename, L"streammetadata", buf, sizeof(buf)/sizeof(wchar_t)) && buf[0]=='1')
+ hts.force_useformatting = 1;
+ */
+
+ if ( config_useexttitles && SendMessageW( hMainWindow, WM_WA_IPC, (WPARAM)&hts, IPC_HOOK_TITLES ) )
+ {
+ MultiByteToWideCharSZ( CP_ACP, 0, narrowTitle, -1, title, (int)titleCch );
+ if ( hts.length != -1 )
+ {
+ _lastlen = hts.length;
+ return title;
+ }
+ else
+ {
+ In_Module *mod = in_setmod_noplay( filename, 0 );
+ _lastlen = -1;
+ if ( mod )
+ {
+ wchar_t title2[ GETFILEINFO_TITLE_LENGTH ] = { 0 };
+ InW_GetFileInfo( mod, filename, title2, &_lastlen );
+ }
+ if ( _lastlen != -1 ) _lastlen /= 1000;
+ }
+ return title;
+ }
+ return 0;
+ }
+
+ static wchar_t *GetExtendedTitleW(const wchar_t *filename, wchar_t *title, size_t titleCch, bool active=false)
+ {
+ waHookTitleStructW hts = {0};
+ hts.filename = filename;
+ hts.length = -1;
+ hts.title = title;
+
+ if (PathIsURLW(filename))
+ {
+ wchar_t buf[32] = {0};
+ extendedFileInfoStructW s = {filename, L"streammetadata", buf, sizeof(buf)/sizeof(wchar_t)};
+
+ if (0 != SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE) &&
+ L'1' == buf[0])
+ {
+ hts.force_useformatting = 1;
+ }
+ }
+
+ /*
+ wchar_t buf[32]=L"";
+ if (PathIsURLW(filename) && in_get_extended_fileinfoW(filename, L"streammetadata", buf, 32) && buf[0]=='1')
+ hts.force_useformatting = 1;
+
+ */
+
+ if (config_useexttitles && SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&hts, IPC_HOOK_TITLESW))
+ {
+ if (hts.length != -1)
+ {
+ _lastlen = hts.length;
+ return title;
+ }
+ else
+ {
+ In_Module *mod = in_setmod_noplay(filename, 0);
+ _lastlen = -1;
+ if (mod)
+ {
+ wchar_t title2[GETFILEINFO_TITLE_LENGTH] = {0};
+ InW_GetFileInfo(mod, filename, title2, &_lastlen);
+ }
+ if (_lastlen != -1) _lastlen /= 1000;
+ }
+ return title;
+ }
+ return 0;
+ }
+
+ wchar_t *PlayList_gettitle(const wchar_t *filename, int useID3)
+ {
+ /* OK, this function is going to get ugly */
+ AutoLock lock (playlistGuard);
+ static wchar_t title[GETFILEINFO_TITLE_LENGTH] = {0};
+ CHECK_STUFF();
+ if (useID3 || (filename[0] && !StrCmpIW(PathFindExtensionW(filename), L"aip")))
+ {
+ if (filename[0])
+ {
+ wchar_t *ret = GetExtendedTitle(filename, title, GETFILEINFO_TITLE_LENGTH);
+ if (ret)
+ return ret;
+ else
+ {
+ ret = GetExtendedTitleW(filename, title, GETFILEINFO_TITLE_LENGTH);
+ if (ret)
+ return ret;
+ else
+ {
+ ret = GetFileInfo(filename, title, GETFILEINFO_TITLE_LENGTH);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ else
+ {
+ wchar_t *ret = GetExtendedTitle(FileName, title, GETFILEINFO_TITLE_LENGTH, true);
+ if (ret)
+ return ret;
+
+ else
+ {
+ ret = GetExtendedTitleW(FileName, title, GETFILEINFO_TITLE_LENGTH, true);
+ if (ret)
+ return ret;
+ else
+ {
+ ret = GetFileInfo(FileName, title, GETFILEINFO_TITLE_LENGTH);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ }
+ else
+ {
+ _lastlen = -1;
+ if (filename[0] && PathIsURLW(filename))
+ {
+ if (title) StringCchCopyW(title, GETFILEINFO_TITLE_LENGTH, filename);
+ }
+ else if (title)
+ {
+ wchar_t buf[1024] = {0};
+ StringCchCopyW(buf, 1024, filename);
+ StringCchCopyW(title, GETFILEINFO_TITLE_LENGTH, PathFindFileNameW(buf));
+ PathRemoveExtensionW(title);
+ }
+ }
+ return title;
+ }
+
+ void PlayList_append_withinfo_curtain(const wchar_t *filename, const wchar_t *title, int length, char *curtain, const wchar_t *ext, int is_nde_string)
+ {
+ AutoLock lock (playlistGuard);
+ bool cached = true;
+ wchar_t fn[FILENAME_SIZE] = {0};
+ CHECK_STUFF();
+ if (!(is_nde_string & 1) && !PathIsURLW(filename))
+ {
+ if (wcsstr(fn, L"\\"))
+ {
+ int ret = GetLongPathNameW(filename, fn, FILENAME_SIZE);
+ if (ret && ret < FILENAME_SIZE)
+ filename=fn;
+ }
+ }
+
+ if (!title)
+ {
+ title = remove_urlcodesW(PlayList_gettitle(filename, (config_riol == 1 ? 1 : 0)));
+ // changed 5.64 - if we have a length but no title, use the length and build the title
+ if (length < 0)
+ {
+ _lastlen = -1;
+ // added post 5.65 to ensure read on loading will work
+ // after some of the other changes made in 5.64 / 5.65
+ if (config_riol == 1)
+ {
+ In_Module *mod = in_setmod_noplay(filename, 0);
+ if (mod)
+ {
+ wchar_t title2[GETFILEINFO_TITLE_LENGTH] = {0};
+ InW_GetFileInfo(mod, filename, title2, &_lastlen);
+ if (_lastlen != -1) _lastlen /= 1000;
+ }
+ }
+ }
+ length = _lastlen;
+ cached = config_riol == 1;
+ }
+
+ if (list_size && list[list_size - 1].more)
+ {
+ // We have the final item to add to the last index
+ // Add it to the more items list
+ // Reset more flag
+ // and do not adjust the list_size;
+ list[list_size - 1].moreStuff->AddHiddenItem(filename, title, length, list[list_size - 1].more, curtain);
+ list[list_size - 1].curitems = list[list_size - 1].more;
+ list[list_size - 1].curindex = 0;
+ list[list_size - 1].more = 0;
+ }
+ else
+ {
+ PlayList_allocmem(list_size + 1);
+ if (list_pos == -1)
+ list_pos = 0;
+ list[list_size].Create(length, filename, title, curtain, ext, is_nde_string);
+ list[list_size].cached = cached ? 1 : 0;
+ Playlist_rnd_additem();
+ list_size++;
+ }
+ Playlist_notifyModified();
+ }
+
+ void PlayList_append_withinfo(const wchar_t *filename, const wchar_t *title, const wchar_t *ext, int length, int is_nde_string)
+ {
+ AutoLock lock (playlistGuard);
+ PlayList_append_withinfo_curtain(filename, title, length, NULL, ext, is_nde_string);
+ }
+
+ void PlayList_append_withinfo_hidden(const wchar_t *filename, const wchar_t *title, int length, char *curtain/*, char *browser*/)
+ {
+ AutoLock lock (playlistGuard);
+ bool cached = true;
+ wchar_t fn[FILENAME_SIZE] = {0};
+ CHECK_STUFF();
+ if (!PathIsURLW(filename))
+ {
+ if (wcsstr(fn, L"\\"))
+ {
+ int ret = GetLongPathNameW(filename, fn, FILENAME_SIZE);
+ if (ret && ret < FILENAME_SIZE)
+ filename=fn;
+ }
+ }
+
+ if (!title)
+ {
+ title = remove_urlcodesW(PlayList_gettitle(filename, (config_riol == 1 ? 1 : 0)));
+ // changed 5.64 - if we have a length but no title, use the length and build the title
+ if (length < 0)
+ {
+ _lastlen = -1;
+ // added post 5.65 to ensure read on loading will work
+ // after some of the other changes made in 5.64 / 5.65
+ if (config_riol == 1)
+ {
+ In_Module *mod = in_setmod_noplay(filename, 0);
+ if (mod)
+ {
+ wchar_t title2[GETFILEINFO_TITLE_LENGTH] = {0};
+ InW_GetFileInfo(mod, filename, title2, &_lastlen);
+ if (_lastlen != -1) _lastlen /= 1000;
+ }
+ }
+ }
+ length = _lastlen;
+ cached = config_riol == 1;
+ }
+
+ if (list_size && list[list_size - 1].more)
+ {
+ // add item with info to more list
+ // increment more flag so another item may be added to the hidden list
+ list[list_size - 1].moreStuff->AddHiddenItem(filename, title, length, list[list_size - 1].more, curtain);
+ list[list_size - 1].more++;
+ }
+ else
+ {
+ // Create a new entry, but set the more flag. so the next item gets added to
+ // more list
+ PlayList_allocmem(list_size + 1);
+ if (list_pos == -1)
+ list_pos = 0;
+ list[list_size].CreateMore(length, filename, title, curtain/*, browser*/);
+ list[list_size].cached = cached ? 1 : 0;
+ Playlist_rnd_additem();
+ list_size++;
+ }
+ Playlist_notifyModified();
+ }
+
+ static void _appendcd(const wchar_t *url)
+ {
+ AutoLock lock (playlistGuard);
+ wchar_t buf2[32] = {0};
+ in_get_extended_fileinfoW(url, L"ntracks", buf2, 32);
+ int n = _wtoi(buf2);
+ if (n > 0 && n < 256)
+ {
+ for (int x = 0; x < n; x ++)
+ {
+ wchar_t s[64] = {0};
+ StringCchPrintfW(s, 64, L"%s,%d",url, x + 1);
+ PlayList_append(s, 0);
+ }
+ }
+ }
+
+ void PlayList_check_unknown(const wchar_t *url, int is_nde_string)
+ {
+ if (!_wcsicmp(extensionW(url), L"")) // no extension, check for pls/m3u signatures
+ {
+ // TODO: move to its own function
+ FILE *fp = _wfopen(url,L"r");
+
+ char buf[21] = {0};
+ if (fp)
+ {
+ fread(buf, 1, 21, fp);
+ fclose(fp);
+ buf[20] = 0;
+ }
+ if (!_strnicmp(buf, "[Reference]", 11))
+ LoadPlaylistByExtension(url, L".asx", 1, 0);
+ else if (!_strnicmp(buf, "[playlist]", 10))
+ LoadPlaylistByExtension(url, L".pls", 1, 0);
+ else if (!memcmp(buf, L"[playlist]", 20))
+ LoadPlaylistByExtension(url, L".pls", 1, 0);
+ else if (!_strnicmp(buf, "#EXTM3U", 7))
+ LoadPlaylistByExtension(url, L".m3u", 1, 0);
+ else if (!_strnicmp(buf, "<ASX", 4))
+ LoadPlaylistByExtension(url, L".asx", 1, 0);
+ else if (!_strnicmp(buf, "<?wpl", 5))
+ LoadPlaylistByExtension(url, L".wpl", 1, 0);
+ else if (!_strnicmp(buf, "<?zpl", 5))
+ LoadPlaylistByExtension(url, L".zpl", 1, 0);
+ else PlayList_append(url, is_nde_string);
+ }
+ else
+ PlayList_append(url, is_nde_string);
+ }
+
+ void PlayList_appendthing(const wchar_t *url, int doMIMEcheck, int is_nde_string)
+ {
+ wchar_t temp2[MAX_PATH] = {0};
+ AutoLock lock (playlistGuard);
+ if (!_wcsicmp(extensionW(url), L"lnk"))
+ {
+ if (ResolveShortCut(hMainWindow, url, temp2))
+ {
+ url = temp2; //StringCchCopy(url, MAX_PATH, temp2);
+ is_nde_string &= ~1;
+ }
+ else
+ return ;
+ }
+
+ if (!_wcsnicmp(url, L"cda://", 6))
+ {
+ if ( wcslen(url) == 7)
+ _appendcd(url);
+ else
+ PlayList_append(url, is_nde_string);
+ }
+ else if (PathIsURLW(url))
+ {
+ if (LoadPlaylist(url, 1, doMIMEcheck) == -1) // if it's not a playlist file
+ PlayList_append(url, is_nde_string);
+ }
+ else if (!lstrcmpW(url + 1, L":\\"))
+ PlayList_adddir(url, 1);
+ else
+ {
+ WIN32_FIND_DATAW d = {0};
+ HANDLE h = FindFirstFileW(url, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ FindClose(h);
+ if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ PlayList_adddir(url, 1);
+ else if (LoadPlaylist(url, 1, 0) == -1) // if it's not a playlist file
+ {
+ PlayList_check_unknown(url, is_nde_string); // no extension, check for pls/m3u signatures
+ }
+ }
+ else
+ PlayList_append(url, is_nde_string);
+ }
+ }
+
+ int PlayList_getrepeatcount(int pos)
+ {
+ AutoLock lock (playlistGuard);
+ if ( list_size )
+ {
+ return list[pos].repeatCount;
+ }
+ else return 0;
+ }
+
+ void PlayList_SetLastItem_RepeatCount(int count)
+ {
+ AutoLock lock (playlistGuard);
+ if ( list_size )
+ {
+ list[list_size -1].repeatCount = count;
+ }
+ }
+
+ void PlayList_SetLastItem_Range(unsigned long start, unsigned long end)
+ {
+ int index = 0;
+
+ if ( list[list_size - 1].curitems ) index = list[list_size - 1].curitems;
+ else if ( list[list_size - 1].more - 1 > 0 ) index = list[list_size - 1].more - 1;
+
+ if ( list_size && index )
+ {
+ list[list_size - 1].moreStuff->SetRange(index, start, end);
+ }
+ else if ( list_size )
+ {
+ list[list_size - 1].starttime = start;
+ list[list_size - 1].endtime = end;
+ }
+ Playlist_notifyModified();
+ }
+
+ unsigned long PlayList_GetItem_Start(int pos)
+ {
+ if (pos >= 0 && pos < list_size)
+ {
+ if ( !list[pos].curindex )
+ return list[pos].starttime;
+ else
+ {
+ return list[pos].moreStuff->GetStart(list[pos].curindex);
+ }
+ }
+ else
+ return 0;
+ }
+
+ unsigned long PlayList_GetItem_End(int pos)
+ {
+ if (pos >= 0 && pos < list_size)
+ {
+ if ( !list[pos].curindex )
+ return list[pos].endtime;
+ else
+ {
+ return list[pos].moreStuff->GetEnd(list[pos].curindex);
+ }
+ }
+ else
+ return 0;
+ }
+
+ void PlayList_terminate_lasthidden(void)
+ {
+ AutoLock lock (playlistGuard);
+ if ( list_size && list[list_size - 1].more )
+ {
+ // Reset more flag
+ // and do not adjust the list_size;
+
+ list[list_size - 1].curitems = list[list_size - 1].more - 1;
+ list[list_size - 1].curindex = 0;
+ list[list_size - 1].more = 0;
+ Playlist_notifyModified();
+ }
+ }
+
+
+ void PlayList_append(const wchar_t *filename, int is_nde_string)
+ {
+ AutoLock lock (playlistGuard);
+ PlayList_append_withinfo_curtain(filename, NULL, 0, NULL, L"", 0);
+ }
+
+ void PlayList_getcurrent_onstop(wchar_t *filename, wchar_t *filetitle)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ if (list_pos >= 0 && list_pos < list_size)
+ {
+ int position = list_pos;
+ if (!PlayList_getcached(position))
+ {
+ _lastlen = -1;
+ wchar_t *str = remove_urlcodesW(PlayList_gettitle(list[position].strFile, 1));
+ list[position].SetTitle(str);
+ PlayList_setcached(position, 1);
+ if (_lastlen != -1)
+ list[position].length = _lastlen;
+ }
+
+ StringCchCopyW(filename, FILENAME_SIZE, list[list_pos].strFile);
+ StringCchCopyW(filetitle, FILETITLE_SIZE, list[list_pos].strTitle);
+ //StringCchPrintfW(filetitle, FILETITLE_SIZE, L"%d. %s", list_pos + 1, list[list_pos].strTitle);
+ }
+ else *filename = *filetitle = 0;
+ }
+
+ void PlayList_GetCurrentTitle(wchar_t *filetitle, int cchLen)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ if (list_pos >= 0 && list_pos < list_size)
+ {
+ StringCchCopyW(filetitle, cchLen, list[list_pos].strTitle);
+ //StringCchPrintfW(filetitle, cchLen, L"%d. %s", list_pos + 1, list[list_pos].strTitle);
+ }
+ else *filetitle = 0;
+ }
+
+ void PlayList_getcurrent(wchar_t *filename, wchar_t *filetitle, wchar_t *filetitlenum)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ if (list_pos >= 0 && list_pos < list_size)
+ {
+ if ( !list[ list_pos ].curindex )
+ {
+ wa::strings::wa_string l_filename( L"" );
+
+ wa::strings::wa_string l_original_filename( list[ list_pos ].strFile );
+
+ if ( list[ list_pos ].strExt && *list[ list_pos ].strExt && l_original_filename.contains( "://" ) )
+ {
+ wa::strings::wa_string l_ext( "." );
+ l_ext.append( list[ list_pos ].strExt );
+ l_ext.toUpper();
+
+ wa::strings::wa_string l_strFile( list[ list_pos ].strFile );
+
+ l_filename.append( "http://client.winamp.com/fileproxy?destination=" );
+ l_filename.append( list[ list_pos ].strFile );
+
+ wa::strings::wa_string l_upper_case_filename( l_strFile.GetW() );
+ l_upper_case_filename.toUpper();
+
+ if ( !l_upper_case_filename.contains( l_ext.GetW() ) )
+ {
+ if ( !l_strFile.contains( "?" ) )
+ l_filename.append( "?" );
+ else
+ l_filename.append( "&" );
+
+ l_filename.append( "ext=" );
+ l_filename.append( l_ext );
+ }
+
+ StringCchCopyW( filename, FILENAME_SIZE, l_filename.GetW().c_str() );
+ }
+ else
+ StringCchCopyW( filename, FILENAME_SIZE, list[ list_pos ].strFile );
+ }
+ else
+ {
+ StringCchCopyW(filename, FILENAME_SIZE, list[list_pos].moreStuff->GetHiddenFilename(list[list_pos].curindex));
+ }
+ StringCchCopyW(filetitle, FILETITLE_SIZE, list[list_pos].strTitle);
+ StringCchPrintfW(FileTitleNum, FILETITLE_SIZE, L"%d. %s", list_pos + 1, list[list_pos].strTitle);
+ }
+ else *filename = *filetitle = 0;
+ }
+
+ void PlayList_setcurrent(const wchar_t *filename, wchar_t *filetitle)
+ {
+ AutoLock lock (playlistGuard);
+ PlayList_setitem(list_pos, filename, filetitle);
+ }
+
+ void PlayList_setitem(int x, const wchar_t *filename, wchar_t *filetitle)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ if (x >= 0 && x < list_size)
+ {
+ list[x].SetFile(filename);
+ // Dont allow update of the title if there is hidden elements
+ if ( !list[x].curitems )
+ {
+ wchar_t *str = remove_urlcodesW(filetitle);
+ list[x].SetTitle(str);
+ }
+ list[x].cached = 1;
+ if (x != list_pos) Playlist_notifyModified();
+ }
+ }
+
+ void PlayList_swap(int e1, int e2)
+ {
+ AutoLock lock (playlistGuard);
+ pl_entry p;
+ if (e1 < 0 || e2 < 0 || e1 >= list_size || e2 >= list_size || e1 == e2) return ;
+ p = list[e1];
+ list[e1] = list[e2];
+ list[e2] = p;
+ Playlist_notifyModified();
+ }
+
+ int PlayList_setposition(int pos)
+ {
+ AutoLock lock (playlistGuard);
+ if (list_pos >= 0 && list_pos < list_size)
+ list[list_pos].curindex = 0;
+
+ list_pos = 0;
+ if (pos >= 0 && pos < list_size)
+ list[pos].curindex = 0;
+
+ return (PlayList_advance(pos));
+ }
+
+ int PlayList_getPosition()
+ {
+ AutoLock lock (playlistGuard); // to let any pending actions finish
+ return list_pos;
+ }
+
+ int PlayList_getNextPosition()
+ {
+ AutoLock lock (playlistGuard); // to let any pending actions finish
+ // rnd
+
+ int pl_len = PlayList_getlength();
+ if (pl_len > 0)
+ {
+ // repeat track is enabled so will be current one
+ if (!config_pladv && config_repeat)
+ {
+ // manual playlist advance is on so should be the current track
+ // (may change but won't unless user does a prev / next action)
+ return list_pos;
+ }
+ else
+ {
+ // shuffle is off so can determine next entry
+ if (!config_shuffle)
+ {
+ // if at the end then loop to the start
+ // otherwise it will be the next entry
+ // butif repeat is off then we don't know
+ return ((list_pos + 1 >= pl_len) ? (!config_repeat ? -1 : 0) : list_pos + 1);
+ }
+ // shuffle is on so need to find out from table
+ else
+ {
+ // keep things in check when at end of table
+ if (!rnd_listmodified && rnd_i >= 0 && rnd_i + 1 != rnd_lastls)
+ {
+ return (rnd_rtable ? rnd_rtable[rnd_i + 1] : 0);
+ }
+ // otherwise if at the end and repeat on go to start
+ else
+ {
+ if(config_repeat)
+ {
+ return (rnd_rtable ? rnd_rtable[0] : 0);
+ }
+ }
+ }
+ }
+ }
+ // if nothing or only one item then default to the first entry
+ else if(!pl_len)
+ {
+ return (!config_repeat ? -1 : 0);
+ }
+
+ // not sure what is the next so fail nicely
+ return -1;
+ }
+
+ int PlayList_advance(int byval)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ if ( byval == HIDDEN_TRAP )
+ {
+ if ( list_size )
+ {
+ // Our hidden trap
+ if ( list[list_pos].curitems && list[list_pos].curindex < list[list_pos].curitems )
+ {
+ list[list_pos].curindex++;
+ return list_pos;
+ }
+ byval = 1;
+ list[list_pos].curindex = 0;
+ if ( list[list_pos].repeatCount && list[list_pos].repeatCurrent++ != list[list_pos].repeatCount )
+ {
+ return list_pos;
+ }
+ list[list_pos].repeatCurrent = 0;
+ }
+ }
+ if (!byval) return list_pos;
+ //if ( list_size && byval != 1 ) for ( x = 0; x < list_size; x++ ) list[x].curindex = 0;
+ //if ( list_size && byval == 1 ) list[list_pos].curindex = 0;
+ if (list_size > 1 && list_pos >= 0 && list_pos < list_size)
+ {
+ list[list_pos].curindex = 0;
+ list[list_pos].repeatCurrent = 0;
+ }
+
+ list_pos += byval;
+ if (list_pos < 0) list_pos = 0;
+ else if (list_pos >= list_size) list_pos = list_size - 1;
+ else return list_pos;
+ return -1;
+ }
+
+ void PlayList_addfromdlg(const wchar_t *fns)
+ {
+ AutoLock lock (playlistGuard);
+ WinampPlaylist playlist;
+ playlistManager->LoadFromDialog(fns, &playlist);
+ }
+
+ void PlayList_getcurrent_tupdate(wchar_t *FileName, wchar_t *FileTitle)
+ {
+ AutoLock lock (playlistGuard);
+ if (!g_has_deleted_current)
+ {
+ PlayList_refreshtitle(); // removed for evil vbr fix. ? ?
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ }
+ else
+ {
+ _lastlen = -1;
+ StringCchCopyW(FileTitle, FILETITLE_SIZE, remove_urlcodesW(PlayList_gettitle(L"", 1)));
+ }
+ }
+
+ void PlayList_refreshtitle(void)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ if (list_pos >= 0 && list_pos < list_size)
+ {
+ _lastlen = -1;
+
+ // TODO: benski> tag probably needs this, but MN radio can't have it: if ( !list[list_pos].curitems )
+ {
+ wchar_t *title = remove_urlcodesW(PlayList_gettitle(L"", 1));
+ list[list_pos].SetTitle(title);
+ }
+ PlayList_setcached(list_pos, 1);
+ if (_lastlen != -1) list[list_pos].length = _lastlen;
+ //JF100500 SendMessageW(hPLWindow,WM_USER+1,0,0);
+ }
+ }
+
+ const wchar_t *PlayList_GetCachedTitle(const wchar_t *filename)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ for (int i = 0;i < list_size;i++)
+ {
+ if (!lstrcmpiW(filename, list[i].strFile))
+ {
+ if (list[i].cached)
+ {
+ _lastlen = list[i].length;
+ return list[i].strTitle;
+ }
+ else
+ return 0;
+ }
+ }
+ return 0;
+ }
+
+ void PlayList_UpdateTitle(const wchar_t *filename)
+ {
+ AutoLock lock (playlistGuard);
+ CHECK_STUFF();
+ for (int i = 0;i < list_size;i++)
+ {
+ if (!lstrcmpiW(filename, list[i].strFile))
+ PlayList_updateitem(i);
+ }
+
+ Playlist_notifyModified();
+ }
+
+ void PlayList_updaterandpos(void)
+ {
+ AutoLock lock (playlistGuard);
+ //MessageBox(NULL,"updaterandpos","b",0);
+ rnd_listmodified = 1;
+ }
+
+ void Playlist_rnd_additem()
+ {
+ AutoLock lock (playlistGuard);
+ if (!rnd_listmodified && rnd_rtable && rnd_lastls > 0)
+ {
+ int x, newpos;
+ rnd_lastls++;
+ int *newtable = (int*)realloc(rnd_rtable, sizeof(int) * (rnd_lastls));
+ if (!newtable)
+ {
+ newtable = (int*)malloc(sizeof(int) * (rnd_lastls));
+ if (newtable)
+ {
+ memcpy(newtable, rnd_rtable, sizeof(int)*(rnd_lastls - 1));
+ free(rnd_rtable);
+ rnd_rtable = newtable;
+ }
+ else return ;
+ }
+ else rnd_rtable = newtable;
+
+ newpos = warand() % rnd_lastls;
+
+ for (x = rnd_lastls - 1; x > newpos; x --)
+ {
+ rnd_rtable[x] = rnd_rtable[x - 1];
+ if (rnd_rtable[x] >= list_size) rnd_rtable[x]++;
+ }
+ rnd_rtable[x] = list_size;
+ while (x > 0)
+ {
+ x--;
+ if (rnd_rtable[x] >= list_size) rnd_rtable[x]++;
+ }
+ }
+ else rnd_listmodified = 1;
+ }
+
+ void Playlist_rnd_deleteitem(int item)
+ {
+ AutoLock lock (playlistGuard);
+ if (!rnd_listmodified && rnd_rtable && rnd_lastls > 0)
+ {
+ for (int x = 0; x < rnd_lastls; x ++)
+ {
+ if (rnd_rtable[x] > item)
+ {
+ rnd_rtable[x]--;
+ }
+ else if (rnd_rtable[x] == item)
+ {
+ std::rotate(&rnd_rtable[x], &rnd_rtable[x + 1], &rnd_rtable[rnd_lastls]);
+ if (rnd_rtable[x] > item) rnd_rtable[x]--;
+ if (rnd_i >= x) rnd_i--;
+ if (rnd_i < 0) rnd_i = 0;
+ rnd_lastls--;
+ }
+ }
+ }
+ else rnd_listmodified = 1;
+ }
+
+ static int Rand(int n)
+ {
+ return warand() % n ;
+ }
+
+ int PlayList_randpos(int x)
+ {
+ AutoLock lock (playlistGuard);
+ int ls;
+
+ if (x == -666) // exiting winamp
+ {
+ rnd_i = 0;
+ free(rnd_rtable);
+ rnd_rtable = 0;
+ return 0;
+ }
+
+ if (ls = PlayList_getlength())
+ {
+ if (ls != rnd_lastls || rnd_listmodified)
+ {
+ int first_run = (rnd_lastls < 0);
+ //init table;
+ rnd_lastls = ls;
+ rnd_listmodified = 0;
+ if (!ls) return 0;
+ free(rnd_rtable);
+ rnd_rtable = (int *) malloc(ls * sizeof(int));
+ for (x = 0; x < ls; x ++)
+ {
+ rnd_rtable[x] = x;
+ }
+ x = 0;
+ if (first_run && list_pos >= 0 && list_pos < ls)
+ {
+ // at startup, go back to current song from last session:
+ rnd_rtable[list_pos] = 0;
+ rnd_rtable[0] = list_pos;
+ x = 1; // (don't re-randomize this entry)
+ }
+ std::random_shuffle(&rnd_rtable[x], &rnd_rtable[ls], Rand);
+ rnd_i = 0;
+ }
+ else rnd_i += x;
+
+ if (rnd_i >= ls)
+ {
+ if (config_repeat)
+ {
+ rnd_i = 0;
+ if (ls > 2)
+ {
+ // note: config_shuffle_morph_rate==0 means slow morph, and minimal changes to playlist each time through [window_size==2]
+ // config_shuffle_morph_rate==50 means fast morph, and guarantees that HALF of the other songs will play before any one song repeats [ideal]
+ int window_size = max(MulDiv(ls, config_shuffle_morph_rate, 100), 2);
+ for (x = 0; x < ls - 1; x ++)
+ {
+ std::random_shuffle(&rnd_rtable[x], &rnd_rtable[min(x + window_size, ls)], Rand);
+ }
+ }
+ }
+ else rnd_i = ls - 1;
+ PlayList_setposition(rnd_rtable[rnd_i]);
+ return 1;
+ }
+ if (rnd_i < 0)
+ {
+ rnd_i = 0;
+ PlayList_setposition(rnd_rtable[rnd_i]);
+ return 1;
+ }
+ PlayList_setposition(rnd_rtable[rnd_i]);
+ }
+ else rnd_lastls = 0;
+ return 0;
+ }
+
+ static bool PlayList_sortByFile(pl_entry &a, pl_entry &b) //const void *a, const void *b)
+ {
+ const wchar_t *file1 = PathFindFileNameW(a.strFile);
+ const wchar_t *file2 = PathFindFileNameW(b.strFile);
+
+ // int comp = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | /*NORM_IGNOREKANATYPE |*/ NORM_IGNOREWIDTH, file1, -1, file2 , -1);
+ //return comp == CSTR_LESS_THAN;
+ return FileCompareLogical(file1, file2) < 0;
+ }
+
+ static bool PlayList_sortByTitle(pl_entry &a, pl_entry &b)
+ {
+ // int comp = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE/*|NORM_IGNOREKANATYPE*/|NORM_IGNOREWIDTH, a.strTitle, -1, b.strTitle, -1);
+ // return comp == CSTR_LESS_THAN;
+ return CompareStringLogical(a.strTitle, b.strTitle) < 0;
+ }
+
+ static bool PlayList_sortByDirectory(pl_entry &a, pl_entry &b) // by dir, then by title
+ {
+ const wchar_t *directory1 = a.strFile;
+ const wchar_t *directory2 = b.strFile;
+ const wchar_t *directoryEnd1 = scanstr_backcW(directory1, L"\\", 0);
+ const wchar_t *directoryEnd2 = scanstr_backcW(directory2 , L"\\", 0);
+ size_t dirLen1 = directoryEnd1 - directory1;
+ size_t dirLen2 = directoryEnd2 - directory2;
+
+ if (!dirLen1 && !dirLen2) // both in the current directory?
+ return PlayList_sortByFile(a, b); // not optimized, because the function does another scanstr_back, but easy for now :)
+
+ if (!dirLen1) // only the first dir is empty?
+ return true; // sort it first
+
+ if (!dirLen2) // only the second dir empty?
+ return false; // empty dirs go first
+
+ int comp = FileCompareLogicalN(directory1, dirLen1, directory2, dirLen2);
+ if (comp == 0)
+ return PlayList_sortByFile(a, b);
+ else
+ return comp < 0;
+#if 0 // old way
+ int comp = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | /*NORM_IGNOREKANATYPE | */NORM_IGNOREWIDTH, directory1, dirLen1, directory2 , dirLen2);
+ if (comp == CSTR_EQUAL) // same dir
+ return PlayList_sortByFile(a, b); // do second sort
+ else // different dirs
+ return comp == CSTR_LESS_THAN;
+#endif
+ }
+
+ void PlayList_mark()
+ {
+ for (int x = 0; x < list_size; x++)
+ list[x].tmp = 0;
+ list[list_pos].tmp = 1;
+ }
+
+ void PlayList_restore()
+ {
+ for (int x = 0; x < list_size; x ++)
+ {
+ if (list[x].tmp)
+ {
+ list_pos = x;
+ break;
+ }
+ }
+ }
+
+ void PlayList_sort(int bytitle, int start_p)
+ {
+ AutoLock lock (playlistGuard);
+ if (start_p >= list_size || list_size < 2 || !list) return ;
+ PlayList_mark();
+ if (bytitle == 0)
+ std::sort(&list[start_p], &list[list_size], PlayList_sortByFile);
+ else if (bytitle == 1)
+ std::sort(&list[start_p], &list[list_size], PlayList_sortByTitle);
+ else
+ std::sort(&list[start_p], &list[list_size], PlayList_sortByDirectory);
+ PlayList_restore();
+ Playlist_notifyModified();
+ }
+
+ void PlayList_reverse(void)
+ {
+ AutoLock lock (playlistGuard);
+ if (!list || list_size <= 1)
+ return ;
+ PlayList_mark();
+ std::reverse(list, &list[list_size]);
+ PlayList_restore();
+ Playlist_notifyModified();
+ }
+
+ void PlayList_randomize(void)
+ {
+ AutoLock lock (playlistGuard);
+ if (!list || list_size <= 1)
+ return ;
+ PlayList_mark();
+ std::random_shuffle(list, &list[list_size], Rand);
+ PlayList_restore();
+ Playlist_notifyModified();
+ }
+
+ void PlayList_adddir(const wchar_t *path, int recurse)
+ {
+ if (playlistManager)
+ {
+ AutoLock lock (playlistGuard);
+ WinampDirectoryLoad dir(recurse!=0, 0);
+ WinampPlaylist playlist(0);
+ playlistManager->LoadDirectory(path, &playlist, &dir);
+ }
+ }
+
+ void PlayList_makerelative(const wchar_t *listfile, wchar_t *filename, int useBase)
+ {
+ if (useBase)
+ MakeRelativePathName(filename, filename, M3UBASE);
+ else
+ {
+ wchar_t path[MAX_PATH] = {0};
+ StringCchCopyW(path, MAX_PATH, listfile);
+ PathRemoveFileSpecW(path);
+ PathRemoveBackslashW(path);
+ MakeRelativePathName(filename, filename, path);
+ }
+ }
+}
+
+static void Playlist_notifyModified()
+{
+ plneedsave = plmodified = 1;
+ SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_PLAYLIST_MODIFIED);
+}
+
+int IsPlaylistExtension(const wchar_t *ext)
+{
+ wchar_t temp[32] = {0};
+ StringCchPrintfW(temp, 32, L"hi.%s", ext);
+
+ if (playlistManager && playlistManager->CanLoad(temp)) // TODO: make a "valid extension" method
+ return 1;
+ else
+ return 0;
+}
+
+int IsPlaylistExtensionA(const char *ext)
+{
+ return IsPlaylistExtension(AutoWide(ext));
+}
+
+void GetMIMEType(const char *url, char *mimeType, int mimeTypeCch);
+
+int LoadPlaylistByExtension(const wchar_t *fn, const wchar_t *ext, int whattodo, int useBase)
+{
+ if (!playlistManager || !playlistManager->CanLoad(ext))
+ return -1;
+
+ //if (useBase)
+ // WASABI_API_APP->path_setWorkingPath(M3UBASE);
+ //cut: SetCurrentDirectoryW(M3UBASE);
+
+ int i = 0;
+
+ if (PathIsURLW(fn))
+ {
+ int rval = 1;
+ if (!httpRetrieveFileW(hMainWindow, AutoChar(fn), TEMP_FILE, getStringW(IDS_RETRPL, NULL, 0)))
+ {
+ rval = LoadPlaylistByExtension(TEMP_FILE, ext, whattodo, useBase);
+ }
+ DeleteFileW(TEMP_FILE);
+ return rval;
+ }
+
+ if (PlayList_getlength())
+ {
+ if (whattodo < 1)
+ {
+ PlayList_delete();
+ i = 1;
+ }
+ }
+
+ WinampPlaylist playlist(useBase?M3UBASE:0, !useBase);
+ playlistManager->LoadAs(fn, ext, &playlist);
+
+ if (i)
+ {
+ StopPlaying(0);
+ if (config_shuffle) PlayList_randpos( -BIGINT);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ if (whattodo == 0) StartPlaying();
+ }
+ return 0;
+}
+
+int LoadPlaylist(const wchar_t *filename, int whattodo, int doMIMEcheck)
+{
+ wchar_t ext[65]=L".";
+ extension_exW(filename, ext+1, 64); // TODO: make api_playlistmanager use this function
+ int x = LoadPlaylistByExtension(filename, ext, whattodo, 0);
+ if (doMIMEcheck && x == -1 && PathIsURLW(filename))
+ {
+ /*
+ benski> disabled for now
+ GetMIMEType(AutoChar(filename), ext, 64);
+ if (*ext)
+ {
+ if (!_stricmp(ext, "video/x-ms-asf"))
+ return LoadPlaylistByExtension(filename, L".asx", whattodo, 0); // TODO: make "load playlist by MIME type" API
+ else if (!_stricmp(ext, "video/asx"))
+ return LoadPlaylistByExtension(filename, L".asx", whattodo, 0);
+ }
+ */
+ }
+ return x;
+}
+
+void PlayList_insert(int position, const wchar_t *filename)
+{
+ AutoLock lock (playlistGuard);
+ PlayList_saveend(position);
+ PlayList_appendthing(filename, 0, 0);
+ PlayList_restoreend();
+} \ No newline at end of file
diff --git a/Src/Winamp/PlayQueue.cpp b/Src/Winamp/PlayQueue.cpp
new file mode 100644
index 00000000..26f4fc30
--- /dev/null
+++ b/Src/Winamp/PlayQueue.cpp
@@ -0,0 +1,108 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+
+#include "main.h"
+#include "resource.h"
+
+extern void ConvertEOF();
+int PlayQueue_OnEOF()
+{
+ if (m_converting)
+ {
+ ConvertEOF();
+ return 0;
+ }
+ LRESULT nextItem;
+
+ g_fullstop = 1;
+
+ // for gen_jumpex mainly so it doesn't have to use ugly hacks
+ nextItem = SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GET_NEXT_PLITEM);
+
+ if (nextItem != -1) // check to see if anyone has overridden what track we play next
+ {
+ PlayList_setposition(nextItem);
+
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ }
+ else // nope? just advanced to the next track
+ {
+ if (PlayList_getlength() && !g_stopaftercur)
+ {
+ if (!config_pladv) // if manual playlist advance is on
+ {
+ if (!config_repeat
+ && !PlayList_current_hidden()) // if this is a "horizontal" playlist, let the tracks play out
+ goto fullstop;
+ StartPlaying();
+ }
+ else if (!config_shuffle && PlayList_advance(HIDDEN_TRAP) < 0) // -33 is so i can trap playnext
+ {
+ if (config_repeat)
+ {
+ PlayList_setposition(0);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ }
+ else
+ {
+ g_fullstop = 2;
+ StopPlaying(0);
+ }
+ }
+ else
+ {
+ if (config_shuffle && !PlayList_current_hidden())
+ {
+ int lp = PlayList_getPosition();
+ if ((PlayList_randpos(1) || PlayList_getlength() == 1) // this isn't really the place for this check
+ && !config_repeat)
+ {
+ g_fullstop = 2;
+ StopPlaying(0);
+ g_fullstop = 0;
+ return 0;
+ }
+ if (PlayList_getPosition() == lp && PlayList_getlength() > 1)
+ {
+ PlayList_randpos(1);
+ }
+ }
+ else
+ {
+ // 5.64 - if pledit is cleared, shuffle is off & we're playing
+ // then we set playing to go back to the start of the playlist
+ // as we get complaints it'll go to #2 instead of #1 as shown.
+ if (plcleared)
+ {
+ plcleared = 0;
+ PlayList_setposition(0);
+ }
+ }
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ }
+ }
+ else
+ {
+ HMENU m;
+ fullstop:
+ g_stopaftercur = 0;
+ CheckMenuItem(main_menu, WINAMP_BUTTON4_CTRL, MF_UNCHECKED);
+ m = GetSubMenu(top_menu, 3);
+ CheckMenuItem(m, WINAMP_BUTTON4_CTRL, MF_UNCHECKED);
+ g_fullstop = 2;
+ StopPlaying(0);
+ }
+ }
+
+ g_fullstop = 0;
+ return 1;
+} \ No newline at end of file
diff --git a/Src/Winamp/PlaybackConfigGroup.cpp b/Src/Winamp/PlaybackConfigGroup.cpp
new file mode 100644
index 00000000..8d836c9f
--- /dev/null
+++ b/Src/Winamp/PlaybackConfigGroup.cpp
@@ -0,0 +1,48 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "PlaybackConfigGroup.h"
+#include "../Agave/Config/ifc_configitem.h"
+
+#include "WinampAttributes.h"
+
+ifc_configitem *PlaybackConfigGroup::GetItem(const wchar_t *name)
+{
+ if (!wcscmp(name, L"bits"))
+ return &config_audio_bits;
+ else if (!wcscmp(name, L"mono"))
+ return &config_audio_mono;
+ else if (!wcscmp(name, L"surround"))
+ return &config_audio_surround;
+ else if (!wcscmp(name, L"dither"))
+ return &config_audio_dither;
+ else if (!wcscmp(name, L"replaygain"))
+ return &config_replaygain;
+ else if (!wcscmp(name, L"replaygain_mode"))
+ return &config_replaygain_mode;
+ else if (!wcscmp(name, L"replaygain_source"))
+ return &config_replaygain_source;
+ else if (!wcscmp(name, L"replaygain_preferred_only"))
+ return &config_replaygain_preferred_only;
+ else if (!wcscmp(name, L"non_replaygain"))
+ return &config_replaygain_non_rg_gain;
+ else if (!wcscmp(name, L"replaygain_preamp"))
+ return &config_replaygain_preamp;
+ else if (!wcscmp(name, L"priority"))
+ return &config_playback_thread_priority;
+
+ return 0;
+}
+
+
+#define CBCLASS PlaybackConfigGroup
+START_DISPATCH;
+CB(IFC_CONFIGGROUP_GETITEM, GetItem)
+CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Winamp/PlaybackConfigGroup.h b/Src/Winamp/PlaybackConfigGroup.h
new file mode 100644
index 00000000..d9a09639
--- /dev/null
+++ b/Src/Winamp/PlaybackConfigGroup.h
@@ -0,0 +1,24 @@
+#ifndef NULLSOFT_WINAMP_PLAYBACKCONFIGGROUP_H
+#define NULLSOFT_WINAMP_PLAYBACKCONFIGGROUP_H
+
+#include "main.h"
+#include "../Agave/Config/ifc_configgroup.h"
+
+// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
+static const GUID playbackConfigGroupGUID =
+{ 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
+
+class PlaybackConfigGroup : public ifc_configgroup
+{
+public:
+ ifc_configitem *GetItem(const wchar_t *name);
+ GUID GetGUID() { return playbackConfigGroupGUID; }
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern PlaybackConfigGroup playbackConfigGroup;
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Playlist.h b/Src/Winamp/Playlist.h
new file mode 100644
index 00000000..341637cd
--- /dev/null
+++ b/Src/Winamp/Playlist.h
@@ -0,0 +1,12 @@
+#ifndef NULLSOFT_WINAMP_PLAYLIST_H
+#define NULLSOFT_WINAMP_PLAYLIST_H
+
+#include "../playlist/ifc_playlistloadercallback.h"
+
+class Playlist : public ifc_playlistloadercallback
+{
+public:
+ void OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info );
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Pledit.cpp b/Src/Winamp/Pledit.cpp
new file mode 100644
index 00000000..fdb0f707
--- /dev/null
+++ b/Src/Winamp/Pledit.cpp
@@ -0,0 +1,1723 @@
+#include <windowsx.h>
+
+#include "Main.h"
+#include "ipc_pe.h"
+#include "buildType.h"
+#include "../Plugins/General/gen_ml/ml_ipc.h"
+#include "../Plugins/General/gen_ml/ml.h"
+#include "../Plugins/General/gen_ml/menufucker.h"
+#include "api.h"
+#include "ExplorerFindFile.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoWideFn.h"
+#include "resource.h"
+
+int pledit_disp_offs;
+static int pledit_delta_carryover;
+
+void plEditRefresh(void)
+{
+ if (config_pe_open) InvalidateRect(hPLWindow, NULL, FALSE);
+}
+
+void plEditSelect(int song)
+{
+ if (hPLWindow) SendMessageW(hPLWindow, WM_USER, 666, song);
+}
+
+int pe_startuphack, eq_startuphack;
+
+void pleditDlg(HWND hwnd, int init_state)
+{
+ if (!hPLWindow) return ;
+ int toggle = Ipc_WindowToggle(IPC_CB_WND_PE, !config_pe_open);
+ KillTimer(hPLWindow, 3);
+ if (!toggle) return;
+
+ if (!config_pe_open)
+ {
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_PLEDIT, MF_CHECKED);
+ if (pe_startuphack == 1)
+ {
+ if(!GetParent(hPLWindow))
+ SetTimer(hPLWindow, 3, 10, NULL);
+ config_pe_open = 1;
+ }
+ else
+ {
+ if(!init_state && !config_minimized) ShowWindow(hPLWindow, SW_SHOWNA);
+ SendMessageW(hPLWindow, WM_USER, 666, PlayList_getPosition());
+ config_pe_open = 1;
+
+ // works around a quirk with Bento docked to the right-hand edge
+ // where the pledit is left docked on reverting to classic skin (dro)
+ if(!GetParent(hPLWindow)) set_aot(1);
+ }
+ }
+ else
+ {
+ if (GetForegroundWindow() == hPLWindow || IsChild(hPLWindow, GetForegroundWindow()))
+ {
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_NEXT_WINDOW, 0);
+ }
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_PLEDIT, MF_UNCHECKED);
+ ShowWindow(hPLWindow, SW_HIDE);
+ config_pe_open = 0;
+ }
+ draw_eqplbut(config_eq_open, 0, config_pe_open, 0);
+ return ;
+}
+
+int playlist_open(HWND hwnd)
+{
+ if (!(loadpls(hwnd, -1))) return 0;
+ PlayList_setposition(0);
+ if (config_shuffle) PlayList_randpos(-100000);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hPLWindow, &r, FALSE);
+ }
+ return 1;
+}
+
+static wchar_t entryFN[FILENAME_SIZE];
+static BOOL CALLBACK entryProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SetDlgItemTextW(hwndDlg, IDC_OLD, entryFN);
+ SetDlgItemTextW(hwndDlg, IDC_NEW, entryFN);
+
+ // show ctrl+e window and restore last position as applicable
+ POINT pt = {ctrle_rect.left, ctrle_rect.top};
+ if (!windowOffScreen(hwndDlg, pt))
+ SetWindowPos(hwndDlg, HWND_TOP, ctrle_rect.left, ctrle_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
+
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetDlgItemTextW(hwndDlg, IDC_NEW, entryFN, FILENAME_SIZE);
+ GetWindowRect(hwndDlg, &ctrle_rect);
+ EndDialog(hwndDlg, 1);
+ return 0;
+ case IDCANCEL:
+ GetWindowRect(hwndDlg, &ctrle_rect);
+ EndDialog(hwndDlg, 0);
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+void PE_Cmd(windowCommand *wc)
+{
+ if (wc == NULL) return ;
+ switch (wc->cmd)
+ {
+ case PLCMD_ADD:
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 1), wc->align, wc->x, wc->y, hPLWindow);
+ break;
+ case PLCMD_REM:
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 2), wc->align, wc->x, wc->y, hPLWindow);
+ break;
+ case PLCMD_SEL:
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 3), wc->align, wc->x, wc->y, hPLWindow);
+ break;
+ case PLCMD_MISC:
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 0), wc->align, wc->x, wc->y, hPLWindow);
+ break;
+ case PLCMD_LIST:
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 4), wc->align, wc->x, wc->y, hPLWindow);
+ break;
+ }
+}
+
+static librarySendToMenuStruct mySendTo;
+static HMENU ratingMenu;
+static int PE_OnRButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ POINT p;
+ GetCursorPos(&p);
+
+ if ((flags & MK_LBUTTON)) return 1;
+
+ if (peui_isrbuttoncaptured()) return 1;
+
+ if (config_pe_height != 14 && config_pe_width >= 350 &&
+ (x >= config_pe_width - 150 - 75 && y >= config_pe_height - 26 && x <= config_pe_width - 150 && y <= config_pe_height - 8))
+ {
+ extern HMENU g_submenus_vis;
+ DoTrackPopup(g_submenus_vis, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else if (config_pe_height != 14 &&
+ (x >= 14 && y >= config_pe_height - 30 && x <= 32 && y <= config_pe_height - 12))
+ {
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 1), TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else if (config_pe_height != 14 &&
+ (x >= 43 && y >= config_pe_height - 30 && x <= 64 && y <= config_pe_height - 12))
+ {
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 2), TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else if (config_pe_height != 14 &&
+ (x >= 72 && y >= config_pe_height - 30 && x <= 93 && y <= config_pe_height - 12))
+ {
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 3), TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else if (config_pe_height != 14 &&
+ (x >= 101 && y >= config_pe_height - 30 && x <= 122 && y <= config_pe_height - 12))
+ {
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else if (config_pe_height != 14 &&
+ (x >= config_pe_width - 44 && y >= config_pe_height - 30 && x <= config_pe_width - 44 + 22 && y <= config_pe_height - 12))
+ {
+ DoTrackPopup(GetSubMenu(GetSubMenu(top_menu, 2), 4), TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ else if (config_pe_height != 14 && y >= 20 && y <= config_pe_height - 38 && x >= 12 && x <= config_pe_width - 20)
+ { // right click in list box
+ int wh = (y - 22) / pe_fontheight + pledit_disp_offs;
+ int s = (flags & MK_CONTROL);
+
+ if (!s && !PlayList_getselect(wh))
+ {
+ int x, t = PlayList_getlength();
+
+ for (x = 0; x < t; x ++)
+ PlayList_setselect(x, 0);
+ }
+
+ if (PlayList_getselect(wh) && s)
+ PlayList_setselect(wh, 0);
+ else
+ {
+ int y = wh - pledit_disp_offs;
+ if (y < PlayList_getlength() - pledit_disp_offs && y < (config_pe_height - 38 - 20 - 2) / pe_fontheight)
+ {
+ PlayList_setselect(wh, 1);
+ }
+ }
+
+ // ensures the selection is shown before the menu is displayed
+ {
+ RECT r1 = {12, 22, config_pe_width - 20, config_pe_height - 38};
+ InvalidateRect(hwnd, &r1, FALSE);
+ UpdateWindow(hwnd);
+ }
+
+#ifdef WINAMP_FINAL_BUILD
+ if (!PlayList_gethidden(wh) && !PlayList_hasanycurtain(wh))
+#endif
+ {
+ LRESULT IPC_LIBRARY_SENDTOMENU = wa_register_ipc((WPARAM)&"LibrarySendToMenu");
+ HMENU menu = 0, ourmenu = GetSubMenu(GetSubMenu(top_menu, 2), 5);
+
+ memset(&mySendTo, 0, sizeof(mySendTo));
+ if (IPC_LIBRARY_SENDTOMENU > 65536 && SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)0, IPC_LIBRARY_SENDTOMENU) == 0xffffffff)
+ {
+ MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU | MIIM_TYPE, MFT_STRING, };
+ mii.hSubMenu = menu = CreatePopupMenu();
+ mii.dwTypeData = getStringW(IDS_SENDTO_STR,NULL,0);
+ mii.cch = (UINT)wcslen(mii.dwTypeData);
+
+ InsertMenuItemW(ourmenu, 1, TRUE, &mii);
+
+ mySendTo.mode = 1;
+ mySendTo.hwnd = hwnd;
+ mySendTo.data_type = ML_TYPE_FILENAMESW;
+ mySendTo.build_hMenu = menu;
+ }
+
+ {
+ HMENU tmenu = NULL;
+ int nitems = GetMenuItemCount(ourmenu);
+ for (int i = 0; i < nitems; i++)
+ {
+ // test for it being a popup
+ if(GetMenuItemID(ourmenu, i) == -1)
+ {
+ if((tmenu = GetSubMenu(ourmenu, i)))
+ {
+ // and if so then see what the last popup menu item is
+ if(GetMenuItemID(tmenu, GetMenuItemCount(tmenu)-1) == ID_PL_RATING0)
+ {
+ ratingMenu = tmenu;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ menufucker_t mf = {sizeof(mf),MENU_PLAYLIST,ourmenu,0x3000,0x4000,0};
+ pluginMessage message_build = {(int)wa_register_ipc((WPARAM)&"menufucker_build"),(intptr_t)&mf,0};
+ sendMlIpc(ML_IPC_SEND_PLUGIN_MESSAGE,(WPARAM)&message_build);
+ int ret = DoTrackPopup(ourmenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, p.x, p.y, hwnd);
+ ratingMenu = NULL;
+ pluginMessage message_result = {(int)wa_register_ipc((WPARAM)&"menufucker_result"),(intptr_t)&mf,ret,0};
+ sendMlIpc(ML_IPC_SEND_PLUGIN_MESSAGE,(WPARAM)&message_result);
+
+ if (menu)
+ {
+ if (mySendTo.mode == 2)
+ {
+ mySendTo.menu_id = ret;
+ if (SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&mySendTo, IPC_LIBRARY_SENDTOMENU) == 0xffffffff)
+ {
+ size_t buf_size = 4096;
+ wchar_t *buf = (wchar_t*)malloc(buf_size*sizeof(wchar_t));
+ size_t buf_pos = 0;
+
+ int i, l = PlayList_getlength();
+
+ for (i = 0;i < l;i++)
+ {
+ if (PlayList_getselect(i)
+#ifdef WINAMP_FINAL_BUILD
+ && !PlayList_gethidden(i) && !PlayList_hasanycurtain(i)
+#endif
+ )
+ {
+ wchar_t itrFilename[FILENAME_SIZE] = {0};
+ PlayList_getitem(i, itrFilename, NULL);
+ size_t newsize = buf_pos + wcslen(itrFilename) + 1;
+ if (newsize < buf_size)
+ {
+ size_t old_buf_size = buf_size;
+ buf_size = newsize + 4096;
+ wchar_t *new_buf = (wchar_t*)realloc(buf, buf_size*sizeof(wchar_t));
+ if (!new_buf)
+ {
+ new_buf = (wchar_t*)malloc(buf_size*sizeof(wchar_t));
+ if (new_buf)
+ {
+ memcpy(new_buf, buf, old_buf_size*sizeof(wchar_t));
+ free(buf);
+ buf = new_buf;
+ }
+ }
+ else buf = new_buf;
+ }
+ StringCchCopyW(buf + buf_pos, buf_size - buf_pos, itrFilename);
+ buf_pos = newsize;
+ }
+ }
+
+ if (buf_pos)
+ {
+ buf[buf_pos] = 0;
+ mySendTo.mode = 3;
+ mySendTo.data = buf;
+ mySendTo.data_type = ML_TYPE_FILENAMESW;
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&mySendTo, IPC_LIBRARY_SENDTOMENU);
+ }
+
+ free(buf);
+ ret = 0;
+ }
+ }
+ // remove sendto
+ DeleteMenu(ourmenu, 1, MF_BYPOSITION);
+ }
+ if (mySendTo.mode)
+ {
+ mySendTo.mode = 4;
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&mySendTo, IPC_LIBRARY_SENDTOMENU); // cleanup
+ memset(&mySendTo, 0, sizeof(mySendTo));
+ }
+ if (ret) SendMessageW(hwnd, WM_COMMAND, ret, 0);
+ }
+ }
+ else
+ {
+ DoTrackPopup(main_menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hMainWindow);
+ }
+
+ return 1;
+}
+
+static int PE_OnLButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ ReleaseCapture();
+ peui_handlemouseevent(hwnd, x, y, -1, flags);
+ return 1;
+}
+
+static int PE_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
+{
+ SetCapture(hwnd);
+ peui_handlemouseevent(hwnd, x, y, 1, keyFlags);
+ SetFocus(hwnd);
+ return 1;
+}
+
+static int PE_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
+{
+ peui_handlemouseevent(hwnd, x, y, 0, keyFlags);
+ return 1;
+}
+
+static BOOL PE_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized)
+{
+ if (fActive == FALSE)
+ {
+ draw_pe_tbar(hwnd, NULL, config_hilite ? 0 : 1);
+ peui_reset(hwnd);
+ }
+ else
+ {
+ draw_pe_tbar(hwnd, NULL, 1);
+ }
+ return TRUE;
+}
+
+static int PE_OnLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
+{
+ if (y <= 14 && x < config_pe_width - 20)
+ {
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_OPTIONS_WINDOWSHADE_PL, 0);
+ }
+ else if (config_pe_height != 14)
+ {
+ if (x >= 12 && y >= 20 && x <= config_pe_width - 20 && y <= config_pe_height - 38)
+ {
+ int t = (y - 22) / pe_fontheight;
+ if (t < PlayList_getlength() - pledit_disp_offs && t < (config_pe_height - 38 - 20 - 2) / pe_fontheight)
+ {
+ t += pledit_disp_offs;
+ PlayList_setposition(t);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ SetForegroundWindow(hwnd);
+ }
+ }
+ else if (x >= config_pe_width - 44 && y >= config_pe_height - 30 && x < config_pe_width - 44 + 22 && y < config_pe_height - 12)
+ {
+ InvalidateRect(hwnd, NULL, 0);
+ SendMessageW(hwnd, WM_COMMAND, ID_PE_OPEN, 0);
+ }
+ else if (x >= 101 && y >= config_pe_height - 30 && x < 122 && y < config_pe_height - 12)
+ {
+ {
+ POINT p = {122, config_pe_height - 30};
+ ClientToScreen(hwnd, &p);
+ DoTrackPopup(GetSubMenu(GetSubMenu(GetSubMenu(top_menu, 2), 0), 2), TPM_LEFTALIGN, p.x, p.y, hwnd);
+ }
+ peui_reset(hwnd);
+ }
+ else if (x >= 72 && y >= config_pe_height - 30 && x < 93 && y < config_pe_height - 12)
+ {
+ peui_reset(hwnd);
+ SendMessageW(hwnd, WM_COMMAND, ID_PE_SELECTALL, 0);
+ }
+ else if (x >= 43 && y >= config_pe_height - 30 && x < 64 && y < config_pe_height - 12)
+ {
+ peui_reset(hwnd);
+ SendMessageW(hwnd, WM_COMMAND, IDC_PLAYLIST_REMOVEMP3, 0);
+ }
+ else if (x >= 14 && y >= config_pe_height - 30 && x < 35 && y < config_pe_height - 12)
+ {
+ peui_reset(hwnd);
+ SendMessageW(hwnd, WM_COMMAND, IDC_PLAYLIST_ADDMP3, 0);
+ }
+ }
+ return 1;
+}
+
+int setCurrentRating(int rating)
+{
+ LRESULT ret = sendMlIpc(ML_IPC_SETRATING, rating);
+ if (!ret && !got_ml)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (!PlayList_getitem2W(PlayList_getPosition(), fn, NULL))
+ {
+ wchar_t buf[64] = {0};
+ if (rating > 0)
+ StringCchPrintfW(buf, 64, L"%d", rating);
+ else
+ buf[0] = 0;
+
+ if(config_noml_ratings_prompt)
+ {
+ config_noml_ratings = (LPMessageBox(hMainWindow, IDS_NOML_SAVE_RATING, IDS_NOML_SAVE_RATING_TITLE, MB_YESNO | MB_ICONQUESTION) == IDYES);
+ config_noml_ratings_prompt = 0;
+ }
+
+ if (config_noml_ratings)
+ {
+ in_set_extended_fileinfoW(fn, L"rating", buf);
+ in_write_extended_fileinfo();
+ }
+ }
+ }
+ SendMessageW(hMainWindow,WM_TIMER,UPDATE_DISPLAY_TIMER+4,0);
+ return ret;
+}
+
+int setPlRating(int rating)
+{
+ int r = 0;
+ int i, l = PlayList_getlength();
+
+ for (i = 0;i < l;i++)
+ {
+ if (PlayList_getselect(i))
+ {
+ pl_set_rating psr;
+ psr.plentry = i;
+ psr.rating = rating;
+ r |= sendMlIpc(ML_IPC_PL_SETRATING, (WPARAM) & psr);
+ if (!r && !got_ml)
+ {
+ wchar_t buf[64] = {0};
+ if (rating > 0)
+ StringCchPrintfW(buf, 64, L"%d", rating);
+ else
+ buf[0] = 0;
+
+ if(config_noml_ratings_prompt)
+ {
+ config_noml_ratings = (LPMessageBox(hMainWindow, IDS_NOML_SAVE_RATING, IDS_NOML_SAVE_RATING_TITLE, MB_YESNO | MB_ICONQUESTION) == IDYES);
+ config_noml_ratings_prompt = 0;
+ }
+
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (config_noml_ratings && !PlayList_getitem2W(i, fn, NULL))
+ {
+ in_set_extended_fileinfoW(fn, L"rating", buf);
+ in_write_extended_fileinfo();
+ }
+ }
+ g_need_titleupd = 1; // force a title update (%rating% may be in the ATF string)
+ PlayList_updateitem(i);
+ }
+ }
+ plEditRefresh();
+ SendMessageW(hMainWindow,WM_TIMER,UPDATE_DISPLAY_TIMER+4,0);
+ return r;
+}
+
+LRESULT CALLBACK PE_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static int se_lp, se_a, se_t;
+ if (uMsg == g_scrollMsg)
+ {
+ wParam <<= 16; uMsg = WM_MOUSEWHEEL;
+ }
+ switch (uMsg)
+ {
+ case WM_SHOWWINDOW:
+ if (wParam == TRUE && lParam == SW_PARENTOPENING && !config_pe_open)
+ return 0;
+ break;
+
+ case WM_DISPLAYCHANGE:
+ InvalidateRect(hwnd, NULL, TRUE);
+ break;
+
+ case WM_INITMENUPOPUP:
+ if (wParam && (HMENU)wParam == mySendTo.build_hMenu && mySendTo.mode == 1)
+ {
+ int IPC_LIBRARY_SENDTOMENU = wa_register_ipc((WPARAM)&"LibrarySendToMenu");
+ if (IPC_LIBRARY_SENDTOMENU > 65536 && SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&mySendTo, IPC_LIBRARY_SENDTOMENU) == 0xffffffff)
+ mySendTo.mode = 2;
+ }
+
+ // handles the ratings menu and is localised happy now
+ // (compared to the IDS_RATEITEM_STR based code) - DO 26/09/07
+ else if (wParam && (HMENU)wParam == ratingMenu)
+ {
+ int darating = -1, firstrating = -1;
+ for (int i = 0; i < PlayList_getlength(); i++)
+ {
+ int rating = 0;
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (PlayList_getselect2(i, fn)
+#ifdef WINAMP_FINAL_BUILD
+ && !PlayList_gethidden(i) && !PlayList_hasanycurtain(i)
+#endif
+ )
+ {
+ rating = sendMlIpc(ML_IPC_GET_FILE_RATINGW, (WPARAM)fn);
+ if (!i) firstrating = rating;
+
+ // deal with no ml being present and querying the rating of a file from the tag (if possible)
+ // as well as getting a zero rating which could mean that it's not present in the library
+ if (!rating && !got_ml)
+ {
+ wchar_t buf[64] = {0};
+ in_get_extended_fileinfoW(fn, L"rating", buf, 64);
+ rating = _wtoi(buf);
+ if (!i) firstrating = rating;
+ }
+
+ if (darating == -1)
+ {
+ darating = rating;
+ }
+ else
+ {
+ if (darating != rating) darating = -2;
+ }
+ }
+ }
+
+ if (darating == -2) darating = firstrating;
+ CheckMenuItem(ratingMenu, ID_PL_RATING5, (darating == 5) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingMenu, ID_PL_RATING4, (darating == 4) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingMenu, ID_PL_RATING3, (darating == 3) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingMenu, ID_PL_RATING2, (darating == 2) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingMenu, ID_PL_RATING1, (darating == 1) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingMenu, ID_PL_RATING0, (darating == 0) ? MF_CHECKED : MF_UNCHECKED);
+
+ // set this so we don't re-process until the menu is re-loaded completely
+ ratingMenu = NULL;
+ }
+ return 0;
+ HANDLE_MSG(hwnd, WM_QUERYNEWPALETTE, Main_OnQueryNewPalette);
+ HANDLE_MSG(hwnd, WM_PALETTECHANGED, Main_OnPaletteChanged);
+ HANDLE_MSG(hwnd, WM_LBUTTONUP, PE_OnLButtonUp);
+ HANDLE_MSG(hwnd, WM_RBUTTONUP, PE_OnRButtonUp);
+ HANDLE_MSG(hwnd, WM_LBUTTONDOWN, PE_OnLButtonDown);
+ HANDLE_MSG(hwnd, WM_MOUSEMOVE, PE_OnMouseMove);
+ HANDLE_MSG(hwnd, WM_NCACTIVATE, PE_OnNCActivate);
+ HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, PE_OnLButtonDblClk);
+ case WM_SYSCOMMAND:
+ if ((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER)
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+ break;
+
+ case WM_CLOSE:
+ WASABI_API_APP->main_shutdown();
+ return 0;
+ case WM_PAINT:
+ draw_paint_pe(hwnd);
+ return 0;
+ case WM_PRINTCLIENT:
+ draw_printclient_pe(hwnd, (HDC)wParam, lParam);
+ return 0;
+ case WM_GETMINMAXINFO:
+ {
+ MINMAXINFO *p = (MINMAXINFO *)lParam;
+ p->ptMaxTrackSize.x = 16384;
+ p->ptMaxTrackSize.y = 16384;
+ }
+ return 0;
+ case WM_NOTIFY:
+ {
+ LPTOOLTIPTEXT tt = (LPTOOLTIPTEXT)lParam;
+ /*if(tt->hdr.hwndFrom = hPL2TooltipWindow)
+ {
+ switch (tt->hdr.code)
+ {
+ case TTN_SHOW:*/
+ /*if(tt->hdr.idFrom == 17)
+ {
+ POINT pt = {0};
+ GetCursorPos(&pt);
+ ScreenToClient(hPLWindow,&pt);
+ RECT rc = {0};
+ EstPLWindowRect(&rc);
+ rc.left += 12;
+
+ int t = (pt.y - 20) / pe_fontheight;
+ if (t < 0) t = 0;
+ else if (t > (config_pe_height - 38 - 20 - 2) / pe_fontheight) t = PlayList_getlength();
+ rc.top += 22+(pe_fontheight*t);
+
+ SendMessageW(tt->hdr.hwndFrom,TTM_ADJUSTRECT,TRUE,(LPARAM)&rc);
+ SetWindowPos(tt->hdr.hwndFrom,HWND_TOPMOST,rc.left,rc.top,0,0,SWP_NOSIZE|SWP_NOACTIVATE);
+ return TRUE;
+ }
+ else*/
+ /*{
+ SetWindowPos(tt->hdr.hwndFrom,HWND_TOPMOST,0,0,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
+ }
+ break;
+ }
+ }
+ else*/ if(tt->hdr.hwndFrom = hPLTooltipWindow)
+ {
+ switch (tt->hdr.code)
+ {
+ case TTN_SHOW:
+ SetWindowPos(tt->hdr.hwndFrom,HWND_TOPMOST,0,0,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
+ break;
+ }
+ }
+ }
+ break;
+ case WM_SIZE:
+ if (wParam == SIZE_RESTORED)
+ {
+ // changed to this as it's a cleaner approach to the earlier option
+ // this will better handle playlist size changes (especially on skin
+ // change) without causing the current item to be returned to view
+ // unlike my prior commit from 30/05/08 (so this acts more natural).
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ int num_songs = (config_pe_height - 38 - 20 - 2) / pe_fontheight;
+ int t = PlayList_getlength();
+ if (pledit_disp_offs >= t - num_songs) pledit_disp_offs = t - num_songs;
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ return 0;
+ case WM_WINDOWPOSCHANGED:
+ if (GetParent(hwnd)) // fix the stupid pl bug?
+ {
+ WINDOWPOS *lpwp = (WINDOWPOS*)lParam;
+ config_pe_width = lpwp->cx;
+ if (config_pe_height != 14)
+ {
+ config_pe_height = lpwp->cy;
+ if (hPLVisWindow)
+ {
+ int x, y, w, h;
+ x = config_pe_width - 150 - 75 + 2;
+ y = config_pe_height - 26;
+ w = (config_pe_width >= 350 && config_pe_height != 14 ? 72 : 0);
+ h = 16;
+ SetWindowPos(hPLVisWindow, 0, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
+ break;
+ } else {
+ // update the position of the tooltips on window resize
+ set_pl_wnd_tooltip();
+ }
+ break;
+ case WM_CREATE:
+ hPLWindow = hwnd;
+ SetTimer(hwnd, 1, 100, NULL);
+ draw_reinit_plfont(0);
+ SetWindowLongPtrW(hwnd, GWLP_USERDATA, (config_keeponscreen&2) ? 0x49474541 : 0);
+ if (NULL != WASABI_API_APP) WASABI_API_APP->app_registerGlobalWindow(hwnd);
+ {
+ if (!config_embedwnd_freesize) config_pe_width -= config_pe_width % 25;
+ if (config_pe_width < 275) config_pe_width = 275;
+ if (config_pe_height != 14)
+ {
+ if (!config_embedwnd_freesize) config_pe_height -= config_pe_height % 29;
+ if (config_pe_height < 116) config_pe_height = 116;
+ config_pe_height_ws = 0;
+ }
+ else
+ {
+ if (!config_embedwnd_freesize) config_pe_height_ws -= config_pe_height_ws % 29;
+ if (config_pe_height_ws < 116) config_pe_height_ws = 116;
+ }
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE)&~(WS_CAPTION));
+ SetWindowPos(hwnd, 0, config_pe_wx, config_pe_wy, config_pe_width, config_pe_height, SWP_NOACTIVATE | SWP_NOZORDER);
+
+ HACCEL hAccel = LoadAcceleratorsW(language_pack_instance, MAKEINTRESOURCEW(IDR_ACCELERATOR_PL));
+ if (!hAccel && language_pack_instance != hMainInstance) hAccel = LoadAcceleratorsW(hMainInstance, MAKEINTRESOURCEW(IDR_ACCELERATOR_PL));
+ if (hAccel) WASABI_API_APP->app_addAccelerators(hwnd, &hAccel, 1, TRANSLATE_MODE_NORMAL);
+ }
+
+ return 0;
+ case WM_DESTROY:
+ KillTimer(hwnd, 1);
+ KillTimer(hwnd, 3);
+ if (pe_init)
+ draw_pe_kill();
+ if (NULL != WASABI_API_APP) WASABI_API_APP->app_unregisterGlobalWindow(hwnd);
+ return 0;
+ case WM_TIMER:
+ if (wParam == 3)
+ {
+ KillTimer(hwnd, 3);
+ if (!IsMinimized(hMainWindow))
+ {
+ ShowWindow(hwnd, SW_SHOWNA);
+ }
+ SendMessageW(hwnd, WM_USER, 666, PlayList_getPosition());
+
+ // works around a quirk with Bento docked to the right-hand edge
+ // where the pledit is left docked on reverting to classic skin (dro)
+ if(!GetParent(hwnd)) set_aot(1);
+ }
+ else if (wParam == 1)
+ {
+ static int a;
+ if (!a && config_pe_height != 14 && config_pe_open && (config_riol == 0 || config_riol == 4) && !peui_isrbuttoncaptured())
+ {
+ int start, end, view_start, pl_len;
+ a = 1;
+ start = pledit_disp_offs;
+ end = start + (config_pe_height - 38 - 20 - 2) / pe_fontheight;
+ if (start < 0) start = 0;
+ pl_len = PlayList_getlength();
+ if (end > pl_len || config_riol == 4) end = pl_len;
+ view_start = start;
+
+ while (start < end)
+ {
+ if (!PlayList_getcached(start))
+ {
+ RECT r1 = {12, 20 + (start - pledit_disp_offs) * pe_fontheight,
+ config_pe_width - 20, 20 + (start + 1 - pledit_disp_offs) * pe_fontheight};
+
+ PlayList_updateitem(start);
+ if (PlayList_getcached(start))
+ {
+ InvalidateRect(hwnd, &r1, FALSE);
+ if(config_riol == 4)
+ InvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ }
+ start++;
+
+ // if we got to the end of the viewable area / playlist contents
+ // then we loop to the start so we can try to read all the titles
+ // and back to the point just before the current top of list point
+ if(config_riol == 4 && start == end && end == pl_len){
+ start = 0;
+ end = view_start;
+ }
+ }
+ a = 0;
+ }
+ }
+ return 0;
+ case WM_USER:
+ switch (wParam)
+ {
+ case 666:
+ {
+ RECT r = {12, 22, config_pe_width - 3, config_pe_height - 37};
+ int num_songs = (config_pe_height - 38 - 20 - 2) / pe_fontheight;
+ int p = (lParam & ((1 << 30) - 1)), t;
+ int brep = !(lParam & (1 << 30));
+ int needrepaint = 1;
+ t = PlayList_getlength();
+ if (config_pe_height == 14)
+ {
+ RECT r2 = {0, 0, config_pe_width, 14};
+ r = r2;
+ num_songs = (config_pe_height_ws - 38 - 20 - 2) / pe_fontheight;
+ }
+
+ if (p >= pledit_disp_offs + num_songs || p < pledit_disp_offs)
+ {
+ if (brep)
+ {
+ pledit_disp_offs = max(p - num_songs / 2, 0);
+ if (pledit_disp_offs + num_songs > t)
+ pledit_disp_offs = t - num_songs;
+ }
+ else needrepaint = 0;
+ }
+ if (brep)
+ {
+ if (num_songs >= t || pledit_disp_offs < 0)
+ {
+ pledit_disp_offs = 0;
+ }
+ }
+ if (needrepaint && IsWindowVisible(hwnd)) InvalidateRect(hwnd, &r, FALSE);
+ }
+ break;
+ case IPC_PE_GETDIRTY:
+ return plmodified;
+ case IPC_PE_SETCLEAN:
+ plmodified = 0;
+ break;
+ case IPC_PE_GETNEXTSELECTED:
+ return PlayList_GetNextSelected(lParam);
+ case IPC_PE_GETSELECTEDCOUNT:
+ return PlayList_GetSelectedCount();
+ case IPC_PE_GETCURINDEX:
+ return PlayList_getPosition();
+ case IPC_PE_GETINDEXTOTAL:
+ return PlayList_getlength();
+ case IPC_PE_DELETEINDEX:
+ {
+ if (lParam < PlayList_getlength())
+ {
+ PlayList_deleteitem(lParam);
+ }
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ break;
+ }
+ case IPC_PE_SWAPINDEX:
+ {
+ PlayList_swap(lParam & 0xFFFF, (lParam & 0xFFFF0000) >> 16);
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ break;
+ }
+ case IPC_PE_GETIDXFROMPOINT:
+ {
+ POINT *p = (POINT *) lParam;
+ int t;
+
+ if (config_pe_height == 14) return PlayList_getlength();
+ else
+ {
+ t = (p->y - 20) / pe_fontheight;
+ if (t < 0) t = 0;
+ else if (t > (config_pe_height - 38 - 20 - 2) / pe_fontheight) t = PlayList_getlength();
+ else t += pledit_disp_offs;
+ }
+ return t;
+ }
+ case IPC_PE_SAVEEND:
+ se_a = PlayList_getlength();
+ PlayList_saveend(se_t = (int)lParam);
+ se_lp = PlayList_getPosition();
+
+ break;
+ case IPC_PE_RESTOREEND:
+ PlayList_restoreend();
+ if (se_t <= PlayList_getPosition())
+ {
+ PlayList_setposition(se_lp + PlayList_getlength() - se_a);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ plEditRefresh();
+ break;
+ case IPC_PE_GETINDEXTITLE:
+ if (lParam)
+ {
+ fileinfo2 *fi = (fileinfo2 *)lParam;
+ return PlayList_getitem3(fi->fileindex, fi->filetitle, fi->filelength);
+ }
+ break;
+ case IPC_PE_GETINDEXTITLEW:
+ if (lParam)
+ {
+ fileinfo2W *fi = (fileinfo2W *)lParam;
+ return PlayList_getitem3W(fi->fileindex, fi->filetitle, fi->filelength);
+ }
+ break;
+ case IPC_PE_GETINDEXINFO_INPROC:
+ if (lParam)
+ {
+ fileinfo *fi = (fileinfo *)lParam;
+ char tempfile[FILENAME_SIZE]="";
+ PlayList_getitem2(fi->index, tempfile, NULL);
+ StringCbCopyA(fi->file, MAX_PATH, tempfile);
+ }
+ break;
+ case IPC_PE_GETINDEXINFOW_INPROC:
+ if (lParam)
+ {
+ fileinfoW *fi = (fileinfoW *)lParam;
+ wchar_t tempfile[FILENAME_SIZE]=L"";
+ PlayList_getitem2W(fi->index, tempfile, NULL);
+ StringCbCopyW(fi->file, sizeof(fi->file), tempfile);
+ }
+ break;
+ }
+ return 0;
+
+
+ case WM_COPYDATA:
+ {
+ COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lParam;
+ switch (cds->dwData)
+ {
+ case IPC_PE_INSERTFILENAME:
+ {
+ fileinfo *f = (fileinfo *)(cds->lpData);
+ if (f && *f->file)
+ {
+ int oldposition = PlayList_getPosition();
+ int oldSize = PlayList_getlength();
+ PlayList_saveend(f->index);
+ PlayList_appendthing(AutoWideFn(f->file), 0, 0);
+ PlayList_restoreend();
+ if (oldposition >= f->index)
+ {
+ oldposition += (PlayList_getlength() - oldSize);
+ PlayList_setposition(oldposition);
+ }
+
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ return TRUE;
+ }
+ case IPC_PE_INSERTFILENAMEW:
+ {
+ fileinfoW *f = (fileinfoW *)(cds->lpData);
+ if (f && *f->file)
+ {
+ int oldposition = PlayList_getPosition();
+ int oldSize = PlayList_getlength();
+ PlayList_saveend(f->index);
+ PlayList_appendthing(f->file, 0, 0);
+ PlayList_restoreend();
+ if (oldposition >= f->index)
+ {
+ oldposition += (PlayList_getlength() - oldSize);
+ PlayList_setposition(oldposition);
+ }
+
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ return TRUE;
+ }
+ case IPC_PE_GETINDEXINFO:
+ {
+ callbackinfo *i = (callbackinfo *)(cds->lpData);
+ if (i && i->callback)
+ {
+ COPYDATASTRUCT cdsr;
+ fileinfo f;
+ cdsr.dwData = IPC_PE_GETINDEXINFORESULT;
+ char tempfile[FILENAME_SIZE]="";
+ PlayList_getitem2(i->index, tempfile, NULL);
+ StringCbCopyA(f.file, sizeof(f.file), tempfile);
+ f.index = i->index;
+ cdsr.lpData = (void *) & f;
+ cdsr.cbData = sizeof(fileinfo);
+ SendMessageW(i->callback, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cdsr);
+ return 0;
+ }
+ return TRUE;
+ }
+ case IPC_PE_GETINDEXINFO_TITLE:
+ {
+ callbackinfo *i = (callbackinfo *)(cds->lpData);
+ if (i && i->callback)
+ {
+ COPYDATASTRUCT cdsr;
+ fileinfo f;
+ cdsr.dwData = IPC_PE_GETINDEXINFORESULT_TITLE;
+ PlayList_getitem3(i->index, f.file, NULL);
+ f.index = i->index;
+ cdsr.lpData = (void *) & f;
+ cdsr.cbData = sizeof(fileinfo);
+ SendMessageW(i->callback, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cdsr);
+ return 0;
+ }
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case ID_PE_SHOWPLAYING:
+ plEditSelect(PlayList_getPosition());
+ return 0;
+ case WINAMP_OPTIONS_WINDOWSHADE:
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_OPTIONS_WINDOWSHADE_PL, 0);
+ return 0;
+ case ID_PE_FFOD:
+ {
+ int x, v;
+ wchar_t fn[FILENAME_SIZE] = {0};
+ v = PlayList_getlength();
+ for (x = 0; x < v; x++)
+ {
+ if (PlayList_getselect(x)
+ #ifdef WINAMP_FINAL_BUILD
+ && !PlayList_gethidden(x) && !PlayList_hasanycurtain(x)
+ #endif
+ )
+ {
+ if (!PlayList_getitem2W(x, fn, NULL))
+ {
+ // show the playlist file entry of the selected item(s) if there were any
+ explorerFindFileManager->AddFile(fn);
+ }
+ }
+ }
+ explorerFindFileManager->ShowFiles();
+ return 0;
+ }
+ case ID_PE_BOOKMARK:
+ {
+ int x, v;
+ wchar_t fn[FILENAME_SIZE] = {0}, ft[FILETITLE_SIZE] = {0};
+ v = PlayList_getlength();
+ for (x = 0; x < v; x++)
+ {
+ if (PlayList_getselect(x)
+ #ifdef WINAMP_FINAL_BUILD
+ && !PlayList_gethidden(x) && !PlayList_hasanycurtain(x)
+ #endif
+ )
+ {
+ PlayList_getitem2W(x, fn, ft);
+ Bookmark_additem(fn, ft);
+ }
+ }
+ }
+ return 0;
+ case ID_PE_EXTINFO:
+ {
+ wchar_t ft[FILETITLE_SIZE] = {0};
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ int v = PlayList_getlength();
+ for (int x = 0; x < v; x++)
+ {
+ if (PlayList_getselect(x)
+ #ifdef WINAMP_FINAL_BUILD
+ && !PlayList_gethidden(x) && !PlayList_hasanycurtain(x)
+#endif
+ )
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ PlayList_getitem(x, fn, ft);
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)fn, IPC_FILE_TAG_MAY_UPDATEW);
+ PlayList_setitem(x, fn, PlayList_gettitle(fn, 1));
+ PlayList_setlastlen(x);
+ }
+ }
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ return 0;
+ case ID_PE_PRINT:
+ doHtmlPlaylist();
+ return 0;
+ case WINAMP_NEXT_WINDOW:
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+ case ID_PE_OPEN:
+ {
+ //int isvisible = IsWindowVisible(hwnd);
+ if (!playlist_open(/*isvisible ? hwnd :*/ (g_dialog_box_parent ? g_dialog_box_parent : hMainWindow))) break;
+ }
+ return 0;
+ case ID_PE_EDIT_SEL:
+ if (PlayList_GetNextSelected(-1) != -1)
+ {
+ extern INT_PTR CALLBACK EditInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ LPDialogBoxW(IDD_EDIT_INFO, hwnd, EditInfo);
+ }
+ return 0;
+ case ID_PE_ID3:
+ {
+ int x, v;
+ wchar_t ft[FILETITLE_SIZE] = {0};
+ v = PlayList_getlength();
+ for (x = 0; x < v; x++)
+ {
+ if (PlayList_getselect(x)
+ #ifdef WINAMP_FINAL_BUILD
+ && !PlayList_gethidden(x) && !PlayList_hasanycurtain(x)
+#endif
+ )
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+
+ PlayList_getitem(x, fn, ft);
+
+ if (in_infobox(hwnd, fn)) break;
+ PlayList_setitem(x, fn, PlayList_gettitle(fn, 1));
+ PlayList_setlastlen(x);
+ }
+ }
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ return 0;
+ case ID_PE_CLEAR:
+ PlayList_delete();
+ PlayList_randpos(0);
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ return 0;
+ case IDC_SELECTINV:
+ {
+ int x, v;
+ v = PlayList_getlength();
+ for (x = 0; x < v; x ++)
+ {
+ PlayList_setselect(x, !PlayList_getselect(x));
+ }
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ return 0;
+ case ID_PE_SELECTALL:
+ {
+ int x, v;
+ v = PlayList_getlength();
+ for (x = 0; x < v; x ++)
+ {
+ PlayList_setselect(x, 1);
+ }
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ return 0;
+ case ID_PE_NONE:
+ {
+ int x, v;
+ v = PlayList_getlength();
+ for (x = 0; x < v; x ++)
+ {
+ PlayList_setselect(x, 0);
+ }
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ return 0;
+ case ID_PE_ENTRY:
+ {
+ int x, v;
+ wchar_t ft[FILETITLE_SIZE] = {0};
+ v = PlayList_getlength();
+ for (x = 0; x < v; x ++)
+ {
+ if (PlayList_getselect(x)
+#ifdef WINAMP_FINAL_BUILD
+ && !PlayList_gethidden(x) && !PlayList_hasanycurtain(x)
+#endif
+ )
+ {
+ wchar_t itrFilename[FILENAME_SIZE] = {0};
+ PlayList_getitem(x, itrFilename, ft);
+ StringCchCopyW(entryFN, FILENAME_SIZE, itrFilename);
+ if (!LPDialogBoxW(IDD_EDITENTRY, DIALOG_PARENT(hwnd), (WNDPROC)entryProc))
+ {
+ SetFocus(hwnd);
+ break;
+ }
+ SetFocus(hwnd);
+ PlayList_setitem(x, entryFN, PlayList_gettitle(entryFN, 1));
+ }
+ }
+
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ return 0;
+ case ID_PE_SAVEAS:
+ savepls(hwnd);
+ return 0;
+ case IDC_PLAYLIST_CROP:
+ {
+ int v = PlayList_getlength();
+ int x;
+ for (x = 0; x < v; x ++)
+ if (PlayList_getselect(x)) break;
+ if (x != v) for (x = v - 1; x >= 0; x--)
+ {
+ if (!PlayList_getselect(x))
+ {
+ PlayList_deleteitem(x);
+ }
+ }
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ return 0;
+ case IDC_PLAYLIST_REMOVEMP3:
+ {
+ int v = PlayList_getlength(), x;
+ for (x = v - 1; x >= 0; x--)
+ {
+ if (PlayList_getselect(x))
+ {
+ PlayList_deleteitem(x);
+ }
+ }
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ return 0;
+ case ID_PEPLAYLIST_PLAYLISTPREFERENCES:
+ prefs_last_page = 23;
+ prefs_dialog(1);
+ return 0;
+ case ID_PE_SCUP:
+ case ID_PE_SCDOWN:
+ // TODO: need to make the shift action more like Windows so it'll shrink the selection down rather than making it grow
+ // ideally need to keep a record of the 'current selection' so we can then adjust from there-will be interesting
+ if (config_pe_height != 14)
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ int which;
+ int x;
+ int num_songs = (config_pe_height - 38 - 20 - 2) / pe_fontheight;
+ if (LOWORD(wParam) == ID_PE_SCUP)
+ {
+ for (x = pledit_disp_offs; x < pledit_disp_offs + num_songs; x ++) if (PlayList_getselect(x)) break;
+ if (x != pledit_disp_offs + num_songs) which = x - 1;
+ else which = pledit_disp_offs;
+ }
+ else
+ {
+ for (x = pledit_disp_offs + num_songs - 1; x >= pledit_disp_offs; x--) if (PlayList_getselect(x)) break;
+ if (x >= pledit_disp_offs) which = x + 1;
+ else which = pledit_disp_offs + num_songs - 1;
+ }
+
+ if (which < 0) which = 0;
+ if (which >= PlayList_getlength()) which = PlayList_getlength() - 1;
+ if (!(GetAsyncKeyState(VK_SHIFT)&0x8000))
+ {
+ for (x = PlayList_getlength() - 1; x >= 0; x --) PlayList_setselect(x, 0);
+ }
+ PlayList_setselect(which, 1);
+ if (which < pledit_disp_offs) pledit_disp_offs = which;
+ else if (which >= pledit_disp_offs + num_songs)
+ pledit_disp_offs = which - num_songs + 1;
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ else
+ {
+ if (LOWORD(wParam) == ID_PE_SCUP)
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON1, 0);
+ else
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON5, 0);
+ }
+ return 0;
+ case ID_PE_SCROLLDOWN:
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ int num_songs = (config_pe_height - 38 - 20 - 2) / pe_fontheight;
+ int t = PlayList_getlength();
+ pledit_disp_offs += config_plscrollsize;
+ if (pledit_disp_offs >= t - num_songs) pledit_disp_offs = t - num_songs;
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ return 0;
+
+ case ID_PE_SCROLLUP:
+ if (pledit_disp_offs > 0)
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ pledit_disp_offs -= config_plscrollsize;
+ if (pledit_disp_offs < 0) pledit_disp_offs = 0;
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ return 0;
+
+ case ID_PE_MOVEDOWN:
+ {
+ extern int shiftsel_1;
+ int v = PlayList_getlength();
+ RECT r =
+ {
+ 0, 0, config_pe_width, config_pe_height - 37
+ };
+ if (!PlayList_getselect(v - 1))
+ for (int x = v - 2; x >= 0; x --)
+ {
+ if (PlayList_getselect(x))
+ {
+ if (shiftsel_1 == x) shiftsel_1 = x + 1;
+ PlayList_swap(x, x + 1);
+ if (x == PlayList_getPosition()) PlayList_advance(1);
+ else if (x + 1 == PlayList_getPosition()) PlayList_advance(-1);
+ }
+ }
+ InvalidateRect(hwnd, &r, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ return 0;
+
+ case ID_PE_MOVEUP:
+ {
+ extern int shiftsel_1;
+ int v = PlayList_getlength();
+ RECT r =
+ {
+ 0, 0, config_pe_width, config_pe_height - 37
+ };
+ if (!PlayList_getselect(0))
+ for (int x = 1; x < v; x ++)
+ {
+ if (PlayList_getselect(x))
+ {
+ if (shiftsel_1 == x) shiftsel_1 = x + 1;
+ PlayList_swap(x, x - 1);
+ if (x == PlayList_getPosition()) PlayList_advance(-1);
+ else if (x - 1 == PlayList_getPosition()) PlayList_advance(1);
+ }
+ }
+ InvalidateRect(hwnd, &r, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ return 0;
+ }
+ case ID_PE_CLOSE:
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_OPTIONS_PLEDIT, 0);
+ return 0;
+ case IDC_PLAYLIST_ADDMP3:
+ //getNewFile(0, hwnd, 0); // changed May-10-2005 benski
+ getNewFile(0, /*NULL*/DIALOG_PARENT(hMainWindow), 0);
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ SetFocus(hwnd);
+ SetForegroundWindow(hwnd);
+ return 0;
+ case IDC_PLAYLIST_ADDLOC:
+ getNewLocation(0, hwnd);
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ return 0;
+ case IDC_PLAYLIST_ADDDIR:
+ {
+ BROWSEINFOW bi = {0};
+ wchar_t name[MAX_PATH] = {0};
+ bi.hwndOwner = hwnd;
+ bi.pszDisplayName = name;
+ bi.lpszTitle = L"__foo";
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc;
+ bi.lParam = 1;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist)
+ {
+ int s = PlayList_getlength();
+ wchar_t path[MAX_PATH] = {0};
+ SHGetPathFromIDListW(idlist, path);
+ Shell_Free(idlist);
+ WASABI_API_APP->path_setWorkingPath(path);
+ //SetCurrentDirectoryW(path);
+ PlayList_adddir(path, (config_rofiob&2) ? 0 : 1);
+ if (config_rofiob&1)
+ PlayList_sort(2, s);
+
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+
+ }
+ }
+ return 0;
+ case IDC_PLAYLIST_PLAY:
+ {
+ int x, v = PlayList_getlength();
+ for (x = 0; x < v; x ++)
+ {
+ if (PlayList_getselect(x)) break;
+ }
+ if (x != v)
+ {
+ PlayList_setposition(x);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ SetForegroundWindow(hwnd);
+ }
+ }
+ return 0;
+ case ID_PE_S_TITLE:
+ case ID_PE_S_FILENAME:
+ case ID_PE_S_PATH:
+ case ID_PE_S_RANDOM:
+ case ID_PE_S_REV:
+ {
+ int num_songs = (config_pe_height - 38 - 20 - 2) / pe_fontheight;
+ int w = 0;
+ if (LOWORD(wParam) == ID_PE_S_TITLE) w = 1;
+ else if (LOWORD(wParam) == ID_PE_S_PATH) w = 2;
+ else if (LOWORD(wParam) == ID_PE_S_FILENAME) w = 0;
+ else if (LOWORD(wParam) == ID_PE_S_RANDOM) w = 3;
+ else if (LOWORD(wParam) == ID_PE_S_REV) w = 4;
+ if (w == 3) PlayList_randomize();
+ else if (w == 4) PlayList_reverse();
+ else if (w <= 2) PlayList_sort(w, 0);
+ pledit_disp_offs = PlayList_getPosition();
+ if (pledit_disp_offs + num_songs > PlayList_getlength())
+ pledit_disp_offs = PlayList_getlength() - num_songs;
+ if (pledit_disp_offs < 0) pledit_disp_offs = 0;
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ break;
+ case ID_PE_DELETEFROMDISK:
+ {
+ int v, x;
+ v = PlayList_getlength();
+ for (x = v - 1; x >= 0; x --)
+ {
+ if (PlayList_getselect(x))
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+
+ PlayList_getitem(x, fn, NULL);
+ if (!PathIsURLW(fn))
+ {
+ SHFILEOPSTRUCTW fileOp = {0};
+ wchar_t file[FILENAME_SIZE] = {0};
+ StringCchCopyW(file, FILENAME_SIZE - 1, fn);
+ file[ wcslen(fn) + 1] = 0; // double null terminate;
+
+ fileOp.hwnd = hwnd;
+ fileOp.wFunc = FO_DELETE;
+ fileOp.pFrom = file;
+ fileOp.pTo = 0;
+ fileOp.fFlags = config_playlist_recyclebin ? FOF_ALLOWUNDO : 0;
+ fileOp.fAnyOperationsAborted = 0;
+ fileOp.hNameMappings = 0;
+ fileOp.lpszProgressTitle = 0;
+
+ if (SHFileOperationW(&fileOp))
+ {
+ wchar_t mes[4096] = {0};
+ StringCchPrintfW(mes, 4096, getStringW(IDS_ERROR_DELETING,NULL,0), fn);
+ MessageBoxW(hwnd, mes, getStringW(IDS_ERROR,NULL,0), MB_OK);
+ }
+ else
+ {
+ // only remove if the deletion actually went ahead
+ if(!fileOp.fAnyOperationsAborted)
+ PlayList_deleteitem(x);
+ }
+ }
+ }
+ }
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ break;
+ case ID_PE_NONEXIST:
+ {
+ int x, v;
+ v = PlayList_getlength();
+ for (x = v - 1; x >= 0; x --)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ FILE *fp = NULL;
+ PlayList_getitem(x, fn, NULL);
+ fp = _wfopen(fn, L"rb");
+ if (!PathIsURLW(fn) && !(fp/* = _wfopen(fn, L"rb")*/))
+ {
+ PlayList_deleteitem(x);
+ }
+ else
+ {
+ if (fp) fclose(fp);
+ }
+ }
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ break;
+ case ID_PE_TOP:
+ if (config_pe_height != 14)
+ {
+ pledit_disp_offs = 0;
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ break;
+ case ID_PE_BOTTOM:
+ if (config_pe_height != 14)
+ {
+ pledit_disp_offs = PlayList_getlength() - (config_pe_height - 38 - 20 - 2) / pe_fontheight;
+ if (pledit_disp_offs < 0) pledit_disp_offs = 0;
+ {
+ RECT r = {0, 0, config_pe_width, config_pe_height - 37};
+ InvalidateRect(hwnd, &r, FALSE);
+ }
+ }
+ break;
+ case ID_PE_FONTBIGGER:
+ case ID_PE_FONTSMALLER:
+ case ID_PE_FONTRESET:
+ switch (LOWORD(wParam))
+ {
+ case ID_PE_FONTBIGGER:
+ config_pe_fontsize++;
+ break;
+ case ID_PE_FONTSMALLER:
+ if (config_pe_fontsize > 2) config_pe_fontsize--;
+ break;
+ case ID_PE_FONTRESET:
+ config_pe_fontsize = PE_FONTSIZE;
+ break;
+ }
+
+ if (hMainWindow)
+ {
+ draw_reinit_plfont(1);
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ UpdatePlaylistFontSizeText();
+ _w_i("pe_fontsize", config_pe_fontsize);
+ break;
+ default:
+ SendMessageW(hMainWindow, uMsg, wParam, lParam);
+ if (GetForegroundWindow() == hMainWindow) SetForegroundWindow(hEQWindow);
+ return 0;
+ }
+ return 0;
+ case WM_USER + 0xebe:
+ if (lParam != 0xdeadbeef) break;
+ case WM_DROPFILES:
+ {
+ wchar_t temp[FILENAME_SIZE] = {0};
+ int x, y, a, t, lp;
+ HDROP h = (HDROP)(HANDLE) wParam;
+ POINT dp;
+ DragQueryPoint(h, &dp);
+ if (config_pe_height == 14) t = PlayList_getlength();
+ else
+ {
+ t = (dp.y - 20) / pe_fontheight;
+ if (t < 0) t = 0;
+ else if (t > (config_pe_height - 38 - 20 - 2) / pe_fontheight) t = PlayList_getlength();
+ else t += pledit_disp_offs;
+ }
+
+ y = DragQueryFileW(h, 0xffffffff, temp, FILENAME_SIZE);
+
+ a = PlayList_getlength();
+ PlayList_saveend(t);
+ lp = PlayList_getPosition();
+
+ for (x = 0; x < y; x ++)
+ {
+ DragQueryFileW(h, x, temp, FILENAME_SIZE);
+ PlayList_appendthing(temp, 0, 0);
+ }
+ PlayList_restoreend();
+ if (t <= PlayList_getPosition())
+ {
+ PlayList_setposition(lp + PlayList_getlength() - a);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ if (uMsg == WM_DROPFILES) DragFinish(h);
+ plEditRefresh();
+ }
+ return 0;
+ case WM_SETCURSOR:
+ if (config_usecursors && !disable_skin_cursors)
+ {
+ if ((HWND)wParam == hwnd && HIWORD(lParam) == WM_MOUSEMOVE)
+ pe_ui_handlecursor(hwnd);
+ return TRUE;
+ }
+ else SetCursor(LoadCursor(NULL, IDC_ARROW));
+ break;
+ case WM_MOUSEWHEEL:
+ {
+ int zDelta = GET_WHEEL_DELTA_WPARAM(wParam), dLines;
+ // if the delta changes then ignore prior carryover
+ // hopefully this will go with the expected action.
+ if(zDelta < 0 && pledit_delta_carryover > 0 ||
+ zDelta > 0 && pledit_delta_carryover < 0)
+ {
+ pledit_delta_carryover = 0;
+ }
+ // otherwise add on the carryover from the prior message
+ else zDelta += pledit_delta_carryover;
+
+ if (0 == (MK_MBUTTON & LOWORD(wParam)) &&
+ config_plmw2xscroll)
+ {
+ zDelta *= 2;
+ }
+
+ dLines = zDelta / WHEEL_DELTA;
+ pledit_delta_carryover = zDelta - dLines * WHEEL_DELTA;
+
+ if (!dLines)
+ {
+ if (zDelta > 0) dLines = 1;
+ else if (zDelta < 0) dLines = 0;
+ }
+ zDelta = (dLines >= 0) ? dLines : -dLines;
+
+ if (config_pe_height == 14)
+ {
+ if (dLines >= 0) dLines = WINAMP_BUTTON1;
+ else dLines = WINAMP_BUTTON5;
+ }
+ else
+ {
+ if (0 != (MK_MBUTTON & LOWORD(wParam)))
+ {
+ if (dLines >= 0) dLines = ID_PE_MOVEUP;
+ else dLines = ID_PE_MOVEDOWN;
+ }
+ else
+ {
+ if (dLines >= 0) dLines = ID_PE_SCROLLUP;
+ else dLines = ID_PE_SCROLLDOWN;
+ }
+ }
+
+ while (zDelta--)
+ {
+ SendMessageW(hwnd, WM_COMMAND, dLines, 0);
+ }
+ }
+ return 1; //FG> or gen_ff gets it too
+ }
+ if (FALSE != IsDirectMouseWheelMessage(uMsg))
+ {
+ SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+} \ No newline at end of file
diff --git a/Src/Winamp/Pls.cpp b/Src/Winamp/Pls.cpp
new file mode 100644
index 00000000..13a3177d
--- /dev/null
+++ b/Src/Winamp/Pls.cpp
@@ -0,0 +1,170 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include <io.h>
+#include <sys/stat.h>
+#include "api.h"
+#include "WinampPlaylist.h"
+#include "../nu/AutoChar.h"
+#include <strsafe.h>
+
+void saveplsfn(const wchar_t *_fn)
+{
+ int pos = PlayList_getPosition();
+ PlayList_setposition(0);
+ FILE *plsFile = _wfopen(_fn, L"wt");
+ if(plsFile)
+ {
+ int x = 0;
+ fprintf(plsFile, "[playlist]\r\n");
+ for (;;)
+ {
+ int plspos = PlayList_getPosition();
+ if (!PlayList_gethidden(plspos) && !PlayList_hasanycurtain(plspos))
+ {
+ wchar_t fnbuf[FILENAME_SIZE] = {0}, ftbuf[FILETITLE_SIZE] = {0};
+ PlayList_getitem2W(plspos, fnbuf, ftbuf);
+ PlayList_makerelative(_fn, fnbuf, 0);
+ fprintf(plsFile, "File%d=%s\r\n", ++x, (char *)AutoChar(fnbuf));
+ /*
+ const char *sBrowser = PlayList_getbrowser(plspos);
+ if (sBrowser)
+ fprintf(plsFile, "Browser%d=%s\r\n", x, sBrowser);
+ */
+
+ if (PlayList_getcached(plspos))
+ {
+ fprintf(plsFile, "Title%d=%s\r\n", x, (char *)AutoChar(ftbuf));
+ fprintf(plsFile, "Length%d=%d\r\n", x, PlayList_getcurrentlength());
+ }
+ int repeat = PlayList_getrepeatcount(plspos);
+ if (repeat > 0)
+ fprintf(plsFile, "Repeat%d=%d\r\n", x, repeat);
+ }
+ if (PlayList_advance(1) < 0) break;
+ }
+ fprintf(plsFile, "NumberOfEntries=%d\r\n", x);
+ fprintf(plsFile, "Version=2\r\n");
+
+ PlayList_setposition(pos);
+ fclose(plsFile);
+ }
+ return ;
+}
+
+int loadpls(HWND hwnd, int whattodo)
+{
+ if (!playlistManager)
+ {
+ LPMessageBox(hwnd, IDS_PLAYLIST_SUPPORT_NOT_INSTALLED,IDS_PLAYLIST_LOAD_ERROR, MB_OK);
+ return 0;
+ }
+ wchar_t filter[1024] = {0};
+ playlistManager->GetFilterList(filter, 1024);
+ wchar_t temp[FILENAME_SIZE] = {0}, oldCurPath[MAX_PATH] = {0}, titleStr[128] = {0};
+
+ GetCurrentDirectoryW(MAX_PATH, oldCurPath);
+
+ OPENFILENAMEW l = {sizeof(OPENFILENAMEW),0};
+ static int q;
+ int retv = 0;
+ if (q) return 0;
+ q = 1;
+ l.hwndOwner = DIALOG_PARENT(hMainWindow); //hwnd;
+ l.hInstance = hMainInstance;
+ l.lpstrFilter = filter;
+ l.lpstrFile = temp;
+ temp[0] = 0;
+ l.nMaxFile = FILENAME_SIZE;
+ l.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();
+
+ if (whattodo == 0) l.lpstrTitle = getStringW(IDS_OPEN_PLAYLIST,titleStr,128);
+ else if (whattodo == 1) l.lpstrTitle = getStringW(IDS_ADD_PLAYLIST,titleStr,128);
+ else l.lpstrTitle = getStringW(IDS_OPEN_PLAYLIST,titleStr,128);
+ l.lpstrDefExt = L"pls";
+
+ l.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER;
+
+ UninitDragDrops();
+ if (GetOpenFileNameW(&l))
+ {
+ wchar_t newCurPath[MAX_PATH] = {0};
+ GetCurrentDirectoryW(MAX_PATH, newCurPath);
+ WASABI_API_APP->path_setWorkingPath(newCurPath);
+
+ q = 0;
+ if (LoadPlaylist(temp, whattodo, 0) != 0)
+ retv = 0;
+ //else // TODO: this wasn't there in the old code, so we'll leave it out for now
+ retv = 1;
+ }
+ SetCurrentDirectoryW(oldCurPath);
+ q = 0;
+ InitDragDrops();
+ return retv;
+}
+
+static void checkplswritable(wchar_t *filename)
+{
+ if (!_waccess(filename, 0))
+ {
+ if (_waccess(filename, 2))
+ {
+ _wchmod(filename, _S_IREAD | _S_IWRITE);
+ }
+ }
+}
+
+int savepls(HWND hwnd)
+{
+ wchar_t oldCurPath[MAX_PATH] = {0};
+ GetCurrentDirectoryW(MAX_PATH, oldCurPath);
+
+ static wchar_t temp[MAX_PATH] = {0};
+ OPENFILENAMEW l = {sizeof(OPENFILENAMEW),0};
+ static int q;
+ if (q) return 0;
+ int ret = 0;
+ q = 1;
+ l.hwndOwner = hwnd;
+ l.hInstance = hMainInstance;
+ l.lpstrFilter = (LPCWSTR)SendMessageW(hMainWindow, WM_WA_IPC, 3, IPC_GET_PLAYLIST_EXTLISTW);
+ l.nFilterIndex = _r_i("plsflt", 3);
+ l.lpstrFile = temp;
+ l.nMaxFile = MAX_PATH - 1;
+ l.lpstrTitle = getStringW(IDS_SAVE_PLAYLIST,NULL,0);
+ l.lpstrDefExt = L"m3u";
+
+ l.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_OVERWRITEPROMPT;
+
+ if (GetSaveFileNameW(&l))
+ {
+ wchar_t newCurPath[MAX_PATH] = {0};
+ GetCurrentDirectoryW(MAX_PATH, newCurPath);
+ WASABI_API_APP->path_setWorkingPath(newCurPath);
+ SetCurrentDirectoryW(oldCurPath);
+
+ checkplswritable(temp);
+ q = 0;
+ ret = 1;
+ if (!_wcsicmp(extensionW(temp), L"pls"))
+ {
+ DeleteFileW(temp);
+ saveplsfn(temp);
+ }
+ else // if it's not PLS, then it's m3u or m3u8, both of which are handled by the same function
+ {
+ savem3ufn(temp, 0, 0);
+ }
+ }
+
+ _w_i("plsflt", l.nFilterIndex);
+ SetCurrentDirectoryW(oldCurPath);
+ q = 0;
+ return ret;
+} \ No newline at end of file
diff --git a/Src/Winamp/Resampler.cpp b/Src/Winamp/Resampler.cpp
new file mode 100644
index 00000000..f6d27588
--- /dev/null
+++ b/Src/Winamp/Resampler.cpp
@@ -0,0 +1,172 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "Resampler.h"
+#include <ks.h>
+#include <ksmedia.h>
+
+static int GetChannelMask(size_t channels)
+{
+ switch(channels)
+ {
+ case 1: return KSAUDIO_SPEAKER_MONO;
+ case 2: return KSAUDIO_SPEAKER_STEREO;
+ case 4: return KSAUDIO_SPEAKER_SURROUND;
+ case 6: return KSAUDIO_SPEAKER_5POINT1;
+ case 8: return KSAUDIO_SPEAKER_7POINT1;
+ default: return 0;
+ }
+}
+static void FillWFX_float(WAVEFORMATIEEEFLOATEX *format, size_t channels, size_t bits, size_t sampleRate)
+{
+ ZeroMemory(format, sizeof(WAVEFORMATIEEEFLOATEX));
+ size_t padded_bits = (bits + 7) & (~7);
+ format->Format.nChannels = (WORD)channels;
+ format->Format.nSamplesPerSec = (DWORD)sampleRate;
+ format->Format.nAvgBytesPerSec = (DWORD)(sampleRate * channels * (padded_bits >> 3));
+ format->Format.nBlockAlign = (WORD)(channels * (padded_bits >> 3));
+ format->Format.wBitsPerSample = (WORD)padded_bits;
+
+ format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ format->Format.cbSize = sizeof(WAVEFORMATIEEEFLOATEX) - sizeof(WAVEFORMATEX);
+ format->Samples.wValidBitsPerSample = (WORD)bits;
+ format->dwChannelMask = GetChannelMask(channels);
+ format->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+}
+
+static void FillWFX(WAVEFORMATEXTENSIBLE *format, size_t channels, size_t bits, size_t sampleRate)
+{
+ ZeroMemory(format, sizeof(WAVEFORMATEXTENSIBLE));
+ size_t padded_bits = (bits + 7) & (~7);
+ format->Format.nChannels = (WORD)channels;
+ format->Format.nSamplesPerSec = (DWORD)sampleRate;
+ format->Format.nAvgBytesPerSec = (DWORD)(sampleRate * channels * (padded_bits >> 3));
+ format->Format.nBlockAlign = (WORD)(channels * (padded_bits >> 3));
+ format->Format.wBitsPerSample = (WORD)padded_bits;
+
+ if (channels > 2 || padded_bits != bits)
+ {
+ format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ format->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+ format->Samples.wValidBitsPerSample = (WORD)bits;
+ format->dwChannelMask = GetChannelMask(channels);
+ format->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }
+ else
+ {
+ format->Format.wFormatTag = WAVE_FORMAT_PCM;
+ format->Format.cbSize = 0;
+ }
+}
+
+Resampler::Resampler(size_t inputBits, size_t inputChannels, size_t inputSampleRate,
+ size_t outputBits, size_t outputChannels, size_t outputSampleRate, bool floatingPoint)
+ : sizeFactor(1.), hStream(0), buffer(0), eof(false)
+{
+ if (floatingPoint)
+ {
+ WAVEFORMATIEEEFLOATEX inputFormat;
+ FillWFX_float(&inputFormat, inputChannels, inputBits, inputSampleRate);
+
+ WAVEFORMATIEEEFLOATEX outputFormat;
+ FillWFX_float(&outputFormat, outputChannels, outputBits, outputSampleRate);
+
+ acmStreamOpen(&hStream, 0, &inputFormat.Format, &outputFormat.Format, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
+ }
+ else
+ {
+ WAVEFORMATEXTENSIBLE inputFormat = {0};
+ FillWFX(&inputFormat, inputChannels, inputBits, inputSampleRate);
+
+ WAVEFORMATEXTENSIBLE outputFormat = {0};
+ FillWFX(&outputFormat, outputChannels, outputBits, outputSampleRate);
+
+ acmStreamOpen(&hStream, 0, &inputFormat.Format, &outputFormat.Format, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
+ }
+
+ if (!hStream)
+ {
+ // error - what should we do?
+ return ;
+ }
+
+ bufferAlloc = MulDiv(1024, (int) (outputBits * outputChannels), 8); // TODO: use acmStreamSize
+ buffer = (__int8 *)calloc(bufferAlloc, sizeof(__int8));
+ bufferValid = 0;
+
+ sizeFactor = (outputChannels * outputBits * outputSampleRate) * (inputChannels * inputBits * inputSampleRate);
+}
+
+Resampler::~Resampler()
+{
+ if (hStream)
+ {
+ acmStreamClose(hStream, 0);
+ }
+ free(buffer);
+}
+
+size_t Resampler::UseInternalBuffer(void *output, size_t outputBytes)
+{
+ if (bufferValid)
+ {
+ size_t writeSize = min(outputBytes, bufferValid);
+ memcpy(output, buffer, writeSize);
+
+ if (writeSize)
+ memmove(buffer, buffer + writeSize, bufferValid - writeSize);
+ bufferValid -= writeSize;
+
+ return writeSize;
+ }
+ else
+ return 0;
+}
+
+void Resampler::Flush()
+{
+ eof = true;
+}
+
+size_t Resampler::Convert(void *input, size_t *inputBytes, void *output, size_t outputBytes)
+{
+ size_t x = UseInternalBuffer(output, outputBytes);
+ if (x)
+ return x;
+
+ ACMSTREAMHEADER streamHeader;
+ ZeroMemory(&streamHeader, sizeof(streamHeader));
+
+ streamHeader.cbStruct = sizeof(streamHeader);
+ streamHeader.pbSrc = reinterpret_cast<LPBYTE>(input);
+ streamHeader.cbSrcLength = (DWORD)*inputBytes;
+ streamHeader.pbDst = reinterpret_cast<LPBYTE>(buffer);
+ streamHeader.cbDstLength = (DWORD)bufferAlloc;
+
+ if (acmStreamPrepareHeader(hStream, &streamHeader, 0))
+ return 0; // m_error = 1;
+
+ if (input && *inputBytes && !eof)
+ acmStreamConvert(hStream, &streamHeader, ACM_STREAMCONVERTF_BLOCKALIGN);
+ else
+ acmStreamConvert(hStream, &streamHeader, ACM_STREAMCONVERTF_END);
+
+ *inputBytes -= streamHeader.cbSrcLengthUsed;
+ bufferValid = streamHeader.cbDstLengthUsed;
+
+ acmStreamUnprepareHeader(hStream, &streamHeader, 0);
+ return UseInternalBuffer(output, outputBytes);
+}
+
+bool Resampler::OK()
+{
+ if (hStream)
+ return true;
+ else
+ return false;
+}
diff --git a/Src/Winamp/Resampler.h b/Src/Winamp/Resampler.h
new file mode 100644
index 00000000..2d293b84
--- /dev/null
+++ b/Src/Winamp/Resampler.h
@@ -0,0 +1,23 @@
+#ifndef NULLSOFT_WINAMP_RESAMPLER_H
+#define NULLSOFT_WINAMP_RESAMPLER_H
+#include <mmreg.h>
+#include <msacm.h>
+class Resampler
+{
+public:
+ Resampler(size_t inputBits, size_t inputChannels, size_t inputSampleRate,
+ size_t outputBits, size_t outputChannels, size_t outputSampleRate, bool floatingPoint);
+ ~Resampler();
+ size_t Convert(void *input, size_t *inputBytes, void *output, size_t outputBytes);
+ bool OK();
+ void Flush();
+ double sizeFactor;
+private:
+ size_t UseInternalBuffer(void *output, size_t outputBytes);
+ HACMSTREAM hStream;
+ __int8 *buffer;
+ size_t bufferAlloc;
+ size_t bufferValid;
+ bool eof;
+};
+#endif \ No newline at end of file
diff --git a/Src/Winamp/ResamplingReader.cpp b/Src/Winamp/ResamplingReader.cpp
new file mode 100644
index 00000000..6aa71116
--- /dev/null
+++ b/Src/Winamp/ResamplingReader.cpp
@@ -0,0 +1,89 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "ResamplingReader.h"
+
+ResamplingReader::ResamplingReader(Resampler *_resampler, CommonReader *_reader, size_t inputFrameSize)
+ : resampler(_resampler), reader(_reader),
+ bufferValid(0),
+ readState(READING)
+{
+ bufferAlloc = inputFrameSize * 1024; // enough room for 1024 samples
+ buffer = (__int8 *)calloc(bufferAlloc, sizeof(__int8));
+}
+
+ResamplingReader::~ResamplingReader()
+{
+ free(buffer);
+ delete resampler;
+ delete reader;
+}
+
+size_t ResamplingReader::ReadAudio(void *outputBuffer, size_t sizeBytes)
+{
+ size_t origSize = sizeBytes;
+ __int8 *origBuffer = (__int8 *)outputBuffer;
+ size_t bytesResampled = 0;
+read_again:
+ // First, read from the file decoder
+ switch (readState)
+ {
+ case READING:
+ {
+ size_t bytesToRead = bufferAlloc - bufferValid;
+ if (bytesToRead)
+ {
+ int decode_killswitch=0, decode_error;
+ size_t bytesRead = reader->ReadAudio(buffer + (bufferAlloc - bytesToRead), bytesToRead, &decode_killswitch, &decode_error);
+ bufferValid += bytesRead;
+ if (bytesRead == 0)
+ {
+ readState = ENDOFFILE;
+ }
+ }
+ }
+ break;
+ case ENDOFFILE:
+ resampler->Flush();
+ readState = FLUSHING;
+
+ }
+
+ // now, resample
+ size_t inputBytes = bufferValid;
+ size_t bytesDone;
+
+ bytesDone = resampler->Convert(buffer, &inputBytes, outputBuffer, sizeBytes);
+ bytesResampled += bytesDone;
+
+ // if we didn't use all of our input buffer, then we'll copy what's left to the beginning
+ if (inputBytes)
+ memmove(buffer, buffer + (bufferValid - inputBytes), inputBytes);
+
+ // mark the number of bytes of data still valid in the input buffer
+ bufferValid = inputBytes;
+
+ if (!bytesDone && readState == FLUSHING)
+ readState = DONE;
+
+ if (bytesResampled != origSize && readState != DONE) // if we didn't provide enough data to fill the output buffer
+ {
+ sizeBytes = origSize - bytesResampled;
+ outputBuffer = origBuffer + bytesResampled;
+ goto read_again;
+ }
+
+
+
+ return bytesResampled;
+
+}
+#define CBCLASS ResamplingReader
+START_DISPATCH;
+CB(IFC_AUDIOSTREAM_READAUDIO, ReadAudio)
+END_DISPATCH;
diff --git a/Src/Winamp/ResamplingReader.h b/Src/Winamp/ResamplingReader.h
new file mode 100644
index 00000000..d080aa96
--- /dev/null
+++ b/Src/Winamp/ResamplingReader.h
@@ -0,0 +1,38 @@
+#ifndef NULLSOFT_WINAMP_RESAMPLINGREADER_H
+#define NULLSOFT_WINAMP_RESAMPLINGREADER_H
+
+#include "../Agave/DecodeFile/ifc_audiostream.h"
+#include "Resampler.h"
+#include "CommonReader.h"
+// TODO: should probably pass in a sample frame size (nch*bps/8) so that we can have an integral number of samples in the buffer
+#define RESAMPLE_BUFFERSIZE 1024
+class ResamplingReader :public CommonReader
+{
+public:
+ ResamplingReader(Resampler *_resampler, CommonReader *_reader, size_t inputFrameSize);
+ ~ResamplingReader();
+ size_t ReadAudio(void *outputBuffer, size_t sizeBytes);
+
+
+protected:
+ RECVS_DISPATCH;
+
+private:
+ Resampler *resampler;
+ CommonReader *reader;
+
+ __int8 *buffer;
+ size_t bufferAlloc;
+ size_t bufferValid;
+
+ enum ReadState
+ {
+ READING=0,
+ ENDOFFILE=1,
+ FLUSHING=2,
+ DONE=3,
+ };
+ ReadState readState;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/SA.cpp b/Src/Winamp/SA.cpp
new file mode 100644
index 00000000..251e0c45
--- /dev/null
+++ b/Src/Winamp/SA.cpp
@@ -0,0 +1,314 @@
+/*
+Spectrum Analyzer
+*/
+
+#include "Main.h"
+#include <math.h>
+#include "../nu/threadname.h"
+
+static int last_pos;
+typedef struct sa_l
+{
+ int timestamp;
+ unsigned char data[2*75];
+ char which;
+} sa_l;
+
+static int sa_fps = 76;
+static sa_l *sa_bufs;
+static int sa_position;
+static int sa_length, sa_size;
+static CRITICAL_SECTION cs;
+
+void sa_init(int numframes)
+{
+ EnterCriticalSection(&cs);
+ sa_length=0;
+ if (numframes < 1) numframes = 1;
+
+ if (numframes > sa_size)
+ {
+ free(sa_bufs);
+ sa_bufs = (sa_l *)calloc(numframes, sizeof(sa_l));
+ sa_size=numframes;
+ }
+ sa_position = 0;
+ sa_length = numframes;
+ last_pos = 0;
+ LeaveCriticalSection(&cs);
+}
+
+void sa_deinit(void)
+{
+ EnterCriticalSection(&cs);
+ //if (sa_bufs)
+// {
+// free(sa_bufs);
+// sa_bufs = 0;
+ sa_length = 0;
+ //}
+ LeaveCriticalSection(&cs);
+}
+
+int sa_add(char *values, int timestamp, int csa)
+{
+ EnterCriticalSection(&cs);
+ if (!sa_bufs || sa_length == 0)
+ {
+ LeaveCriticalSection(&cs);
+ return 1;
+ }
+
+ if (sa_length == 1)
+ {
+ sa_position = 0;
+ }
+ if (csa == 3) csa = 1; // dont let it happen unless it has a high bit set
+ csa &= 0x7fffffff;
+
+ sa_bufs[sa_position].timestamp = timestamp;
+ sa_bufs[sa_position].which = (char)csa;
+
+ if (csa & 1)
+ {
+ memcpy(sa_bufs[sa_position].data, values, 75);
+ values += 75;
+ }
+ else
+ memset(sa_bufs[sa_position].data, 0, 75);
+
+ if (csa & 2)
+ memcpy(sa_bufs[sa_position].data + 75, values, 75);
+ else
+ memset(sa_bufs[sa_position].data + 75, 0, 75);
+
+ sa_position++;
+ if (sa_position >= sa_length) sa_position -= sa_length;
+ LeaveCriticalSection(&cs);
+ return 0;
+}
+
+char *sa_get(int timestamp, int csa, char data[75*2+8])
+{
+ static int sa_pos;
+ int closest = 1000000, closest_v = -1;
+ EnterCriticalSection(&cs);
+
+ if (!sa_bufs || sa_length==0)
+ {
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+
+ if (sa_length == 1)
+ {
+ memcpy(data, sa_bufs[0].data, 75*2);
+ LeaveCriticalSection(&cs);
+ return (data);
+ }
+
+ int i = last_pos;
+ for (int x = 0; x < sa_length; x ++)
+ {
+ if (i >= sa_length) i = 0;
+ int d = timestamp - sa_bufs[i].timestamp;
+ if (d < 0) d = -d;
+ if (d < closest)
+ {
+ closest = d;
+ closest_v = i;
+ }
+ else if (closest <= 6) break;
+ i++;
+ }
+
+ if (closest < 400 && closest_v >= 0 && sa_bufs[closest_v].which & csa)
+ {
+ sa_pos = 0;
+ last_pos = closest_v;
+ memcpy(data, sa_bufs[closest_v].data, 75*2);
+ LeaveCriticalSection(&cs);
+ return data;
+ }
+
+ if (closest_v < 0 || !(sa_bufs[closest_v].which & csa) || closest > 400)
+ {
+ memset(data, 0, 75);
+ data[(sa_pos % 150) >= 75 ? 149 - (sa_pos % 150) : (sa_pos % 150)] = 15;
+ for (int x = 0; x < 75; x ++)
+ data[x + 75] = (char) (int) (7.0 * sin((sa_pos + x) * 0.1));
+ sa_pos++;
+ LeaveCriticalSection(&cs);
+ return data;
+ }
+ LeaveCriticalSection(&cs);
+ return 0;
+}
+
+volatile int sa_override;
+void export_sa_setreq(int want)
+{
+ EnterCriticalSection(&cs);
+ sa_override = want;
+ LeaveCriticalSection(&cs);
+}
+
+char *export_sa_get_deprecated()
+{
+ static char data[75*2 + 8];
+ int now = in_getouttime();
+ char *p = sa_get(now, 3, data);
+ if (!p) memset(data, 0, 75*2);
+
+ return data;
+}
+
+char *export_sa_get(char data[75*2 + 8])
+{
+ try
+ {
+ int now = in_getouttime();
+ char *p = sa_get(now, 3, data);
+ if (!p) memset(data, 0, 75*2);
+ }
+ catch(...) {}
+ return data;
+}
+
+#pragma optimize("", off) // for some reason, optimizations are breaking the case statement in bivis_thread
+#define KILL_EVENT 0
+#define BLANK_EVENT 1
+#define ON_EVENT 2
+#define NUM_EVENTS 3
+
+#define saKillEvent saEvents[0]
+#define saBlankEvent saEvents[1]
+#define saOnEvent saEvents[2]
+
+HANDLE saEvents[NUM_EVENTS] = {0};
+
+static int SA_Wait()
+{
+ if (WaitForSingleObject(saKillEvent, 16) == WAIT_OBJECT_0)
+ return KILL_EVENT;
+
+ if (WaitForSingleObject(saBlankEvent, 0) == WAIT_OBJECT_0)
+ return BLANK_EVENT;
+
+ return WaitForMultipleObjects(NUM_EVENTS, saEvents, FALSE, INFINITE)-WAIT_OBJECT_0;
+}
+
+static DWORD WINAPI bivis_thread(void *none)
+{
+ int cycleCount=0;
+ __int8 data[75*2 + 8] = {0};
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+ SetThreadName((DWORD)-1, "Classic Viz");
+ while (1)
+ {
+ switch(SA_Wait())
+ {
+ case KILL_EVENT:
+ return 0;
+
+ case BLANK_EVENT:
+ draw_sa(NULL, 1);
+ break;
+
+ case ON_EVENT:
+ {
+ int draw=0;
+
+ if (++cycleCount < config_saref)
+ draw=0;
+ else
+ {
+ cycleCount=0;
+ draw=1;
+ }
+
+ if (config_sa
+ && !paused
+ && playing
+ && !config_minimized
+ && (config_mw_open || (config_pe_open && config_pe_width >= 350 && config_pe_height != 14))
+ && (!config_disvis || !vis_running()))
+ {
+ int a = in_getouttime();
+ int t = config_sa;
+ //if ((config_windowshade&&config_mw_open) && t == 1) t=4;
+ char *c = sa_get(a, t, data);
+
+ if (c)
+ {
+ if (t == 2) c += 75;
+ else memset(c + 75, 0, 4);
+ draw_sa((unsigned char*)c, draw);
+ }
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+#pragma optimize("", on)
+HANDLE saThread=0;
+void SpectralAnalyzer_Create()
+{
+ DWORD threadId = 0;
+ InitializeCriticalSection(&cs);
+ saKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ saBlankEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
+ saOnEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ saThread = (HANDLE) CreateThread(NULL, 256*1024, (LPTHREAD_START_ROUTINE) bivis_thread, 0, 0, &threadId);
+ //cut: done on thread - SetThreadPriority(saThread, THREAD_PRIORITY_HIGHEST);
+
+ sa_length=sa_size=0;
+
+ VU_Create();
+}
+
+void SpectralAnalyzer_Destroy()
+{
+ VU_Destroy();
+
+ SetEvent(saKillEvent);
+ WaitForSingleObject(saThread, INFINITE);
+ CloseHandle(saThread);
+ saThread = 0;
+
+ CloseHandle(saKillEvent);
+ CloseHandle(saBlankEvent);
+ CloseHandle(saOnEvent);
+ DeleteCriticalSection(&cs);
+
+ free(sa_bufs);
+ sa_bufs=0;
+ sa_size=0;
+}
+
+volatile int sa_curmode;
+
+/*
+@param mode -1==shutdown 0==none, 1==spectral analyzer, 2==oscilloscope
+*/
+
+void sa_setthread(int mode)
+{
+ if (mode == -1)
+ mode=0;
+
+ sa_curmode = mode;
+
+ if (mode)
+ {
+ SetEvent(saOnEvent);
+ }
+ else
+ {
+ ResetEvent(saOnEvent);
+ SetEvent(saBlankEvent);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/SABuffer.cpp b/Src/Winamp/SABuffer.cpp
new file mode 100644
index 00000000..dfe47c6c
--- /dev/null
+++ b/Src/Winamp/SABuffer.cpp
@@ -0,0 +1,139 @@
+#include "SABuffer.h"
+#include "fft.h"
+#include "../nsutil/window.h"
+#include <windows.h>
+
+static const float const_1_div_128_ = 1.0f / 128.0f; /* 8 bit multiplier */
+static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */
+static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */
+
+static void Int16_To_Float32(float *dest, void *sourceBuffer, signed int sourceStride, unsigned int count)
+{
+ signed short *src = (signed short*)sourceBuffer;
+
+ while (count--)
+ {
+ float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */
+ *dest = samp;
+
+ src += sourceStride;
+ dest++;
+ }
+}
+
+static void Int24_To_Float32(float *dest, void *sourceBuffer, signed int sourceStride, unsigned int count)
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+
+ while (count--)
+ {
+ signed long temp = (((long)src[0]) << 8);
+ temp = temp | (((long)src[1]) << 16);
+ temp = temp | (((long)src[2]) << 24);
+
+ *dest = (float)((double)temp * const_1_div_2147483648_);
+
+ src += sourceStride * 3;
+ dest++;
+ }
+}
+
+static void Int32_To_Float32(float *dest, void *sourceBuffer, signed int sourceStride, unsigned int count)
+{
+ int32_t *src = (int32_t *)sourceBuffer;
+
+ while (count--)
+ {
+ *dest = (float)((double)*src * const_1_div_2147483648_);
+
+ src += sourceStride;
+ dest++;
+ }
+}
+
+static void UInt8_To_Float32(float *dest, void *sourceBuffer, signed int sourceStride, unsigned int count)
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+
+ while (count--)
+ {
+ float samp = (*src - 128) * const_1_div_128_;
+ *dest = samp;
+
+ src += sourceStride;
+ dest++;
+ }
+}
+
+SABuffer::SABuffer()
+{
+ memset(&buffer, 0, sizeof(buffer));
+ used=0;
+ init=false;
+}
+
+void SABuffer::CopyHalf()
+{
+ memcpy(buffer[0], buffer[0]+SABUFFER_WINDOW_INCREMENT, (512-SABUFFER_WINDOW_INCREMENT)*sizeof(float));
+ memcpy(buffer[1], buffer[1]+SABUFFER_WINDOW_INCREMENT, (512-SABUFFER_WINDOW_INCREMENT)*sizeof(float));
+ used-=SABUFFER_WINDOW_INCREMENT;
+}
+
+void SABuffer::Clear()
+{
+ used=0;
+}
+
+void SABuffer::WindowToFFTBuffer(float *wavetrum)
+{
+ for (int i=0;i<512;i++)
+ {
+ wavetrum[i] = (buffer[0][i] + buffer[1][i]);
+ //*wavetrum++=0;
+ }
+ nsutil_window_Multiply_F32_IP(wavetrum, window, 512);
+}
+
+unsigned int SABuffer::AddToBuffer(char *samples, int numChannels, int bps, int ts, unsigned int numSamples)
+{
+ if (!init) {
+ nsutil_window_FillHann_F32_IP(window, 512); // TODO this could be hardcoded
+ init=true;
+ }
+
+ unsigned int toCopy = min((unsigned int)(512-used), numSamples);
+ switch (bps)
+ {
+ case 8:
+ UInt8_To_Float32(buffer[0]+used, samples, numChannels, toCopy);
+ if (numChannels > 1)
+ UInt8_To_Float32(buffer[1]+used, samples+1, numChannels, toCopy);
+ else
+ UInt8_To_Float32(buffer[1]+used, samples, numChannels, toCopy);
+ break;
+ case 16:
+ Int16_To_Float32(buffer[0]+used, samples, numChannels, toCopy);
+ if (numChannels > 1)
+ Int16_To_Float32(buffer[1]+used, samples+2, numChannels, toCopy);
+ else
+ Int16_To_Float32(buffer[1]+used, samples, numChannels, toCopy);
+ break;
+ case 24:
+ Int24_To_Float32(buffer[0]+used, samples, numChannels, toCopy);
+ if (numChannels > 1)
+ Int24_To_Float32(buffer[1]+used, samples+3, numChannels, toCopy);
+ else
+ Int24_To_Float32(buffer[1]+used, samples, numChannels, toCopy);
+ break;
+ case 32:
+ Int32_To_Float32(buffer[0]+used, samples, numChannels, toCopy);
+ if (numChannels > 1)
+ Int32_To_Float32(buffer[1]+used, samples+4, numChannels, toCopy);
+ else
+ Int32_To_Float32(buffer[1]+used, samples, numChannels, toCopy);
+ break;
+ }
+ used+=toCopy;
+ return toCopy;
+}
+
diff --git a/Src/Winamp/SABuffer.h b/Src/Winamp/SABuffer.h
new file mode 100644
index 00000000..8344f3e7
--- /dev/null
+++ b/Src/Winamp/SABuffer.h
@@ -0,0 +1,24 @@
+#ifndef NULLSOFT_WINAMP_SA_BUFFER_H
+#define NULLSOFT_WINAMP_SA_BUFFER_H
+
+#define SABUFFER_WINDOW_INCREMENT 256
+
+class SABuffer
+{
+public:
+ SABuffer();
+ void WindowToFFTBuffer(float *wavetrum);
+ unsigned int AddToBuffer(char *samples, int numChannels, int bps, int ts, unsigned int numSamples);
+ bool Full() { return used == 512; }
+ void CopyHalf();
+ void Clear();
+private:
+
+ float buffer[2][512];
+ float window[512];
+ size_t used;
+ bool init;
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/SHELL.CPP b/Src/Winamp/SHELL.CPP
new file mode 100644
index 00000000..a434799e
--- /dev/null
+++ b/Src/Winamp/SHELL.CPP
@@ -0,0 +1,85 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include "../nu/ns_wc.h"
+extern "C"
+{
+ HRESULT ResolveShortCut(HWND hwnd, LPCWSTR pszShortcutFile, LPWSTR pszPath)
+ {
+ IShellLinkW *psl = 0;
+ WIN32_FIND_DATAW wfd = {0};
+
+ *pszPath = 0; // assume failure
+
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void **) & psl);
+ if (SUCCEEDED(hres))
+ {
+ IPersistFile *ppf = 0;
+ hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf); // OLE 2! Yay! --YO
+ if (SUCCEEDED(hres))
+ {
+ hres = ppf->Load(pszShortcutFile, STGM_READ);
+ if (SUCCEEDED(hres))
+ {
+ hres = psl->Resolve(hwnd, SLR_ANY_MATCH);
+ if (SUCCEEDED(hres))
+ {
+ wchar_t szGotPath[MAX_PATH] = {0};
+ StringCchCopyW(szGotPath, MAX_PATH, pszShortcutFile);
+ hres = psl->GetPath(szGotPath, MAX_PATH, & wfd,
+ SLGP_SHORTPATH );
+ StringCchCopyW(pszPath, MAX_PATH, szGotPath);
+ }
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ return SUCCEEDED(hres);
+ }
+
+ /*void CreateShortCut(HWND hwnd, LPCSTR pszShortcutFile, LPCSTR pszExe, LPCSTR pszArg, int iconindex)
+ {
+ HRESULT hres;
+ IShellLink* psl;
+
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_IShellLink, (void **) & psl);
+ if (SUCCEEDED(hres))
+ {
+ IPersistFile* ppf;
+
+ hres = psl->QueryInterface(IID_IPersistFile, (void **) & ppf); // OLE 2! Yay! --YO
+ if (SUCCEEDED(hres))
+ {
+ wchar_t wsz[MAX_PATH] = {0};
+ MultiByteToWideCharSZ(CP_ACP, 0, pszShortcutFile, -1, wsz, MAX_PATH);
+
+ hres = psl->SetPath(pszExe);
+ if (pszArg)
+ {
+ psl->SetArguments(pszArg);
+ }
+ psl->SetIconLocation(pszExe, iconindex);
+
+ if (SUCCEEDED(hres))
+ {
+ ppf->Save(wsz, TRUE);
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ }*/
+
+ void Shell_Free(void *p)
+ {
+ CoTaskMemFree(p);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/SPLASH.cpp b/Src/Winamp/SPLASH.cpp
new file mode 100644
index 00000000..da3ca50b
--- /dev/null
+++ b/Src/Winamp/SPLASH.cpp
@@ -0,0 +1,56 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+
+#define SPLASH_TIMER 34
+//#define MODAL_SPLASHSCREEN
+
+static INT_PTR CALLBACK splashFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static int wait;
+void splashDlg(int wait_in_ms)
+{
+ wait = wait_in_ms;
+#ifdef MODAL_SPLASHSCREEN
+ DialogBox(hMainInstance, MAKEINTRESOURCE(IDD_SPLASH), NULL, splashFunc);
+#else
+ CreateDialogW(hMainInstance, MAKEINTRESOURCE(IDD_SPLASH), NULL, splashFunc);
+#endif
+}
+
+static INT_PTR CALLBACK splashFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ RECT r;
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SPLASHIMG), &r);
+ SetWindowPos(hwndDlg, 0, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER);
+ SetTimer(hwndDlg, SPLASH_TIMER, wait, NULL);
+ return 0;
+ case WM_KEYDOWN:
+case WM_LBUTTONDOWN: case WM_RBUTTONDOWN:
+#ifdef MODAL_SPLASHSCREEN
+ EndDialog(hwndDlg, 0);
+#else
+ DestroyWindow(hwndDlg);
+#endif
+ return 0;
+ case WM_TIMER:
+ if (wParam == SPLASH_TIMER)
+ {
+#ifdef MODAL_SPLASHSCREEN
+ EndDialog(hwndDlg, 1);
+#else
+ DestroyWindow(hwndDlg);
+#endif
+ }
+ return 0;;
+ }
+ return 0;
+}
diff --git a/Src/Winamp/SYSTRAY.cpp b/Src/Winamp/SYSTRAY.cpp
new file mode 100644
index 00000000..b154700f
--- /dev/null
+++ b/Src/Winamp/SYSTRAY.cpp
@@ -0,0 +1,124 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include <stdarg.h>
+#include "strutil.h"
+
+#define SYSTRAY_ICON 502
+#define SYSTRAY_WINDOW hMainWindow
+
+int systray_intray = 0;
+
+static BOOL systray_add(HWND hwnd, UINT uID, LPWSTR lpszTip);
+static BOOL systray_del(HWND hwnd, UINT uID);
+static BOOL systray_mod(HWND hwnd, UINT uID, LPWSTR lpszTip);
+static HICON hhIcon;
+static int hicon_index=-1;
+
+void systray_minimize(wchar_t *tip)
+{
+ extern int geticonid(int x);
+ int newindex=geticonid(config_sticon);
+ if (!SYSTRAY_WINDOW) return;
+ if (!hhIcon || hicon_index != newindex) {
+ if (hhIcon) {
+ DestroyIcon(hhIcon);
+ }
+ if(newindex == -666) {
+ wchar_t tmp[MAX_PATH] = {0};
+ StringCchPrintfW(tmp,MAX_PATH,L"%s\\winamp.ico",CONFIGDIR);
+ if(!PathFileExistsW(tmp)) {
+ hhIcon = (HICON)LoadImageW(hMainInstance,MAKEINTRESOURCEW(ICON_XP),IMAGE_ICON,16,16,LR_SHARED);
+ }
+ else {
+ hhIcon = (HICON)LoadImageW(0,tmp,IMAGE_ICON,16,16,LR_LOADFROMFILE);
+ }
+ }
+ else {
+ hhIcon = (HICON)LoadImageW(hMainInstance,MAKEINTRESOURCEW(newindex),IMAGE_ICON,16,16,LR_SHARED);
+ }
+ }
+ hicon_index=newindex;
+ if (!systray_intray) {
+ systray_add(SYSTRAY_WINDOW,SYSTRAY_ICON,tip);
+ systray_intray = 1;
+ }
+ else {
+ systray_mod(SYSTRAY_WINDOW,SYSTRAY_ICON,tip);
+ }
+}
+
+void systray_restore(void)
+{
+ if (systray_intray) {
+ systray_del(SYSTRAY_WINDOW,SYSTRAY_ICON);
+ systray_intray = 0;
+ if (hhIcon) {
+ DestroyIcon(hhIcon);
+ hhIcon=NULL;
+ hicon_index=-1;
+ }
+ }
+}
+
+static void mktipstr(wchar_t *out, wchar_t *in, size_t outlen)
+{
+ wchar_t *nextOut;
+ size_t outpos=0;
+ while (outpos < outlen-1 && *in)
+ {
+ if (*in == L'&')
+ {
+ if ((outpos+=2) >= outlen-1) break;
+ *out++=L'&';
+ *out++=L'&';
+ }
+
+ CopyCharW(out, in);
+ nextOut = CharNextW(out);
+ in = CharNextW(in);
+ outpos+=(nextOut-out);
+ out=nextOut;
+ }
+ *out=0;
+}
+
+static BOOL systray_add(HWND hwnd, UINT uID, LPWSTR lpszTip)
+{
+ NOTIFYICONDATAW tnid = {0};
+ tnid.cbSize = sizeof(NOTIFYICONDATAW);
+ tnid.hWnd = hwnd;
+ tnid.uID = uID;
+ tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
+ tnid.uCallbackMessage = WM_WA_SYSTRAY;
+ tnid.hIcon = hhIcon;
+ mktipstr(tnid.szTip,lpszTip,sizeof(tnid.szTip)/sizeof(wchar_t));
+ return Shell_NotifyIconW(NIM_ADD, &tnid);
+}
+
+static BOOL systray_del(HWND hwnd, UINT uID)
+{
+ NOTIFYICONDATAW tnid = {0};
+ tnid.cbSize = sizeof(NOTIFYICONDATAW);
+ tnid.hWnd = hwnd;
+ tnid.uID = uID;
+ return(Shell_NotifyIconW(NIM_DELETE, &tnid));
+}
+
+static BOOL systray_mod(HWND hwnd, UINT uID, LPWSTR lpszTip)
+{
+ NOTIFYICONDATAW tnid = {0};
+ tnid.cbSize = sizeof(NOTIFYICONDATAW);
+ tnid.hWnd = hwnd;
+ tnid.uID = uID;
+ tnid.uFlags = NIF_TIP|NIF_ICON;
+ tnid.hIcon = hhIcon;
+ mktipstr(tnid.szTip,lpszTip,sizeof(tnid.szTip)/sizeof(wchar_t));
+ return (Shell_NotifyIconW(NIM_MODIFY, &tnid));
+} \ No newline at end of file
diff --git a/Src/Winamp/SecurityCOM.cpp b/Src/Winamp/SecurityCOM.cpp
new file mode 100644
index 00000000..da27ca62
--- /dev/null
+++ b/Src/Winamp/SecurityCOM.cpp
@@ -0,0 +1,100 @@
+#include "SecurityCOM.h"
+#include "JSAPI2_Security.h"
+#include "JSAPI.h"
+enum
+{
+ DISP_SECURITY_SETACTIONAUTHORIZATION = 777,
+};
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT SecurityCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("SetActionAuthorization", DISP_SECURITY_SETACTIONAUTHORIZATION )
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT SecurityCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT SecurityCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT SecurityCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ case DISP_SECURITY_SETACTIONAUTHORIZATION:
+ {
+ JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 2, 4);
+ JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
+ const wchar_t *key = JSAPI_PARAM(pdispparams, 1).bstrVal;
+ switch(JSAPI_NUM_PARAMS(pdispparams))
+ {
+ case 2: // key and authorization
+ JSAPI2::security.SetActionAuthorization(key, 0, 0, JSAPI_PARAM(pdispparams, 2).lVal);
+ break;
+ case 3: // key, group and authorization
+ JSAPI2::security.SetActionAuthorization(key, JSAPI_PARAM(pdispparams, 2).bstrVal, 0, JSAPI_PARAM(pdispparams, 3).lVal);
+ break;
+ case 4: // key, group, action and authorization
+ JSAPI2::security.SetActionAuthorization(key, JSAPI_PARAM(pdispparams, 2).bstrVal, JSAPI_PARAM(pdispparams, 3).bstrVal, JSAPI_PARAM(pdispparams, 4).lVal);
+ break;
+ }
+
+ return S_OK;
+ }
+ break;
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP SecurityCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG SecurityCOM::AddRef(void)
+{
+ return 0;
+}
+
+ULONG SecurityCOM::Release(void)
+{
+ return 0;
+}
+
+
+void SecurityCOM::SetActionAuthorization(const wchar_t *key, const wchar_t *group, const wchar_t *action, int authorization)
+{
+
+} \ No newline at end of file
diff --git a/Src/Winamp/SecurityCOM.h b/Src/Winamp/SecurityCOM.h
new file mode 100644
index 00000000..bc442392
--- /dev/null
+++ b/Src/Winamp/SecurityCOM.h
@@ -0,0 +1,22 @@
+#pragma once
+
+/* part of API1, but provides access to the API2 security settings */
+#include <ocidl.h>
+
+class SecurityCOM : public IDispatch
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+private:
+ void SetActionAuthorization(const wchar_t *key, const wchar_t *group, const wchar_t *action, int authorization);
+
+
+};
diff --git a/Src/Winamp/ServiceFactory.cpp b/Src/Winamp/ServiceFactory.cpp
new file mode 100644
index 00000000..3eecd90e
--- /dev/null
+++ b/Src/Winamp/ServiceFactory.cpp
@@ -0,0 +1,25 @@
+#include "main.h"
+#include "api.h"
+#include <api/service/waservicefactorybase.h>
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS waServiceFactoryX
+START_DISPATCH;
+ CB(WASERVICEFACTORY_GETSERVICETYPE, x_getServiceType);
+ CB(WASERVICEFACTORY_GETSERVICENAME, x_getServiceName);
+ CB(WASERVICEFACTORY_GETGUID, getGuid);
+ case WASERVICEFACTORY_GETINTERFACE:
+ switch (nparam) {
+ default: cb<CBCLASS>(&CBCLASS::getInterface, retval, params); break;
+ case 0: cb<CBCLASS>(&CBCLASS::_RETIRED_getInterface, retval, params); break;
+ }
+ break;
+ CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, supportNonLockingGetInterface);
+ CB(WASERVICEFACTORY_RELEASEINTERFACE, releaseInterface);
+ CB(WASERVICEFACTORY_GETTESTSTRING, getTestString);
+ CB(WASERVICEFACTORY_SERVICENOTIFY, serviceNotify);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/ServiceManager.cpp b/Src/Winamp/ServiceManager.cpp
new file mode 100644
index 00000000..5206057e
--- /dev/null
+++ b/Src/Winamp/ServiceManager.cpp
@@ -0,0 +1,285 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "ServiceManager.h"
+#include <api.h>
+#include <api/service/waservicefactory.h>
+#include "../nu/AutoLock.h"
+#include <api/syscb/callbacks/syscb.h>
+#include <api/syscb/callbacks/svccb.h>
+
+using namespace Nullsoft::Utility;
+
+
+struct Counter
+{
+ Counter( waServiceFactory *_owner, void *_ptr ) : ptr( _ptr ), owner( _owner ) {}
+
+ void *ptr;
+ waServiceFactory *owner;
+};
+
+ServiceManager::ServiceManager() : serviceGuard(512)
+{}
+
+int ServiceManager::service_register( waServiceFactory *svc )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_register" ) );
+ FOURCC service_type = svc->getServiceType();
+
+ // add the service to the master list
+ services.push_back( svc );
+
+ // add it to the by-type lookup
+ ServiceList *&type_list = services_by_type[ service_type ];
+ if ( !type_list )
+ type_list = new ServiceList;
+
+ type_list->push_back( svc );
+
+ // send notifications
+ svc->serviceNotify( SvcNotify::ONREGISTERED );
+ WASABI_API_SYSCB->syscb_issueCallback( SysCallback::SERVICE, SvcCallback::ONREGISTER, (intptr_t)service_type, reinterpret_cast<intptr_t>( svc ) );
+
+ return 1;
+}
+
+int ServiceManager::service_deregister( waServiceFactory *svc )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_deregister" ) );
+ FOURCC service_type = svc->getServiceType();
+
+ // remove it from the master list
+ //services.eraseObject(svc);
+ auto it = std::find( services.begin(), services.end(), svc );
+ if ( it != services.end() )
+ services.erase( it );
+
+ // and from the type lookup map
+ ServiceList *type_list = services_by_type[ service_type ];
+ if ( type_list )
+ {
+ //type_list->eraseObject(svc);
+ auto it = std::find( type_list->begin(), type_list->end(), svc );
+ if ( it != type_list->end() )
+ type_list->erase( it );
+ }
+
+ WASABI_API_SYSCB->syscb_issueCallback( SysCallback::SERVICE, SvcCallback::ONDEREGISTER, (intptr_t)service_type, reinterpret_cast<intptr_t>( svc ) );
+ svc->serviceNotify( SvcNotify::ONDEREGISTERED );
+
+ return 1;
+}
+
+size_t ServiceManager::service_getNumServices( FOURCC svc_type )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_getNumServices" ) );
+ if ( svc_type )
+ {
+ ServiceList *type_list = services_by_type[ svc_type ];
+ if ( type_list )
+ return type_list->size();
+ else
+ return 0;
+ }
+ else
+ return services.size();
+}
+
+waServiceFactory *ServiceManager::service_enumService( FOURCC svc_type, size_t n )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_enumService" ) );
+ ServiceList *type_list = 0;
+ if ( svc_type )
+ type_list = services_by_type[ svc_type ];
+ else
+ type_list = &services;
+
+ if ( type_list && n < type_list->size() )
+ return type_list->at( n );
+ else
+ return 0;
+}
+
+waServiceFactory *ServiceManager::service_getServiceByGuid( GUID guid )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_getServiceByGuid" ) );
+ for ( waServiceFactory *l_service : services )
+ {
+ if ( l_service->getGuid() == guid )
+ return l_service;
+ }
+
+ return NULL;
+}
+
+int ServiceManager::service_lock( waServiceFactory *owner, void *svcptr )
+{
+ if ( owner == NULL || svcptr == NULL )
+ return 0;
+
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_lock" ) );
+ locks.push_back( new Counter( owner, svcptr ) );
+
+ return 1;
+}
+
+int ServiceManager::service_clientLock( void *svcptr )
+{
+ return 1;
+}
+
+int ServiceManager::service_release( void *svcptr )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_release" ) );
+ for ( size_t i = 0; i != locks.size(); i++ )
+ {
+ if ( locks[ i ]->ptr == svcptr )
+ {
+ void *ptr = locks[ i ]->ptr;
+ waServiceFactory *owner = locks[ i ]->owner;
+
+ delete locks[ i ];
+
+ locks.erase( locks.begin() + i );
+ owner->releaseInterface( ptr );
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+const char *ServiceManager::service_getTypeName( FOURCC svc_type )
+{
+ return NULL;
+}
+
+int ServiceManager::service_unlock( void *svcptr )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_unlock" ) );
+ for ( size_t i = 0; i != locks.size(); i++ )
+ {
+ if ( locks[ i ]->ptr == svcptr )
+ {
+ delete locks[ i ];
+ locks.erase( locks.begin() + i );
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int ServiceManager::service_isvalid( FOURCC svctype, waServiceFactory *service )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_isvalid" ) );
+ //return !!services.contains(service);
+ return ( services.end() != std::find( services.begin(), services.end(), service ) );
+}
+
+int ServiceManager::service_compactDuplicates( waServiceFactory *me )
+{
+ // first, find 'me'
+ GUID guid = me->getGuid();
+
+ size_t me_index = 0;
+
+ //bool found = services.findItem(me, &me_index);
+ //if (!found)
+ // return 1;
+ if ( services.end() == std::find( services.begin(), services.end(), me ) )
+ return 1;
+
+ ServiceList *type_list = services_by_type[ me->getServiceType() ];
+
+ // go in reverse order because service to compact is likely at the end
+ size_t n = services.size();
+ while ( n-- ) // n is guaranteed to be >0 because otherwise the 'find' loop above would have failed
+ {
+ waServiceFactory *n_service = services[ n ];
+ if ( n != me_index && n_service != me && n_service->getGuid() == guid )
+ {
+ services[ me_index ] = n_service;
+ services.erase( services.begin() + n );
+
+ // fix up our by-type cache
+ if ( type_list )
+ {
+ size_t me_index = 0;
+ size_t n_index = 0;
+
+ //----------------------------------------------------
+ // Replaced with code below this commented code
+ //if (type_list->findItem_reverse(n_service, &n_index) && type_list->findItem(me, &me_index))
+ //{
+ // type_list->at(me_index) = n_service;
+ // type_list->eraseindex(n_index);
+ //}
+
+ bool foundService = false;
+ for ( int idx = type_list->size() - 1; idx >= 0; idx-- )
+ {
+ if ( type_list->at( idx ) == n_service )
+ {
+ foundService = true;
+ n_index = idx;
+ break;
+ }
+ }
+
+ bool foundMe = false;
+ for ( int idx2 = 0; idx2 < type_list->size(); idx2++ )
+ {
+ if ( type_list->at( idx2 ) == me )
+ {
+ foundMe = true;
+ me_index = idx2;
+ break;
+ }
+ }
+
+ if ( foundService && foundMe )
+ {
+ type_list->at( me_index ) = n_service;
+ type_list->erase( type_list->begin() + n_index );
+ }
+ //--------------------------------------------------
+ }
+
+ me->serviceNotify( SvcNotify::ONDEREGISTERED );
+
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS ServiceManager
+START_DISPATCH;
+CB( API_SERVICE_SERVICE_REGISTER, service_register );
+CB( API_SERVICE_SERVICE_DEREGISTER, service_deregister );
+CB( API_SERVICE_SERVICE_GETNUMSERVICES, service_getNumServices );
+CB( API_SERVICE_SERVICE_ENUMSERVICE, service_enumService );
+CB( API_SERVICE_SERVICE_GETSERVICEBYGUID, service_getServiceByGuid );
+CB( API_SERVICE_SERVICE_LOCK, service_lock );
+CB( API_SERVICE_SERVICE_CLIENTLOCK, service_clientLock );
+CB( API_SERVICE_SERVICE_RELEASE, service_release );
+CB( API_SERVICE_SERVICE_GETTYPENAME, service_getTypeName );
+CB( API_SERVICE_SERVICE_UNLOCK, service_unlock );
+CB( API_SERVICE_ISVALID, service_isvalid );
+CB( API_SERVICE_COMPACT_DUPLICATES, service_compactDuplicates );
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/ServiceManager.h b/Src/Winamp/ServiceManager.h
new file mode 100644
index 00000000..b8facf35
--- /dev/null
+++ b/Src/Winamp/ServiceManager.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_SERVICEMANAGERH
+#define NULLSOFT_SERVICEMANAGERH
+
+#include <api/service/api_service.h>
+#include "../nu/AutoLock.h"
+#include <vector>
+#include <map>
+
+struct Counter;
+
+class ServiceManager : public api_service
+{
+public:
+ ServiceManager();
+
+ int service_register( waServiceFactory *svc );
+ int service_deregister( waServiceFactory *svc );
+
+ size_t service_getNumServices( FOURCC svc_type );
+
+ waServiceFactory *service_enumService( FOURCC svc_type, size_t n );
+ waServiceFactory *service_getServiceByGuid( GUID guid );
+
+ int service_lock( waServiceFactory *owner, void *svcptr );
+ int service_clientLock( void *svcptr );
+ int service_release( void *svcptr );
+
+ const char *service_getTypeName( FOURCC svc_type );
+
+ int service_unlock( void *svcptr );
+ int service_isvalid( FOURCC svctype, waServiceFactory *service );
+ int service_compactDuplicates( waServiceFactory *me );
+
+protected:
+ RECVS_DISPATCH;
+
+private:
+ Nullsoft::Utility::LockGuard serviceGuard;
+ typedef std::vector<waServiceFactory *> ServiceList;
+ ServiceList services;
+ std::vector<Counter *> locks;
+ std::map<FOURCC, ServiceList *> services_by_type;
+};
+
+extern api_service *serviceManager;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Set.cpp b/Src/Winamp/Set.cpp
new file mode 100644
index 00000000..fc0bdad8
--- /dev/null
+++ b/Src/Winamp/Set.cpp
@@ -0,0 +1,1287 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include "WinampAttributes.h"
+#include "ExternalCOM.h"
+#include "../nu/AutoWide.h"
+
+static int dc_pos=0;
+extern int is_fullscreen_video;
+extern int g_fsapp;
+
+static BOOL HasParent(HWND hwnd)
+{
+ return ((0 != (WS_CHILD & GetWindowLongPtrW(hwnd, GWL_STYLE))) && NULL != GetParent(hwnd));
+}
+
+void do_caption_autoscroll(void)
+{
+ wchar_t buf[4096]=L"";
+ if (dc_pos < (int)lstrlenW(caption))
+ {
+ StringCchCopyW(buf,4096, caption+dc_pos);
+ StringCchCatW(buf,4096,L" *** ");
+ StringCchCopyW(buf+lstrlenW(buf),4096-lstrlenW(buf),caption);
+ dc_pos++;
+ }
+ else
+ {
+ StringCchCopyW(buf,4096,L" *** "+dc_pos-lstrlenW(caption));
+ StringCchCatW(buf,4096, caption);
+ StringCchCopyW(buf+lstrlenW(buf),4096-lstrlenW(buf), L" *** ");
+ if (++dc_pos >= (int)lstrlenW(caption)+3) dc_pos=0;
+ }
+ SetWindowLong(hMainWindow,GWL_STYLE,GetWindowLongW(hMainWindow,GWL_STYLE)&~(WS_CAPTION));
+ SetWindowTextW(hMainWindow,buf);
+ SetWindowLong(hMainWindow,GWL_STYLE,GetWindowLongW(hMainWindow,GWL_STYLE)|(WS_CAPTION));
+}
+
+void set_caption(int alt_cb, wchar_t *format, ...)
+{
+ va_list v;
+ if (format)
+ {
+ va_start(v,format);
+ StringCchVPrintfW(caption, CAPTION_SIZE, format, v);
+ va_end(v);
+ }
+
+ SetWindowLong(hMainWindow,GWL_STYLE,GetWindowLongW(hMainWindow,GWL_STYLE)&~(WS_CAPTION));
+ SetWindowTextW(hMainWindow,caption);
+ SetWindowLong(hMainWindow,GWL_STYLE,GetWindowLongW(hMainWindow,GWL_STYLE)|(WS_CAPTION));
+ dc_pos=0;
+ if (systray_intray) systray_minimize(caption);
+
+ // TODO in some cases this is crashing based on crash reports (issue with 'now playling' ??)
+ JSAPI1_CurrentTitleChanged();
+ PostMessageW(hMainWindow,WM_WA_IPC,(!alt_cb?IPC_CB_MISC_TITLE:IPC_CB_MISC_TITLE_RATING),IPC_CB_MISC);
+ SendNotifyMessage(HWND_BROADCAST, songChangeBroadcastMessage, 0, 0);
+}
+
+void set_taskbar(void)
+{
+ static int a;
+ if (config_taskbar == 1 || config_taskbar == 2)
+ {
+ systray_minimize(caption);
+ }
+ else
+ {
+ if (systray_intray) systray_restore();
+ }
+
+ ShowWindow(hMainWindow,SW_HIDE);
+
+ if (config_taskbar == 1 || config_taskbar == 3)
+ SetWindowLong(hMainWindow,GWL_EXSTYLE,GetWindowLongW(hMainWindow,GWL_EXSTYLE)|WS_EX_TOOLWINDOW);
+ else
+ SetWindowLong(hMainWindow,GWL_EXSTYLE,GetWindowLongW(hMainWindow,GWL_EXSTYLE)&~WS_EX_TOOLWINDOW);
+ if (a)
+ {
+ extern int deferring_show;
+ if (!deferring_show) ShowWindow(hMainWindow,SW_SHOWNA);
+ }
+ a=1;
+}
+
+// better enter embedcs before calling this func
+static void doMyDirtyShitholeDockingShit(HWND myWnd, RECT newr, int sedge) // -1 to do all
+{
+ RECT oldr = {0};
+ GetWindowRect(myWnd, &oldr);
+ if (myWnd == hMainWindow)
+ FixMainWindowRect(&oldr);
+
+ for (int whichedge = 0; whichedge < 2; whichedge++) // not always used
+ {
+ int diff;
+ embedWindowState *p=embedwndlist;
+
+ if (sedge >= 0)
+ whichedge=sedge;
+
+ if (whichedge == 0)
+ diff=newr.bottom - oldr.bottom;
+ else
+ diff = newr.right - oldr.right;
+
+ // move any windows docked to the bottom, bottom. recursively.
+ if (diff) for (int x = 0; ; x ++)
+ {
+ HWND dockwnd=NULL;
+ RECT oldrect;
+ int vis=0;
+
+ if ( x == 0 )
+ {
+ dockwnd = hMainWindow;
+ vis = config_mw_open;
+ }
+ else if ( x == 1 )
+ {
+ dockwnd = hEQWindow;
+ vis = config_eq_open;
+ }
+ else if ( x == 2 )
+ {
+ dockwnd = hPLWindow;
+ vis = config_pe_open;
+ }
+//else if (x == 3) { dockwnd=hMBWindow; vis=0; } //config_mb_open; }
+ else if ( x == 4 )
+ {
+ dockwnd = hVideoWindow;
+ vis = config_video_open;
+ }
+ else
+ {
+ if ( !p )
+ break;
+
+ dockwnd = p->me;
+ vis = IsWindowVisible( p->me );
+ }
+ GetWindowRect(dockwnd,&oldrect);
+ if (!x)
+ FixMainWindowRect(&oldrect);
+
+ if (dockwnd != myWnd)
+ {
+ int isdocked;
+ if (!whichedge)
+ isdocked=oldrect.top == oldr.bottom && (
+ (oldrect.left >= oldr.left && oldrect.left < oldr.right) ||
+ (oldrect.right > oldr.left && oldrect.right <= oldr.right) ||
+ (oldr.left >= oldrect.left && oldr.left < oldrect.right) ||
+ (oldr.right > oldrect.left && oldr.right <= oldrect.right)
+ );
+ else
+ isdocked=oldrect.left == oldr.right && (
+ (oldrect.top >= oldr.top && oldrect.top < oldr.bottom) ||
+ (oldrect.bottom > oldr.top && oldrect.bottom <= oldr.bottom) ||
+ (oldr.top >= oldrect.top && oldr.top < oldrect.bottom) ||
+ (oldr.bottom > oldrect.top && oldr.bottom <= oldrect.bottom)
+ );
+
+ if (isdocked)
+ {
+ if ( x == 0 )
+ {
+ if ( !whichedge )
+ config_wy = newr.bottom;
+ else
+ config_wx = newr.right;
+
+ EstMainWindowRect( &oldrect );
+ }
+ else if ( x == 1 )
+ {
+ if ( !whichedge )
+ config_eq_wy = newr.bottom;
+ else
+ config_eq_wx = newr.right;
+
+ EstEQWindowRect( &oldrect );
+ }
+ else if ( x == 2 )
+ {
+ if ( !whichedge )
+ config_pe_wy = newr.bottom;
+ else
+ config_pe_wx = newr.right;
+
+ EstPLWindowRect( &oldrect );
+ }
+ else if ( x == 4 && !is_fullscreen_video )
+ {
+ if ( !whichedge )
+ config_video_wy = newr.bottom;
+ else
+ config_video_wx = newr.right;
+
+ EstVidWindowRect( &oldrect );
+ }
+ else
+ {
+ int w = p->r.right - p->r.left;
+ int h = p->r.bottom - p->r.top;
+
+ if ( !whichedge )
+ p->r.top = newr.bottom;
+ else
+ p->r.left = newr.right;
+
+ p->r.right = p->r.left + w;
+ p->r.bottom = p->r.top + h;
+ oldrect = p->r;
+ }
+
+ if ( vis )
+ doMyDirtyShitholeDockingShit( dockwnd, oldrect, whichedge );
+ }
+ }
+
+ if (x>4) p=p->link;
+ }
+
+ if (sedge >= 0) break;
+ }
+}
+
+static void doScreenDockMoveSubWindows(HWND myWnd, RECT newr, int whichedge)
+{
+ RECT oldr = {0};
+ embedWindowState *p=embedwndlist;
+
+ GetWindowRect(myWnd,&oldr);
+ if (myWnd == hMainWindow)
+ FixMainWindowRect(&oldr);
+
+ // move any windows docked to the bottom, bottom. recursively.
+ for (int x = 0; ; x ++)
+ {
+ HWND dockwnd=NULL;
+ RECT oldrect;
+ int vis=0;
+ RECT newrect;
+ if ( x == 0 )
+ {
+ dockwnd = hMainWindow;
+ vis = config_mw_open;
+ EstMainWindowRect( &newrect );
+ }
+ else if ( x == 1 )
+ {
+ dockwnd = hEQWindow;
+ vis = config_eq_open;
+ EstEQWindowRect( &newrect );
+ }
+ else if ( x == 2 )
+ {
+ dockwnd = hPLWindow;
+ vis = config_pe_open;
+ EstPLWindowRect( &newrect );
+ }
+//else if (x == 3) { dockwnd=hMBWindow; vis=0;/*config_mb_open; */ EstMBWindowRect(&newrect); }
+ else if ( x == 4 )
+ {
+ dockwnd = hVideoWindow;
+ vis = config_video_open;
+ EstVidWindowRect( &newrect );
+ }
+ else
+ {
+ if ( !p )
+ break;
+
+ newrect = p->r;
+ dockwnd = p->me;
+ vis = IsWindowVisible( p->me );
+ }
+ GetWindowRect(dockwnd,&oldrect);
+ if (!x) FixMainWindowRect(&oldrect);
+
+ if (dockwnd != myWnd)
+ {
+ int isdocked;
+ if (!whichedge)
+ isdocked=oldrect.bottom == oldr.top && (
+ (oldrect.left >= oldr.left && oldrect.left <= oldr.right) ||
+ (oldrect.right >= oldr.left && oldrect.right <= oldr.right) ||
+ (oldr.left >= oldrect.left && oldr.left <= oldrect.right) ||
+ (oldr.right >= oldrect.left && oldr.right <= oldrect.right)
+ );
+ else
+ isdocked=oldrect.right == oldr.left && (
+ (oldrect.top >= oldr.top && oldrect.top <= oldr.bottom) ||
+ (oldrect.bottom >= oldr.top && oldrect.bottom <= oldr.bottom) ||
+ (oldr.top >= oldrect.top && oldr.top <= oldrect.bottom) ||
+ (oldr.bottom >= oldrect.top && oldr.bottom <= oldrect.bottom)
+ );
+
+ if (isdocked)
+ {
+ int h=newrect.bottom-newrect.top;
+ int w=newrect.right-newrect.left;
+ if ( x == 0 )
+ {
+ if ( !whichedge )
+ config_wy = newr.top - h;
+ else
+ config_wx = newr.left - w;
+
+ EstMainWindowRect( &oldrect );
+ }
+ else if ( x == 1 )
+ {
+ if ( !whichedge )
+ config_eq_wy = newr.top - h;
+ else
+ config_eq_wx = newr.left - w;
+
+ EstEQWindowRect( &oldrect );
+ }
+ else if ( x == 2 )
+ {
+ if ( !whichedge )
+ config_pe_wy = newr.top - h;
+ else
+ config_pe_wx = newr.left - w;
+
+ EstPLWindowRect( &oldrect );
+ }
+ else if ( x == 4 && !is_fullscreen_video )
+ {
+ if ( !whichedge )
+ config_video_wy = newr.top - h;
+ else
+ config_video_wx = newr.left - w;
+
+ EstVidWindowRect( &oldrect );
+ }
+ else
+ {
+ int w = p->r.right - p->r.left;
+ int h = p->r.bottom - p->r.top;
+
+ if ( !whichedge )
+ p->r.top = newr.top - h;
+ else
+ p->r.left = newr.left - w;
+
+ p->r.right = p->r.left + w;
+ p->r.bottom = p->r.top + h;
+ oldrect = p->r;
+ }
+
+ if (vis)
+ doScreenDockMoveSubWindows(dockwnd,oldrect,whichedge);
+ }
+ }
+
+ if (x>4) p=p->link;
+ }
+}
+
+static void doScreenDock()
+{
+ //RECT vp;
+ //SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0); //fixme: make sure we keep things in vp :)
+ for (int whichedge = 0; whichedge < 2; whichedge++)
+ {
+ embedWindowState *p=embedwndlist;
+
+ // move any windows docked to the bottom, bottom. recursively.
+ for (int x = 0; ; x ++)
+ {
+ RECT vp;
+ HWND dockwnd=NULL;
+ RECT oldrect;
+ RECT newrect;
+ int at2side=0;
+ int vis=0;
+ if ( x == 0 )
+ {
+ dockwnd = hMainWindow;
+ vis = config_mw_open;
+ EstMainWindowRect( &newrect );
+ }
+ else if ( x == 1 )
+ {
+ dockwnd = hEQWindow;
+ vis = config_eq_open;
+ EstEQWindowRect( &newrect );
+ }
+ else if ( x == 2 )
+ {
+ dockwnd = hPLWindow;
+ vis = config_pe_open;
+ EstPLWindowRect( &newrect );
+ }
+//else if (x == 3) { dockwnd=hMBWindow; vis=0; /*config_mb_open; */ EstMBWindowRect(&newrect); }
+ else if ( x == 4 )
+ {
+ dockwnd = hVideoWindow;
+ vis = config_video_open;
+ EstVidWindowRect( &newrect );
+ }
+ else
+ {
+ if ( !p )
+ break;
+
+ newrect = p->r;
+ dockwnd = p->me;
+ vis = IsWindowVisible( p->me );
+ }
+
+ GetWindowRect(dockwnd,&oldrect);
+
+ if (!x)
+ FixMainWindowRect(&oldrect);
+
+ getViewport(&vp,NULL,0,&oldrect);
+
+ if (config_keeponscreen&1)
+ {
+ if (!whichedge)
+ at2side=oldrect.bottom == vp.bottom;
+ else
+ at2side=oldrect.right == vp.right;
+ }
+
+ if (at2side)
+ {
+ if (!whichedge)
+ {
+ int diff=vp.bottom-newrect.bottom;
+ newrect.bottom += diff;
+ newrect.top += diff;
+ }
+ else
+ {
+ int diff=vp.right-newrect.right;
+ newrect.right += diff;
+ newrect.left += diff;
+ }
+
+ if ( x == 0 )
+ {
+ if ( !whichedge )
+ config_wy = newrect.top;
+ else
+ config_wx = newrect.left;
+
+ EstMainWindowRect( &oldrect );
+ }
+ else if ( x == 1 )
+ {
+ if ( !whichedge )
+ config_eq_wy = newrect.top;
+ else
+ config_eq_wx = newrect.left;
+
+ EstEQWindowRect( &oldrect );
+ }
+ else if ( x == 2 )
+ {
+ if ( !whichedge )
+ config_pe_wy = newrect.top;
+ else
+ config_pe_wx = newrect.left;
+
+ EstPLWindowRect( &oldrect );
+ }
+// else if (x == 3) { if (!whichedge) config_mb_wy = newrect.top; else config_mb_wx = newrect.left; EstMBWindowRect(&oldrect); }
+ else if ( x == 4 && !is_fullscreen_video )
+ {
+ if ( !whichedge )
+ config_video_wy = newrect.top;
+ else
+ config_video_wx = newrect.left;
+
+ EstVidWindowRect( &oldrect );
+ }
+ else
+ {
+ int w = p->r.right - p->r.left;
+ int h = p->r.bottom - p->r.top;
+
+ if ( !whichedge )
+ p->r.top = newrect.top;
+ else
+ p->r.left = newrect.left;
+
+ p->r.right = p->r.left + w;
+ p->r.bottom = p->r.top + h;
+ oldrect = p->r;
+ }
+
+ if (vis)
+ {
+ doScreenDockMoveSubWindows(dockwnd,oldrect,whichedge);
+ }
+ }
+
+ if (x>4) p=p->link;
+ }
+ }
+}
+
+void set_eq_wnd_tooltip()
+{
+ if (hEQTooltipWindow)
+ {
+ static int b=0;
+ TOOLINFOW ti = {0};
+ RECT r_main;
+ EstEQWindowRect(&r_main);
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_SUBCLASS;
+ ti.hwnd = hEQWindow;
+ ti.rect = r_main;
+
+ ti.uId = (UINT_PTR)hEQTooltipWindow;
+ ti.lpszText = (wchar_t*)LPSTR_TEXTCALLBACK;
+ if (b) SendMessageW(hEQTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hEQTooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+
+ {
+ RECT rs[18]={{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},
+ // toggle winshade / close button
+ {254,3,262,12},{264,3,272,12},
+ // toggle eq, toggle auto, presets
+ {14,18,39,30},{39,18,72,30},{217,18,261,30},
+ // windowshade volume and pan
+ {61,3,162,11},{163,3,206,11}};
+ wchar_t buf[2048] = {0};
+ getStringW(IDS_TOOLTIPS,buf,2048);
+ wchar_t *bands[11] =
+ {
+ L"",
+ L"70",L"180",L"320",L"600", // Hz
+ L"1",L"3",L"6",L"12",L"14",L"16" // KHz
+ };
+ wchar_t *bandsISO[11] =
+ {
+ L"",
+ L"31.5",L"63",L"125",L"250", // Hz
+ L"500",L"1",L"2",L"4",L"8",L"16" // KHz
+ };
+
+ for (int x=0; x < sizeof(rs)/sizeof(rs[0]); x++)
+ {
+ if(x < 11){
+ int xoffs;
+ if (!x) xoffs=21;
+ else xoffs=78+(x-1)*(96-78);
+ rs[x].left = xoffs;
+ rs[x].top = 39;
+ rs[x].right = xoffs+(33-21);
+ rs[x].bottom = 98;
+ }
+
+ ti.uId = x;
+ if(!x) ti.lpszText = getStringW(IDS_PREAMP,NULL,0);
+
+ else if(x > 15){
+ if(config_eq_ws)
+ {
+ // re-use the main tooltip text and handle the 'toggle windowshade' and 'close' buttons as applicable
+ wchar_t buf[2048], *p=buf;
+ getStringW(IDS_TOOLTIPS,buf,2048);
+ ti.lpszText=(wchar_t*)SendMessageW(hMainWindow,WM_WA_IPC,(x - 4),IPC_CB_GETTOOLTIPW);
+ if (!ti.lpszText) ti.lpszText=AutoWide((char*)SendMessageW(hMainWindow,WM_WA_IPC,(x - 4),IPC_CB_GETTOOLTIP));
+ if (!ti.lpszText){
+ for(int i = 0; i < (x - 4); i++){
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ }
+ }
+ }
+ else
+ ti.lpszText = 0;
+ }
+ else if(x > 12){
+ wchar_t buf[2048], *p=buf;
+ getStringW(IDS_EQ_TOOLTIPS,buf,2048);
+ for(int i = 0; i < x - 12; i++){
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ }
+ }
+ else if(x > 10){
+ // re-use the main tooltip text and handle the 'toggle windowshade' and 'close' buttons as applicable
+ wchar_t buf[2048], *p=buf;
+ getStringW(IDS_TOOLTIPS,buf,2048);
+ ti.lpszText=(wchar_t*)SendMessageW(hMainWindow,WM_WA_IPC,x-11,IPC_CB_GETTOOLTIPW);
+ if (!ti.lpszText) ti.lpszText=AutoWide((char*)SendMessageW(hMainWindow,WM_WA_IPC,x-11,IPC_CB_GETTOOLTIP));
+ if (!ti.lpszText){
+ for(int i = 0; i < (x == 11 ? 1 : 3); i++){
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ }
+ }
+ }
+ else{
+ wchar_t HZStr[16] = {0};
+ getStringW((x<5+!(config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?IDS_EQ_HZ:IDS_EQ_KHZ),HZStr,16);
+ StringCchPrintfW(buf,80,L"%s%s",
+ ((config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?bands[x]:bandsISO[x]),
+ (!x?L"":HZStr));
+ ti.lpszText = buf;
+ }
+
+ ti.rect = rs[x];
+ if (config_dsize)
+ {
+ ti.rect.left *= 2;
+ ti.rect.right *= 2;
+ ti.rect.top *= 2;
+ ti.rect.bottom *= 2;
+ }
+ SendMessageW(hEQTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hEQTooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+ }
+ }
+
+ b=config_ttips;
+ }
+}
+
+void set_vid_wnd_tooltip()
+{
+ if (hVideoTooltipWindow)
+ {
+ static int d=0;
+ TOOLINFOW ti = {0};
+ RECT r_main;
+ EstVidWindowRect(&r_main);
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_SUBCLASS;
+ ti.hwnd = hVideoWindow;
+ ti.rect = r_main;
+
+ ti.uId = (UINT_PTR)hVideoTooltipWindow;
+ ti.lpszText = (wchar_t*)LPSTR_TEXTCALLBACK;
+ if (d) SendMessageW(hVideoTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hVideoTooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+
+ {
+ RECT rs[]={{0,3,0,12},{9,0,24,0},{25,0,40,0},{41,0,56,0},{57,0,72,0},{73,0,89,0}};
+
+ rs[0].left = config_video_width-11;
+ rs[0].right = config_video_width-2;
+
+ rs[1].top = rs[2].top = rs[3].top = rs[4].top = rs[5].top = config_video_height-29;
+ rs[1].bottom = rs[2].bottom = rs[3].bottom = rs[4].bottom = rs[5].bottom = config_video_height-11;
+
+ wchar_t buf[2048], *p=buf;
+ getStringW(IDS_VID_TOOLTIPS,buf,2048);
+ for (int x=0; x < sizeof(rs)/sizeof(rs[0]); x++)
+ {
+ if(!x)
+ {
+ // re-use the main tooltip text and handle the 'toggle windowshade' and 'close' buttons as applicable
+ wchar_t buf2[2048], *p2=buf2;
+ getStringW(IDS_TOOLTIPS,buf2,2048);
+ for(int i = 0; i < 3; i++){
+ ti.lpszText=p2;
+ while (p2 && *p2 && *p2 != L'|') p2++;
+ if (p2) *p2++=0;
+ }
+ }
+ else
+ {
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ }
+ ti.uId = x;
+
+ ti.rect = rs[x];
+ if (d) SendMessageW(hVideoTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hVideoTooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+ }
+ }
+
+ d=config_ttips;
+ }
+}
+
+void set_pl_wnd_tooltip()
+{
+ if (hPLTooltipWindow)
+ {
+ static int c=0;
+ TOOLINFOW ti = {0};
+ RECT r_main;
+ EstPLWindowRect(&r_main);
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_SUBCLASS;
+ ti.hwnd = hPLWindow;
+ ti.rect = r_main;
+
+ ti.uId = (UINT_PTR)hPLTooltipWindow;
+ ti.lpszText = (wchar_t*)LPSTR_TEXTCALLBACK;
+ if (c) SendMessageW(hPLWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hPLWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+
+ {
+ // toggle winshade / close button
+ RECT rs[]={{0,3,0,12},{0,3,0,12},
+ // add, rem, sel, misc, list buttons
+ {14,0,36,0},{43,0,65,0},{72,0,94,0},{101,0,123,0},{0},
+ // windowshade mappings - order is out of kilt so it maps more easily to the string
+ // (open, previuos, play, pause, stop, next, time)
+ {0},{0},{0},{0},{0},{0},{0},
+ // up/down scroll buttons
+ {0},{0},
+ // resize horizontally (winshade)
+ /*{0},
+ // playlist item truncated text*/
+ {0}};
+
+ rs[0].left = config_pe_width - 11;
+ rs[0].right = config_pe_width - 2;
+
+ rs[1].left = config_pe_width - 21;
+ rs[1].right = config_pe_width - 12;
+
+ rs[2].top = rs[3].top = rs[4].top = rs[5].top = rs[6].top = (config_pe_height - 30);
+ rs[2].bottom = rs[3].bottom = rs[4].bottom = rs[5].bottom = rs[6].bottom = (config_pe_height - 12);
+
+ rs[6].left = config_pe_width - 44;
+ rs[6].right = config_pe_width - 22;
+
+ rs[7].top = rs[8].top = rs[9].top = rs[10].top = rs[11].top = rs[12].top = rs[13].top = (config_pe_height - 16);
+ rs[7].bottom = rs[8].bottom = rs[9].bottom = rs[10].bottom = rs[11].bottom = rs[12].bottom = rs[13].bottom = (config_pe_height - 8);
+
+ rs[7].left = config_pe_width - 98;
+ rs[7].right = config_pe_width - 90;
+
+ rs[8].left = config_pe_width - 144;
+ rs[8].right = config_pe_width - 137;
+ rs[9].left = config_pe_width - 136;
+ rs[9].right = config_pe_width - 127;
+ rs[10].left = config_pe_width - 126;
+ rs[10].right = config_pe_width - 117;
+ rs[11].left = config_pe_width - 116;
+ rs[11].right = config_pe_width - 109;
+ rs[12].left = config_pe_width - 108;
+ rs[12].right = config_pe_width - 100;
+ rs[13].left = config_pe_width - 87;
+ rs[13].right = config_pe_width - 54;
+
+ wchar_t buf[2048], *p=buf;
+ getStringW(IDS_PL_TOOLTIPS,buf,2048);
+ for (int x=0; x < sizeof(rs)/sizeof(rs[0]); x++)
+ {
+ if(x < 2)
+ {
+ // re-use the main tooltip text and handle the 'toggle windowshade' and 'close' buttons as applicable
+ wchar_t buf2[2048], *p2=buf2;
+ getStringW(IDS_TOOLTIPS,buf2,2048);
+ for(int i = 0; i < (x == 1 ? 1 : 3); i++){
+ ti.lpszText=p2;
+ while (p2 && *p2 && *p2 != L'|') p2++;
+ if (p2) *p2++=0;
+ }
+ }
+ else if(x == 16){
+ if(config_pe_height == 14)
+ {
+ rs[x].left = config_pe_width - 29;
+ rs[x].right = config_pe_width - 22;
+ rs[x].top = 3;
+ rs[x].bottom = 13;
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ }
+ else
+ ti.lpszText = 0;
+ }
+ else if(x >= 14)
+ {
+ rs[x].left = config_pe_width - 16;
+ rs[x].right = config_pe_width - 6;
+ rs[x].top = config_pe_height - (x == 14 ? 37 : 31);
+ rs[x].bottom = config_pe_height - (x == 14 ? 32 : 25);
+
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ *p++=0;
+ }
+ else if(x > 6)
+ {
+ if (config_pe_height != 14)
+ {
+ wchar_t buf2[2048], *p2=buf2;
+ getStringW(IDS_TOOLTIPS,buf2,2048);
+ for(int i = 0; i < 17 + (x - 6); i++){
+ ti.lpszText=p2;
+ while (p2 && *p2 && *p2 != L'|') p2++;
+ *p2++=0;
+ }
+ }
+ else
+ ti.lpszText = 0;
+ }
+ else
+ {
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ if (config_pe_height == 14 && x > 1)
+ ti.lpszText = 0;
+ }
+ ti.uId = x;
+
+ ti.rect = rs[x];
+ if (c) SendMessageW(hPLTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hPLTooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+ }
+ }
+
+ c=config_ttips;
+ }
+}
+
+void set_main_wnd_tooltip()
+{
+ if (hTooltipWindow)
+ {
+ static int a=0;
+ TOOLINFOW ti = {0};
+ RECT r_main;
+ EstMainWindowRect(&r_main);
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_SUBCLASS;
+ ti.hwnd = hMainWindow;
+ ti.rect = r_main;
+
+ ti.uId = (UINT_PTR)hTooltipWindow;
+ ti.lpszText = (wchar_t*)LPSTR_TEXTCALLBACK;
+ if (a) SendMessageW(hTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hTooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+
+ {
+ RECT rs[]={{254,3,262,12},{244,3,253,12},{264,3,272,12},{5,3,17,13},
+ {219,58,219+23,58+12},{219+23,58,219+23+23,58+12},
+ {11,24,19,31},{11,32,19,39},{11,40,19,47},{11,48,19,55},{11,56,19,62},
+ {107,43+15,107+68,51+15},{177,43+15,177+38,51+15},{11+7,58+15,256+7,66+15},{133+7-4+29,75+15,181+7-4-4+29,87+15},{182+7-4-4+29,75+15,182+29+7-4-4+29,87+15},
+ {246+7,76+15,258+7,90+15},{132+7-4+1,60+14+15,132+7-4+22+1,60+14+15+16},
+ {7+8,15+72,7+31,15+91},{7+32,15+72,7+53,15+91},{7+54,15+72,7+77,15+91},{7+78,15+72,7+100,15+91},{7+101,15+72,7+123,15+91},
+ {36,26,96,39},{105,24,266,35},
+ // windowshade mappings - order is out of kilt so it maps more easily to the string
+ // (seeker, open, previuos, play, pause, stop, next, time)
+ {226,4,243,11},{216,2,224,11},{168,2,176,11},{177,2,186,11},{187,2,195,11},{196,2,204,11},{205,2,215,11},{125,4,157,10}};
+
+ wchar_t buf[2048], *p=buf;
+ getStringW(IDS_TOOLTIPS,buf,2048);
+ for (int x=0; x < sizeof(rs)/sizeof(rs[0]); x++)
+ {
+ ti.uId = x;
+ ti.lpszText=(wchar_t*)SendMessageW(hMainWindow,WM_WA_IPC,x,IPC_CB_GETTOOLTIPW);
+ if (!ti.lpszText) ti.lpszText=AutoWide((char*)SendMessageW(hMainWindow,WM_WA_IPC,x,IPC_CB_GETTOOLTIP));
+ if (!ti.lpszText) ti.lpszText=p;
+
+ int ws_parts = sizeof(rs)/sizeof(rs[0]) - 8;
+ if(x < ws_parts)
+ {
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ }
+ else
+ {
+ if(config_windowshade)
+ {
+ getStringW(IDS_TOOLTIPS,buf,2048);
+ p=buf;
+ for(int i = 0; i < (x - ws_parts == 0 ? 14 : x - 8); i++){
+ ti.lpszText=p;
+ while (p && *p && *p != L'|') p++;
+ if (p) *p++=0;
+ }
+ }
+ else
+ ti.lpszText = 0;
+ }
+ ti.rect = rs[x];
+ if (config_dsize)
+ {
+ ti.rect.left *= 2;
+ ti.rect.right *= 2;
+ ti.rect.top *= 2;
+ ti.rect.bottom *= 2;
+ }
+ if (a) SendMessageW(hTooltipWindow,TTM_DELTOOLW,0,(LPARAM) &ti);
+ if (config_ttips) SendMessageW(hTooltipWindow,TTM_ADDTOOLW,0,(LPARAM) &ti);
+ }
+ }
+
+ a=config_ttips;
+ }
+}
+
+void set_aot(int dodockingstuff)
+{
+ // do size handling stuff here
+ if (dodockingstuff>0)
+ {
+ //new mode is inspired by christophe's sexiness
+ RECT newr;
+ EnterCriticalSection(&embedcs);
+ EstMainWindowRect(&newr);
+ doMyDirtyShitholeDockingShit(hMainWindow,newr,-1);
+ EstEQWindowRect(&newr);
+ doMyDirtyShitholeDockingShit(hEQWindow,newr,-1);
+ EstPLWindowRect(&newr);
+ doMyDirtyShitholeDockingShit(hPLWindow,newr,-1);
+
+ // check to see if any windows used to be docked to the right/bottom, and
+ // if they did, move them to the bottom and any attached windows
+
+ // this actually works OK!
+ if ((config_keeponscreen&1) && !g_fsapp) doScreenDock();
+
+ LeaveCriticalSection(&embedcs);
+ }
+
+ set_eq_wnd_tooltip();
+ set_vid_wnd_tooltip();
+ set_pl_wnd_tooltip();
+ set_main_wnd_tooltip();
+
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_AOT,config_aot?MF_CHECKED:MF_UNCHECKED);
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_DSIZE,config_dsize?MF_CHECKED:MF_UNCHECKED);
+
+ if ((config_keeponscreen&1) && !g_fsapp)
+ {
+ RECT r;
+ if (config_mw_open)
+ {
+ RECT thisr;
+ EstMainWindowRect( &thisr );
+ getViewport( &r, NULL, 0, &thisr );
+
+ if ( config_wx + ( thisr.right - thisr.left - 10 ) < r.left )
+ config_wx = r.left - ( thisr.right - thisr.left - 10 );
+
+ if ( config_wy + ( thisr.bottom - thisr.top - 10 ) < r.top )
+ config_wy = r.top - ( thisr.bottom - thisr.top - 10 );
+
+ if (config_wx > r.right - 10)
+ config_wx = r.left + 10; //config_wx = r.right - 10;
+
+ if (config_wy > r.bottom - 10)
+ config_wy = r.top + 10; //config_wy = r.bottom - 10;
+ }
+
+ if (config_eq_open)
+ {
+ RECT thisr;
+ EstEQWindowRect( &thisr );
+ getViewport( &r, NULL, 0, &thisr );
+
+ if ( config_eq_wx + ( thisr.right - thisr.left - 10 ) < r.left )
+ config_eq_wx = r.left - ( thisr.right - thisr.left - 10 );
+
+ if ( config_eq_wy + ( thisr.bottom - thisr.top - 10 ) < r.top )
+ config_eq_wy = r.top - ( thisr.bottom - thisr.top - 10 );
+
+ if (config_eq_wx > r.right - 10)
+ config_eq_wx = r.left + 10; //r.right - 10;
+
+ if (config_eq_wy > r.bottom - 10)
+ config_eq_wy = r.top + 10; //r.bottom - 10;
+ }
+
+ if (config_pe_open)
+ {
+ RECT thisr;
+ EstPLWindowRect( &thisr );
+ getViewport( &r, NULL, 0, &thisr );
+
+ if ( config_pe_wx + ( thisr.right - thisr.left - 10 ) < r.left )
+ config_pe_wx = r.left - ( thisr.right - thisr.left - 10 );
+
+ if ( config_pe_wy + ( thisr.bottom - thisr.top - 10 ) < r.top )
+ config_pe_wy = r.top - ( thisr.bottom - thisr.top - 10 );
+
+ if (config_pe_wx > r.right - 10)
+ config_pe_wx = r.left + 10; //r.right - 10;
+
+ if (config_pe_wy > r.bottom - 10)
+ config_pe_wy = r.top + 10; //r.bottom - 10;
+ }
+
+ if (config_video_open && !is_fullscreen_video)
+ {
+ RECT thisr;
+ EstVidWindowRect( &thisr );
+ getViewport( &r, NULL, 0, &thisr );
+
+ if ( config_video_wx + ( thisr.right - thisr.left - 10 ) < r.left )
+ config_video_wx = r.left - ( thisr.right - thisr.left - 10 );
+
+ if ( config_video_wy + ( thisr.bottom - thisr.top - 10 ) < r.top )
+ config_video_wy = r.top - ( thisr.bottom - thisr.top - 10 );
+
+ if (config_video_wx > r.right - 10)
+ config_video_wx = r.left + 10; //r.right - 10;
+
+ if (config_video_wy > r.bottom - 10)
+ config_video_wy = r.top + 10; // r.bottom - 10;
+ }
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *p=embedwndlist;
+ while (p)
+ {
+ if (IsWindowVisible(p->me))
+ {
+ RECT thisr = p->r;
+ getViewport( &r, NULL, 0, &thisr );
+ if ( thisr.right < r.left - 10 )
+ p->r.left = r.left - ( thisr.right - thisr.left - 10 );
+
+ if ( thisr.bottom < r.top - 10 )
+ p->r.top = r.top - ( thisr.bottom - thisr.top - 10 );
+
+ if (thisr.left > r.right - 10)
+ p->r.left = r.left + 10; // r.right - 10;
+
+ if (thisr.top > r.bottom - 10)
+ p->r.top = r.top + 10; // r.bottom - 10;
+
+ p->r.right = p->r.left + (thisr.right - thisr.left);
+ p->r.bottom = p->r.top + (thisr.bottom - thisr.top);
+ }
+ p=p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+ }
+
+ {
+ HDWP hwdp=BeginDeferWindowPos(10);
+ RECT r;
+ int do_pl_inv=0;
+ extern int g_fsapp;
+
+ EstMainWindowRect(&r);
+ if (config_aot)
+ {
+ if (g_fsapp)
+ {
+ if (config_dropaotfs)
+ {
+ hwdp=DeferWindowPos(hwdp,hMainWindow, HWND_NOTOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE|(config_mw_open?0:SWP_NOMOVE|SWP_NOSIZE));
+ }
+ else
+ {
+ hwdp=DeferWindowPos(hwdp,hMainWindow, HWND_TOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE|(config_mw_open?0:SWP_NOMOVE|SWP_NOSIZE));
+ }
+ }
+ else
+ {
+ hwdp=DeferWindowPos(hwdp,hMainWindow, HWND_TOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE|(config_mw_open?0:SWP_NOMOVE|SWP_NOSIZE));
+ }
+ }
+ else
+ {
+ hwdp=DeferWindowPos(hwdp,hMainWindow, HWND_NOTOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE|(config_mw_open?0:SWP_NOMOVE|SWP_NOSIZE));
+ }
+
+ if (hEQWindow && !GetParent(hEQWindow)) // we check to see if the windows have no parent, for the gen_ff
+ {
+ EstEQWindowRect(&r);
+ hwdp=DeferWindowPos(hwdp,hEQWindow, 0, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE|SWP_NOZORDER);
+ }
+
+ if (hPLWindow && !GetParent(hPLWindow))
+ {
+ EstPLWindowRect(&r);
+ hwdp=DeferWindowPos(hwdp,hPLWindow, 0, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE|SWP_NOZORDER);
+ do_pl_inv=1;
+ }
+
+/* if (hMBWindow && !GetParent(hMBWindow))
+ {
+ EstMBWindowRect(&r);
+ hwdp=DeferWindowPos(hwdp,hMBWindow, 0, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_DRAWFRAME|SWP_NOACTIVATE|SWP_NOZORDER);
+ }*/
+
+ if (hVideoWindow && !GetParent(hVideoWindow) && !is_fullscreen_video)
+ {
+ EstVidWindowRect(&r);
+ hwdp=DeferWindowPos(hwdp,hVideoWindow, 0, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_NOZORDER);
+ }
+
+ // traverse the embed windows
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *p=embedwndlist;
+ while (p)
+ {
+ if (!HasParent(p->me))
+ hwdp=DeferWindowPos(hwdp,p->me, 0, p->r.left, p->r.top, p->r.right-p->r.left, p->r.bottom-p->r.top, SWP_DRAWFRAME|SWP_NOACTIVATE|SWP_NOZORDER);
+
+ p=p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+
+ EndDeferWindowPos(hwdp);
+
+ if(do_pl_inv)
+ InvalidateRect(hPLWindow,NULL,FALSE); // fix pl bug?
+ }
+
+ // region
+ if (!config_minimized && config_mw_open)
+ {
+ HRGN lasthrgn=NULL;
+ int *plist=0, *nlist=0, len=0;
+
+ if (skin_directory[0])
+ len = Skin_GetRegionPointList(0,&plist,&nlist);
+ else
+ len=0;
+
+ if (len)
+ {
+ POINT *points;
+ int x;
+ int a=config_dsize?1:0;
+ int ma=0;
+ for (x=0; x < len; x ++)
+ ma+=nlist[x];
+ points= (POINT *) GlobalAlloc(GPTR,sizeof(POINT) * ma);
+ for (x = 0; x < ma; x ++)
+ {
+ points[x].x = *plist++<<a;
+ points[x].y = *plist++<<a;
+ }
+ lasthrgn = CreatePolyPolygonRgn(points,nlist,len,WINDING);
+ GlobalFree(points);
+ }
+ else
+ {
+ RECT r;
+ EstMainWindowRect(&r);
+ lasthrgn=CreateRectRgn(0,0,r.right-r.left,r.bottom-r.top);
+ }
+ if (lasthrgn) SetWindowRgn(hMainWindow,lasthrgn,TRUE);
+ else SetWindowRgn(hMainWindow,NULL,FALSE);
+ }
+
+ // region
+ if (!config_minimized && config_eq_open && hEQWindow)
+ {
+ int *plist, *nlist, len = Skin_GetRegionPointList(1,&plist,&nlist);
+ if (len)
+ {
+ POINT *points;
+ int x;
+ int a=config_dsize?1:0;
+ int ma=0;
+ for (x=0; x < len; x ++)
+ ma+=nlist[x];
+ points= (POINT *) GlobalAlloc(GPTR,sizeof(POINT) * ma);
+ for (x = 0; x < ma; x ++)
+ {
+ points[x].x = *plist++<<a;
+ points[x].y = *plist++<<a;
+ }
+ HRGN lasthrgn = CreatePolyPolygonRgn(points,nlist,len,WINDING);
+ GlobalFree(points);
+ SetWindowRgn(hEQWindow,lasthrgn,TRUE);
+ }
+ else SetWindowRgn(hEQWindow,NULL,FALSE);
+ }
+
+ // region
+ /*if (!config_minimized && config_pe_open && hPLWindow)
+ {
+ int *plist, *nlist, len = Skin_GetRegionPointList(2,&plist,&nlist);
+ if (len)
+ {
+ POINT *points;
+ int x;
+ int a=config_dsize?1:0;
+ int ma=0;
+ for (x=0; x < len; x ++)
+ ma+=nlist[x];
+ points= (POINT *) GlobalAlloc(GPTR,sizeof(POINT) * ma);
+ for (x = 0; x < ma; x ++)
+ {
+ points[x].x = *plist++<<a;
+ points[x].y = *plist++<<a;
+ }
+ HRGN lasthrgn = CreatePolyPolygonRgn(points,nlist,len,WINDING);
+ if (config_pe_height != 14)
+ {
+ HRGN allhrng = CreateRectRgn(0, 0, config_pe_width, config_pe_height);
+ CombineRgn(lasthrgn, lasthrgn, allhrng, RGN_XOR);
+ DeleteRgn(allhrng);
+ }
+ GlobalFree(points);
+ SetWindowRgn(hPLWindow,lasthrgn,TRUE);
+ }
+ else SetWindowRgn(hPLWindow,NULL,FALSE);
+ }*/
+
+ // refresh windows
+ if (config_mw_open) InvalidateRect(hMainWindow,NULL,FALSE);
+ if (hEQWindow) InvalidateRect(hEQWindow,NULL,FALSE);
+
+ if (hVisWindow)
+ {
+ int x,y,w,h;
+ if (config_windowshade)
+ {
+ x=79;
+ y=5;
+ w=38;
+ h=5;
+ }
+ else
+ {
+ x=24;
+ y=43;
+ w=76;
+ h=16;
+ }
+ if (config_dsize)
+ {
+ x*=2;
+ y*=2;
+ w*=2;
+ h*=2;
+ }
+ SetWindowPos(hVisWindow,0,x,y,w,h,SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+
+ if (hPLVisWindow)
+ {
+ int x,y,w,h;
+ x=config_pe_width-150-75+2;
+ y=config_pe_height-26;
+ w=(config_pe_width >= 350 && config_pe_height != 14 ? 72 : 0);
+ h=16;
+ SetWindowPos(hPLVisWindow,0,x,y,w,h,SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+
+ draw_clutterbar(0);
+ SendMessageW(hMainWindow, WM_WA_IPC, config_aot, IPC_CB_ONTOGGLEAOT);
+}
+
+void set_visopts(void)
+{
+ if (prefs_last_page == 22 && IsWindow(prefs_hwnd))
+ {
+ prefs_last_page=0;
+ prefs_dialog(1);
+ prefs_last_page=22;
+ prefs_dialog(1);
+ }
+}
+
+void set_priority(void)
+{
+ int tab[5]={IDLE_PRIORITY_CLASS,NORMAL_PRIORITY_CLASS,ABOVE_NORMAL_PRIORITY_CLASS,HIGH_PRIORITY_CLASS,REALTIME_PRIORITY_CLASS};
+ if (config_priority > 4) config_priority=1;
+ SetPriorityClass(GetCurrentProcess(),tab[config_priority]);
+} \ No newline at end of file
diff --git a/Src/Winamp/Singleton.h b/Src/Winamp/Singleton.h
new file mode 100644
index 00000000..ff7cd560
--- /dev/null
+++ b/Src/Winamp/Singleton.h
@@ -0,0 +1,138 @@
+#ifndef __WASABI_SINGLETON_H
+#define __WASABI_SINGLETON_H
+
+#include "api/service/waservicefactoryi.h"
+#include "api/service/services.h"
+
+template <class api_t, class impl_t>
+class Singleton : public waServiceFactoryI
+{
+public:
+ Singleton() : impl( 0 ), orig( 0 ) {}
+
+ Singleton( impl_t *new_impl, bool existing ) : impl( 0 ), orig( 0 )
+ {
+ if ( existing )
+ Register( new_impl );
+ else
+ RegisterNew( new_impl );
+ }
+
+ Singleton( impl_t *&new_impl ) : impl( 0 ), orig( 0 ) { RegisterNew( new_impl ); }
+
+ ~Singleton() { Deregister(); }
+
+ void Register( impl_t *new_impl )
+ {
+ impl = new_impl;
+ WASABI_API_SVC->service_register( this );
+ }
+
+ void RegisterNew( impl_t *&new_impl )
+ {
+ if ( !new_impl )
+ {
+ orig = &new_impl;
+ new_impl = new impl_t;
+ }
+
+ impl = new_impl;
+ WASABI_API_SVC->service_register( this );
+ }
+
+ void Deregister()
+ {
+ if ( impl )
+ {
+ WASABI_API_SVC->service_deregister( this );
+ if ( orig )
+ {
+ delete impl;
+ *orig = 0;
+ }
+
+ impl = 0;
+ }
+ }
+
+ impl_t *impl;
+ impl_t **orig;
+
+ FOURCC svc_serviceType() { return WaSvc::UNIQUE; } // TODO: make this a (defaulted) template parameter
+ const char *svc_getServiceName() { return impl_t::getServiceName(); }
+ GUID svc_getGuid() { return impl_t::getServiceGuid(); } // GUID per service factory, can be INVALID_GUID
+ void *svc_getInterface( int global_lock = TRUE ) { return static_cast<api_t *>( impl ); }
+ int svc_supportNonLockingGetInterface() { return TRUE; }
+ int svc_releaseInterface( void *ifc ) { return 0; }
+ CfgItem *svc_getCfgInterface() { return NULL; }
+ const wchar_t *svc_getTestString() { return 0; }
+ int svc_notify( int msg, int param1 = 0, int param2 = 0 ) { return 0; }
+};
+
+
+template <class api_t, class impl_t>
+class Singleton2 : public waServiceFactoryI
+{
+public:
+ Singleton2() : impl( 0 ), orig( 0 ) {}
+
+ Singleton2( impl_t *new_impl, bool existing ) : impl( 0 ), orig( 0 )
+ {
+ if ( existing )
+ Register( new_impl );
+ else
+ RegisterNew( new_impl );
+ }
+
+ Singleton2( impl_t *&new_impl ) : impl( 0 ), orig( 0 ) { RegisterNew( new_impl ); }
+
+ ~Singleton2() { Deregister(); }
+
+ void Register( impl_t *new_impl )
+ {
+ impl = new_impl;
+ WASABI_API_SVC->service_register( this );
+ }
+
+ void RegisterNew( impl_t *&new_impl )
+ {
+ if ( !new_impl )
+ {
+ orig = &new_impl;
+ new_impl = new impl_t;
+ }
+
+ impl = new_impl;
+ WASABI_API_SVC->service_register( this );
+ }
+
+ void Deregister()
+ {
+ if ( impl )
+ {
+ WASABI_API_SVC->service_deregister( this );
+ if ( orig )
+ {
+ delete impl;
+ *orig = 0;
+ }
+
+ impl = 0;
+ }
+ }
+
+ impl_t *impl;
+ impl_t **orig;
+
+ FOURCC svc_serviceType() { return WaSvc::UNIQUE; } // TODO: make this a (defaulted) template parameter
+ const char *svc_getServiceName() { return impl_t::getServiceName(); }
+ GUID svc_getGuid() { return impl_t::getServiceGuid(); } // GUID per service factory, can be INVALID_GUID
+ void *svc_getInterface( int global_lock = TRUE ) { return static_cast<api_t *>( impl ); }
+ int svc_supportNonLockingGetInterface() { return TRUE; }
+ int svc_releaseInterface( void *ifc ) { return 0; }
+ CfgItem *svc_getCfgInterface() { return NULL; }
+ const wchar_t *svc_getTestString() { return 0; }
+ int svc_notify( int msg, int param1 = 0, int param2 = 0 ) { return 0; }
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/SkinBitmapElement.cpp b/Src/Winamp/SkinBitmapElement.cpp
new file mode 100644
index 00000000..51226954
--- /dev/null
+++ b/Src/Winamp/SkinBitmapElement.cpp
@@ -0,0 +1,28 @@
+#include "api.h"
+#include "SkinBitmapElement.h"
+#include "PaletteManager.h"
+
+SkinBitmapElement::SkinBitmapElement(const wchar_t *_id, const wchar_t *_filename, const wchar_t *_rootpath, int _x, int _y, int _w, int _h, ifc_xmlreaderparams *pars, int script_id, int secondarycounter, const wchar_t *colorgrp)
+ : filename(_filename), rootpath(_rootpath), x(_x), y(_y), w(_w), h(_h),
+ scriptid(script_id), seccount(secondarycounter), colorgroup(colorgrp),
+ region(NULL)
+{
+ id = _id;
+
+ if (pars)
+ {
+ for (size_t i = 0;i != pars->getNbItems();i++)
+ params.addItem(pars->getItemName(i), pars->getItemValue(i));
+ }
+}
+
+SkinBitmapElement::~SkinBitmapElement()
+{
+ if (region != NULL) WASABI_API_PALETTE->garbageCollectRegionServer(region);
+ region = NULL;
+}
+
+SkinItem *SkinBitmapElement::getAncestor()
+{
+ return WASABI_API_PALETTE->getBitmapAncestor(this);
+}
diff --git a/Src/Winamp/SkinBitmapElement.h b/Src/Winamp/SkinBitmapElement.h
new file mode 100644
index 00000000..241b093e
--- /dev/null
+++ b/Src/Winamp/SkinBitmapElement.h
@@ -0,0 +1,85 @@
+#pragma once
+#include <api/skin/skinitem.h>
+#include "ParamList.h"
+#include <tataki/region/region.h>
+class ElementRegionServer : public RegionServerI
+{
+public:
+ ElementRegionServer(api_region *r)
+ : reg(r->getOSHandle())
+ {}
+
+ virtual api_region *getRegion()
+ {
+ return &reg;
+ }
+
+private:
+ RegionI reg;
+};
+
+
+struct SkinBitmapElement : public SkinItemI
+{
+public:
+
+ SkinBitmapElement(const wchar_t *_id, const wchar_t *_filename, const wchar_t *_rootpath,
+ int _x, int _y, int _w, int _h,
+ ifc_xmlreaderparams *pars = NULL, int script_id = -1, int secondarycounter = 0, const wchar_t *colorgrp = NULL);
+ virtual ~SkinBitmapElement();
+
+ const wchar_t *getId() { return id; }
+ const wchar_t *getFilename() { return filename; }
+ int getX() { return x; }
+ int getY() { return y; }
+ int getW() { return w; }
+ int getH() { return h; }
+ int getSecCount() { return seccount; }
+ const wchar_t *getColorGroup() { return colorgroup; }
+ ElementRegionServer *getRegionServer() { return region; }
+ void setRegionServer(ElementRegionServer *s) { region = s; }
+
+ virtual const wchar_t *getXmlRootPath() { return rootpath; }
+ virtual const wchar_t *getName() { return L"bitmap"; }
+ virtual ifc_xmlreaderparams *getParams() { return &params; }
+ virtual int getSkinPartId() { return scriptid; }
+ virtual SkinItem *getAncestor();
+
+private:
+
+ StringW id;
+ StringW filename;
+ StringW rootpath;
+ int x;
+ int y;
+ int w;
+ int h;
+ int scriptid;
+ int seccount;
+ ParamList params;
+ StringW colorgroup;
+ ElementRegionServer *region;
+};
+
+
+class SortSkinBitmapElement
+{
+public:
+ static int compareItem(SkinBitmapElement *p1, SkinBitmapElement *p2)
+ {
+ int r = WCSICMP(p1->getId(), p2->getId());
+ if (!r)
+ {
+ if (p1->getSkinPartId() < p2->getSkinPartId()) return -1;
+ if (p1->getSkinPartId() > p2->getSkinPartId()) return 1;
+ if (p1->getSecCount() < p2->getSecCount()) return -1;
+ if (p1->getSecCount() > p2->getSecCount()) return 1;
+ return 0;
+ }
+ return r;
+ }
+ static int compareAttrib(const wchar_t *attrib, SkinBitmapElement *item)
+ {
+ return WCSICMP(attrib, item->getId());
+ }
+};
diff --git a/Src/Winamp/SkinCOM.cpp b/Src/Winamp/SkinCOM.cpp
new file mode 100644
index 00000000..705baaa6
--- /dev/null
+++ b/Src/Winamp/SkinCOM.cpp
@@ -0,0 +1,323 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author: Ben Allison benski@nullsoft.com
+** Created:
+**/
+#include "main.h"
+#include "../nu/ns_wc.h"
+#include "SkinCOM.h"
+#include "resource.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "wa_dlg.h"
+#include "Browser.h"
+
+void WriteEscaped(FILE *fp, const char *str);
+
+void WriteSkinsAsXML(const wchar_t *filename, int limit)
+{
+ FILE *fp = _wfopen(filename, L"wb");
+ fputs("<?xml version=\"1.0\" encoding=\"utf-8\"?>", fp);
+ fputs("<skins>\n", fp);
+ fputs("<skin filename=\"", fp);
+ WriteEscaped(fp,"Winamp Classic");
+ fputs("\"/>\n", fp);
+
+ HANDLE h;
+ WIN32_FIND_DATAW d;
+
+ wchar_t dirmask[MAX_PATH] = {0};
+ PathCombineW(dirmask, SKINDIR, L"*");
+
+ h = FindFirstFileW(dirmask, &d);
+ if (h != INVALID_HANDLE_VALUE )
+ {
+ int count=1;
+ do
+ {
+ if ( limit && count >= limit ) break;
+ if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if (wcscmp(d.cFileName, L".") && wcscmp(d.cFileName, L".."))
+ {
+ fputs("<skin filename=\"", fp);
+ WriteEscaped(fp, AutoChar(d.cFileName, CP_UTF8));
+ fputs("\"/>\n", fp);
+ count++;
+ }
+ }
+ else if (!_wcsicmp(extensionW(d.cFileName), L"zip") || !_wcsicmp(extensionW(d.cFileName), L"wsz") || !_wcsicmp(extensionW(d.cFileName), L"wal"))
+ {
+ fputs("<skin filename=\"", fp);
+ WriteEscaped(fp, AutoChar(d.cFileName, CP_UTF8));
+ fputs("\"/>\n", fp);
+ count++;
+ }
+
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+
+ }
+ fputs("</skins>", fp);
+ fclose(fp);
+}
+
+
+enum
+{
+ DISP_CURRENTSKIN_GETCOLOR = 777,
+ DISP_CURRENTSKIN_GETNAME,
+ DISP_CURRENTSKIN_REGISTERSKINCHANGECALLBACK,
+ DISP_CURRENTSKIN_UNREGISTERSKINCHANGECALLBACK,
+ DISP_CURRENTSKIN_GETFONTNAME,
+ DISP_CURRENTSKIN_GETFONTSIZE,
+ DISP_CURRENTSKIN_GETPLAYLISTCOLOR,
+ DISP_CURRENTSKIN_SETSKIN,
+ DISP_CURRENTSKIN_GETXMLSKINLIST,
+};
+
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT SkinCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ UNREFERENCED_PARAMETER(riid);
+
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("GetColor", DISP_CURRENTSKIN_GETCOLOR)
+ CHECK_ID("GetName", DISP_CURRENTSKIN_GETNAME)
+ CHECK_ID("RegisterSkinChangeCallback", DISP_CURRENTSKIN_REGISTERSKINCHANGECALLBACK)
+ CHECK_ID("UnregisterSkinChangeCallback", DISP_CURRENTSKIN_UNREGISTERSKINCHANGECALLBACK)
+ CHECK_ID("GetFontName", DISP_CURRENTSKIN_GETFONTNAME)
+ CHECK_ID("GetFontSize", DISP_CURRENTSKIN_GETFONTSIZE);
+ CHECK_ID("GetPlaylistColor", DISP_CURRENTSKIN_GETPLAYLISTCOLOR);
+ CHECK_ID("SetSkin", DISP_CURRENTSKIN_SETSKIN);
+ CHECK_ID("GetXMLSkinList", DISP_CURRENTSKIN_GETXMLSKINLIST);
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT SkinCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ UNREFERENCED_PARAMETER(itinfo);
+ UNREFERENCED_PARAMETER(lcid);
+ UNREFERENCED_PARAMETER(pptinfo);
+
+ return E_NOTIMPL;
+}
+
+HRESULT SkinCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ UNREFERENCED_PARAMETER(pctinfo);
+
+ return E_NOTIMPL;
+}
+
+
+HRESULT SkinCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ UNREFERENCED_PARAMETER(riid);
+ UNREFERENCED_PARAMETER(lcid);
+ UNREFERENCED_PARAMETER(pexecinfo);
+ UNREFERENCED_PARAMETER(wFlags);
+
+ switch (dispid)
+ {
+ case DISP_CURRENTSKIN_SETSKIN:
+ if (pdispparams->cArgs == 1)
+ {
+ const wchar_t *newSkin = pdispparams->rgvarg[0].bstrVal;
+ if (newSkin && *newSkin)
+ {
+ if (_wcsicmp(config_skin, newSkin))
+ {
+ StringCchCopyW(config_skin, MAX_PATH, newSkin);
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_REFRESHSKIN, 0);
+ }
+ }
+ return S_OK;
+ }
+ else
+ return DISP_E_BADPARAMCOUNT;
+ case DISP_CURRENTSKIN_REGISTERSKINCHANGECALLBACK:
+ return callbacks.RegisterFromDispParam(pdispparams, 0, puArgErr);
+ case DISP_CURRENTSKIN_UNREGISTERSKINCHANGECALLBACK:
+ return callbacks.UnregisterFromDispParam(pdispparams, 0, puArgErr);
+ case DISP_CURRENTSKIN_GETCOLOR:
+ if (pdispparams->cArgs == 1)
+ {
+ COLORREF color = WADlg_getColor(pdispparams->rgvarg[0].lVal);
+ color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
+ char colorString[8] = {0};
+ StringCchPrintfA(colorString, 8, "#%06X", color);
+ AutoWide answer(colorString);
+ BSTR tag = SysAllocString(answer);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = tag;
+
+ return S_OK;
+ }
+ else
+ return DISP_E_BADPARAMCOUNT;
+
+ case DISP_CURRENTSKIN_GETNAME:
+ {
+ BSTR tag = SysAllocString(config_skin);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = tag;
+ return S_OK;
+ }
+ break;
+
+ case DISP_CURRENTSKIN_GETFONTNAME:
+ {
+ BSTR tag = SysAllocString(GetFontNameW());
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = tag;
+ return S_OK;
+ }
+ break;
+
+ case DISP_CURRENTSKIN_GETFONTSIZE:
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_I4;
+ V_I4(pvarResult) = GetFontSize();
+ return S_OK;
+ }
+ case DISP_CURRENTSKIN_GETPLAYLISTCOLOR:
+ if (pdispparams->cArgs == 1)
+ {
+ COLORREF color = Skin_PLColors[pdispparams->rgvarg[0].lVal];
+ color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
+ char colorString[8] = {0};
+ StringCchPrintfA(colorString, 8, "#%06X", color);
+ AutoWide answer(colorString);
+ BSTR tag = SysAllocString(answer);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = tag;
+
+ return S_OK;
+ }
+ else
+ return DISP_E_BADPARAMCOUNT;
+
+ case DISP_CURRENTSKIN_GETXMLSKINLIST:
+ {
+ int max=0;
+ if (pdispparams->cArgs == 1)
+ {
+
+ max = _wtoi(pdispparams->rgvarg[0].bstrVal);
+ }
+
+ wchar_t tempPath[MAX_PATH] = {0};
+ GetTempPathW(MAX_PATH, tempPath);
+ wchar_t tempFile[MAX_PATH] = {0};
+ GetTempFileNameW(tempPath, L"slx", 0, tempFile);
+ WriteSkinsAsXML(tempFile, max);
+
+ HANDLE plFile = CreateFileW(tempFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+ size_t flen = SetFilePointer(plFile, 0, NULL, FILE_END);
+ SetFilePointer(plFile, 0, NULL, FILE_BEGIN);
+
+ SAFEARRAY *bufferArray=SafeArrayCreateVector(VT_UI1, 0, (ULONG)flen);
+ void *data;
+ SafeArrayAccessData(bufferArray, &data);
+
+ DWORD bytesRead = 0;
+
+ ReadFile(plFile, data, (DWORD)flen, &bytesRead, 0);
+
+ SafeArrayUnaccessData(bufferArray);
+ CloseHandle(plFile);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_ARRAY|VT_UI1;
+ V_ARRAY(pvarResult) = bufferArray;
+ DeleteFileW(tempFile);
+ }
+ return S_OK;
+
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP SkinCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+
+ULONG SkinCOM::AddRef(void)
+{
+ return 0;
+}
+
+
+ULONG SkinCOM::Release(void)
+{
+ return 0;
+}
+
+static void SkinChangedNotifyCb(IDispatch *dispatch, void *param)
+{
+ UNREFERENCED_PARAMETER(param);
+
+ DISPPARAMS params;
+
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = 0;
+ params.rgvarg = 0;
+ unsigned int ret;
+
+ if (!(config_no_visseh&8))
+ {
+ try
+ {
+ dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+ }
+ catch(...)
+ {
+ }
+ }
+ else
+ dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
+}
+
+void SkinCOM::SkinChanged()
+{
+ callbacks.Notify(SkinChangedNotifyCb, NULL, NULL);
+}
diff --git a/Src/Winamp/SkinCOM.h b/Src/Winamp/SkinCOM.h
new file mode 100644
index 00000000..d3525541
--- /dev/null
+++ b/Src/Winamp/SkinCOM.h
@@ -0,0 +1,28 @@
+#ifndef NULLSOFT_SKINCOMH
+#define NULLSOFT_SKINCOMH
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./dispatchCallback.h"
+
+class SkinCOM : public IDispatch
+{
+public:
+
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ void SkinChanged();
+ DispatchCallbackStore callbacks;
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/SkinColorElement.cpp b/Src/Winamp/SkinColorElement.cpp
new file mode 100644
index 00000000..cb9eb1b5
--- /dev/null
+++ b/Src/Winamp/SkinColorElement.cpp
@@ -0,0 +1,20 @@
+#include "api.h"
+#include "SkinColorElement.h"
+#include "PaletteManager.h"
+
+SkinItem *SkinColorElement::getAncestor()
+{
+ return WASABI_API_PALETTE->getColorAncestor(this);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+#define CBCLASS SkinColorElement
+START_DISPATCH;
+CB(SKINITEM_GETXMLROOTPATH, getXmlRootPath);
+CB(SKINITEM_GETNAME, getName);
+CB(SKINITEM_GETPARAMS, getParams);
+CB(SKINITEM_GETSKINPARTID, getSkinPartId);
+CB(SKINITEM_GETANCESTOR, getAncestor);
+END_DISPATCH;
diff --git a/Src/Winamp/SkinColorElement.h b/Src/Winamp/SkinColorElement.h
new file mode 100644
index 00000000..e210d5ef
--- /dev/null
+++ b/Src/Winamp/SkinColorElement.h
@@ -0,0 +1,65 @@
+#ifndef NULLSOFT_GEN_FF_SKINCOLORELEMENT_H
+#define NULLSOFT_GEN_FF_SKINCOLORELEMENT_H
+
+#include <api/skin/skinitem.h>
+#include "ParamList.h"
+
+struct SkinColorElement : public SkinItem
+{
+public:
+ SkinColorElement(const wchar_t *_id, ARGB32 v, int script_id = -1, int secondarycounter = 0, const wchar_t *colorgrp = NULL, const wchar_t *path = NULL, ifc_xmlreaderparams *p = NULL)
+ : id(_id), value(v), scriptid(script_id), seccount(secondarycounter), colorgroup(colorgrp), rootpath(path)
+ {
+ if (p != NULL)
+ {
+ for (size_t i = 0;i != p->getNbItems();i++)
+ params.addItem(p->getItemName(i), p->getItemValue(i));
+ }
+ }
+
+ const wchar_t *getXmlRootPath() { return rootpath; }
+ const wchar_t *getName() { return L"color"; }
+ ifc_xmlreaderparams *getParams() { return &params; }
+ int getSkinPartId() { return scriptid; }
+ SkinItem *getAncestor();
+ const wchar_t *getId() { return id; }
+ ARGB32 getColor() { return value; }
+ ARGB32 *getColorRef() { return &value; }
+ int getSecCount() { return seccount; }
+ const wchar_t *getColorGroup() { return colorgroup; }
+
+private:
+ RECVS_DISPATCH;
+ StringW id;
+ ARGB32 value;
+ int scriptid;
+ int seccount;
+ StringW colorgroup;
+ StringW rootpath;
+ ParamList params;
+};
+
+class SortSkinColorElement
+{
+public:
+ static int compareItem(SkinColorElement *p1, SkinColorElement *p2)
+ {
+ int r = WCSICMP(p1->getId(), p2->getId());
+ if (!r)
+ {
+ if (p1->getSkinPartId() < p2->getSkinPartId()) return -1;
+ if (p1->getSkinPartId() > p2->getSkinPartId()) return 1;
+ if (p1->getSecCount() < p2->getSecCount()) return -1;
+ if (p1->getSecCount() > p2->getSecCount()) return 1;
+ return 0;
+ }
+ return r;
+ }
+ static int compareAttrib(const wchar_t *attrib, SkinColorElement *item)
+ {
+ return WCSICMP(attrib, item->getId());
+ }
+};
+
+
+#endif
diff --git a/Src/Winamp/SkinCursorElement.cpp b/Src/Winamp/SkinCursorElement.cpp
new file mode 100644
index 00000000..75f11500
--- /dev/null
+++ b/Src/Winamp/SkinCursorElement.cpp
@@ -0,0 +1,104 @@
+#include "api.h"
+#include "SkinCursorElement.h"
+#include "PaletteManager.h"
+#include <tataki/canvas/bltcanvas.h>
+
+SkinCursorElement::SkinCursorElement(const wchar_t *_id, const wchar_t *_bitmapid, int _x, int _y, int script_id, int secondarycounter, const wchar_t *path, ifc_xmlreaderparams *p)
+{
+ id = _id;
+ bitmap = _bitmapid;
+ x = _x;
+ y = _y;
+ icon = NULL;
+ scriptid = script_id;
+ seccount = secondarycounter;
+
+ if (p != NULL)
+ {
+ for (size_t i = 0;i != p->getNbItems();i++)
+ params.addItem(p->getItemName(i), p->getItemValue(i));
+ }
+ rootpath = path;
+}
+
+SkinCursorElement::~SkinCursorElement()
+{
+ if (icon != 0)
+ {
+#ifdef WIN32
+ DestroyIcon(icon);
+#else
+ DebugString("portme: ~skincursorelement\n");
+#endif
+
+ }
+
+}
+
+void SkinCursorElement::makeCursor()
+{
+ if (icon)
+ {
+#ifdef WIN32
+ DestroyIcon(icon);
+#else
+ DebugString("portme: skincursorelement::makeCursor\n");
+#endif
+ icon = NULL;
+ }
+
+#ifdef WIN32
+ ICONINFO info;
+ info.fIcon = FALSE;
+ info.xHotspot = x;
+ info.yHotspot = y;
+
+ // make AND bitmask from alpha channel
+
+ SkinBitmap bm(bitmap);
+ int *bits = (int *)bm.getBits();
+ int _x = bm.getX();
+ int _y = bm.getY();
+ int w = bm.getWidth();
+ int h = bm.getHeight();
+ int fw = bm.getFullWidth();
+//CUT: int fh = bm.getFullHeight();
+
+ BltCanvas c(w, h, NULL, 8);
+ unsigned __int8 *d = (unsigned __int8 *)c.getBits();
+ for (int i = 0;i < h;i++)
+ {
+ int *p = bits + _x + x + (_y + y) * fw;
+ int j = w;
+ while (j--)
+ {
+ int a = (*p++ & 0xFF000000) >> 24;
+ *d++ = (a > 0x7F) ? 0xFF : 0;
+ }
+ }
+
+ // copy bits onto a canvas to get hbitmap
+ BltCanvas cc(w, h);
+ bm.blit(&cc, 0, 0);
+
+ info.hbmMask = c.getBitmap();
+ info.hbmColor = cc.getBitmap();
+
+ // create cursor
+ icon = CreateIconIndirect(&info);
+#else
+ DebugString("portme: skincursorelement::makeCursor\n");
+#endif
+}
+
+OSCURSOR SkinCursorElement::getCursor()
+{
+ if (icon == INVALIDOSCURSORHANDLE)
+ makeCursor();
+ return icon;
+}
+
+SkinItem *SkinCursorElement::getAncestor()
+{
+ return WASABI_API_PALETTE->getCursorAncestor(this);
+} \ No newline at end of file
diff --git a/Src/Winamp/SkinCursorElement.h b/Src/Winamp/SkinCursorElement.h
new file mode 100644
index 00000000..17a5ec0c
--- /dev/null
+++ b/Src/Winamp/SkinCursorElement.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <api/wnd/cursor.h>
+#include <api/skin/skinitem.h>
+#include "ParamList.h"
+#include <api/skin/api_skin.h> // for OSCURSOR, probably should put this in a better place
+
+class SkinCursorElement : public SkinItemI
+{
+ friend class SortSkinCursorElement;
+public:
+ SkinCursorElement(const wchar_t *_id, const wchar_t *_bitmapid, int _x, int _y, int script_id = -1, int secondarycounter = 0, const wchar_t *path = NULL, ifc_xmlreaderparams *params = NULL);
+ virtual ~SkinCursorElement();
+
+ const wchar_t *getId() { return id; }
+ const wchar_t *getBitmapId() { return bitmap; }
+ int getHotspotX() { return x; }
+ int getHotspotY() { return y; }
+ int getScriptId() { return scriptid; }
+ int getSecId() { return seccount; }
+
+ virtual OSCURSOR getCursor();
+
+ virtual const wchar_t *getXmlRootPath() { return rootpath; }
+ virtual const wchar_t *getName() { return L"cursor"; }
+ virtual ifc_xmlreaderparams *getParams() { return &params; }
+ virtual int getSkinPartId() { return scriptid; }
+ virtual SkinItem *getAncestor();
+
+private:
+
+ void makeCursor();
+
+ StringW id;
+ StringW bitmap;
+ StringW rootpath;
+ ParamList params;
+ int x;
+ int y;
+ int scriptid;
+ int seccount;
+ OSCURSOR icon;
+};
+
+class SortSkinCursorElement
+{
+public:
+ static int compareItem(SkinCursorElement *p1, SkinCursorElement *p2)
+ {
+ int r = WCSICMP(p1->id, p2->id);
+ if (!r)
+ {
+ if (p1->scriptid < p2->scriptid) return -1;
+ if (p1->scriptid > p2->scriptid) return 1;
+ if (p1->seccount < p2->seccount) return -1;
+ if (p1->seccount > p2->seccount) return 1;
+ return 0;
+ }
+ return r;
+ }
+ static int compareAttrib(const wchar_t *attrib, SkinCursorElement *item)
+ {
+ return WCSICMP(attrib, item->id);
+ }
+};
diff --git a/Src/Winamp/SkinElementAlias.cpp b/Src/Winamp/SkinElementAlias.cpp
new file mode 100644
index 00000000..08edb116
--- /dev/null
+++ b/Src/Winamp/SkinElementAlias.cpp
@@ -0,0 +1,8 @@
+#include "api.h"
+#include "SkinElementAlias.h"
+#include "PaletteManager.h"
+
+SkinItem *SkinElementAlias::getAncestor()
+{
+ return WASABI_API_PALETTE->getAliasAncestor(this);
+}
diff --git a/Src/Winamp/SkinElementAlias.h b/Src/Winamp/SkinElementAlias.h
new file mode 100644
index 00000000..462f9d9c
--- /dev/null
+++ b/Src/Winamp/SkinElementAlias.h
@@ -0,0 +1,65 @@
+#pragma once
+#include <api/skin/skinitem.h>
+#include "ParamList.h"
+struct SkinElementAlias : public SkinItemI
+{
+public:
+
+ SkinElementAlias(const wchar_t *_aliasname, const wchar_t *_idtarget, int _scriptid = -1, int _secondarycounter = 0)
+ : aliasname(_aliasname), idtarget(_idtarget), scriptid(_scriptid), seccount(_secondarycounter) //, rootpath(path)
+ {
+ params = NULL;
+ /*
+ if (p != NULL) {
+ params = new XmlReaderParamsI();
+ for (int i=0;i<p->getNbItems();i++) {
+ params->addItem(p->getItemName(i), p->getItemValue(i));
+ }
+ }
+ */
+ }
+ virtual ~SkinElementAlias()
+ {
+ delete params;
+ }
+
+ const wchar_t *getAliasName() { return aliasname; }
+ const wchar_t *getTargetId() { return idtarget; }
+ int getSecCount() { return seccount; }
+
+ virtual const wchar_t *getXmlRootPath() { return rootpath; }
+ virtual const wchar_t *getName() { return L"elementalias"; }
+ virtual ifc_xmlreaderparams *getParams() { return params; }
+ virtual int getSkinPartId() { return scriptid; }
+ virtual SkinItem *getAncestor();
+
+private:
+ StringW aliasname;
+ StringW idtarget;
+ int scriptid;
+ int seccount;
+ ParamList *params;
+ StringW rootpath;
+};
+
+class SortSkinElementAlias
+{
+public:
+ static int compareItem(SkinElementAlias *p1, SkinElementAlias *p2)
+ {
+ int r = WCSICMP(p1->getAliasName(), p2->getAliasName());
+ if (!r)
+ {
+ if (p1->getSkinPartId() < p2->getSkinPartId()) return -1;
+ if (p1->getSkinPartId() > p2->getSkinPartId()) return 1;
+ if (p1->getSecCount() < p2->getSecCount()) return -1;
+ if (p1->getSecCount() > p2->getSecCount()) return 1;
+ return 0;
+ }
+ return r;
+ }
+ static int compareAttrib(const wchar_t *attrib, SkinElementAlias *item)
+ {
+ return WCSICMP(attrib, item->getAliasName());
+ }
+}; \ No newline at end of file
diff --git a/Src/Winamp/SkinUtils.cpp b/Src/Winamp/SkinUtils.cpp
new file mode 100644
index 00000000..50d46ddf
--- /dev/null
+++ b/Src/Winamp/SkinUtils.cpp
@@ -0,0 +1,32 @@
+#include "main.h"
+#define WA_DLG_IMPLEMENT
+#include "wa_dlg.h"
+
+const char *GetFontName()
+{
+ if (config_custom_plfont && *playlist_custom_font)
+ return playlist_custom_font;
+ if (!Skin_PLFont[0])
+ {
+ static char lang_font[128]; // benski> this is thread-safe because the language pack won't change (changing lang packs requires winamp restart)
+ return getString(IDS_PLFONT, lang_font, 128);
+ }
+ return Skin_PLFont;
+}
+
+const wchar_t *GetFontNameW()
+{
+ if (config_custom_plfont && *playlist_custom_fontW)
+ return playlist_custom_fontW;
+ if (!Skin_PLFontW[0])
+ {
+ static wchar_t lang_fontW[128]; // benski> this is thread-safe because the language pack won't change (changing lang packs requires winamp restart)
+ return getStringW(IDS_PLFONT, lang_fontW, 128);
+ }
+ return Skin_PLFontW;
+}
+
+int GetFontSize()
+{
+ return ScaleY(config_pe_fontsize);
+} \ No newline at end of file
diff --git a/Src/Winamp/Skins.cpp b/Src/Winamp/Skins.cpp
new file mode 100644
index 00000000..48a84f66
--- /dev/null
+++ b/Src/Winamp/Skins.cpp
@@ -0,0 +1,943 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author:
+** Created:
+**/
+
+#include "main.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+#include "minizip/unzip.h"
+#include "api.h"
+
+int g_skinloadedmanually;
+int g_skinmissinggenff = 0;
+
+HWND skin_hwnd;
+
+BOOL _cleanupDirW(const wchar_t *dir)
+{
+ wchar_t dirmask[MAX_PATH] = {0};
+ HANDLE h;
+ WIN32_FIND_DATAW d = {0};
+ PathCombineW(dirmask, dir, L"*.*");
+ h = FindFirstFileW(dirmask, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ wchar_t v[MAX_PATH] = {0};
+ PathCombineW(v, dir, d.cFileName);
+ if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if (wcscmp(d.cFileName,L".") && wcscmp(d.cFileName,L".."))
+ _cleanupDirW(v);
+ }
+ else
+ {
+ if(!DeleteFileW(v))
+ {
+ // this handles some rogue cases where files in the wlz's aren't unloadable
+ MoveFileExW(v, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+ MoveFileExW(dir, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+ }
+ }
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+
+ return RemoveDirectoryW(dir);
+}
+
+// attempt to cleanup the last extracted temp folder for a skin incase Winamp crashed on exit
+void Skin_CleanupAfterCrash(void)
+{
+ wchar_t buf[1024] = {0};
+ char str[78] = {0};
+ StringCchPrintfA(str,78,"skin_clean_up%ws",szAppName);
+ _r_sW(str, buf, sizeof(buf));
+ if (buf[0])
+ {
+ _cleanupDirW(buf);
+ _w_sW(str, 0);
+ }
+}
+
+void Skin_CleanupZip(void)
+{
+ if (!SKINTEMPDIR[0]) return ;
+ if (_cleanupDirW(SKINTEMPDIR))
+ {
+ char str[78] = {0};
+ StringCchPrintfA(str,78,"skin_clean_up%ws",szAppName);
+ _w_s(str, 0);
+ }
+}
+
+void CreateDirectoryForFileW(wchar_t *fn, wchar_t *base)
+{
+ wchar_t buf1[MAX_PATH] = {0};
+ wchar_t *tmp;
+ wchar_t *p;
+ StringCchCopyW(buf1, MAX_PATH, fn);
+ tmp = scanstr_backW(buf1, L"\\/", buf1);
+ *tmp = 0;
+ tmp = buf1;
+ while (tmp && *tmp) { if (*tmp == L'/') *tmp = L'\\'; tmp++; }
+
+ p = buf1 + wcslen(base);
+ while (p && *p)
+ {
+ while (p && *p != L'\\' && *p) p = CharNextW(p);
+ if (p && !*p) CreateDirectoryW(buf1, NULL);
+ else
+ {
+ if (p) *p = 0;
+ CreateDirectoryW(buf1, NULL);
+ if (p) *p++ = L'\\';
+ }
+ }
+}
+
+static void make_skin_dir(void)
+{
+ if (config_skin[0])
+ {
+ if (_wcsicmp(extensionW(config_skin), L"zip") && _wcsicmp(extensionW(config_skin), L"wsz") && _wcsicmp(extensionW(config_skin), L"wal"))
+ {
+ if (PathIsFileSpecW(config_skin) || PathIsRelativeW(config_skin))
+ PathCombineW(skin_directory, SKINDIR, config_skin);
+ else
+ StringCchCopyW(skin_directory, MAX_PATH, config_skin);
+ }
+ else
+ {
+ wchar_t dirmask[MAX_PATH] = {0};
+ char str[78] = {0};
+ StringCchCopyW(skin_directory, MAX_PATH, SKINTEMPDIR);
+ CreateDirectoryW(SKINTEMPDIR, NULL);
+ StringCchPrintfA(str, 78, "skin_clean_up%ws", szAppName);
+ _w_sW(str, SKINTEMPDIR);
+ {
+ unzFile f;
+ if (PathIsFileSpecW(config_skin) || PathIsRelativeW(config_skin))
+ PathCombineW(dirmask, SKINDIR, config_skin);
+ else
+ StringCchCopyW(dirmask, MAX_PATH, config_skin);
+ f = unzOpen(AutoChar(dirmask));
+ if (f)
+ {
+ int iswa3 = 0;
+
+ if (unzGoToFirstFile(f) == UNZ_OK)
+ {
+ wchar_t buriedskinxml[MAX_PATH] = {0};
+ wchar_t *p;
+ StringCchCopyW(buriedskinxml, MAX_PATH, config_skin);
+ p = wcschr(buriedskinxml, '.');
+ if (p) *p = 0;
+ StringCchCatW(buriedskinxml, MAX_PATH, L"/skin.xml");
+ do
+ {
+ char filename[MAX_PATH] = {0};
+ unzGetCurrentFileInfo(f, NULL, filename, sizeof(filename), NULL, 0, NULL, 0);
+ if (!_stricmp(filename, "skin.xml") || !_stricmp(filename, AutoChar(buriedskinxml))) iswa3++;
+ }
+ while (!iswa3 && unzGoToNextFile(f) == UNZ_OK);
+ }
+
+ if (unzGoToFirstFile(f) == UNZ_OK)
+ {
+ OVERLAPPED asyncIO = {0};
+ int isNT = (GetVersion() < 0x80000000);
+ if (isNT)
+ {
+ asyncIO.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
+ asyncIO.OffsetHigh = 0;
+ }
+ do
+ {
+ char filename[MAX_PATH], *fn, *p;
+ if (isNT)
+ SetEvent(asyncIO.hEvent);
+ unzGetCurrentFileInfo(f, NULL, filename, sizeof(filename), NULL, 0, NULL, 0);
+
+ //Only extract the file-types that could be in a skin
+ //If we don't filter here it's a security hole
+ if (iswa3)
+ {
+ if (unzOpenCurrentFile(f) == UNZ_OK)
+ {
+ fn = filename;
+ if (strstr(fn, ":")) fn = strstr(fn, ":") + 1;
+ while (fn && *fn == '\\') fn++;
+ p = extension(fn);
+
+ // TODO: really should enum image loaders so we only extract supported image files
+ if (fn[0] && (p != NULL && (!_stricmp(p, "xml") || !_stricmp(p, "png") ||
+ !_stricmp(p, "cur") || !_stricmp(p, "bmp") || !_stricmp(p, "txt") ||
+ !_stricmp(p, "gif") || !_stricmp(p, "ttf") || !_stricmp(p, "m") ||
+ !_stricmp(p, "maki") || !_stricmp(p, "mp3") || !_stricmp(p, "wma") ||
+ !_stricmp(p, "nsv") || !_stricmp(p, "nsa") || !_stricmp(p, "m4a") ||
+ !_stricmp(p, "avi") || !_stricmp(p, "wav") || !_stricmp(p, "mp4") ||
+ !_stricmp(p, "ogg") || IsPlaylistExtension(AutoWide(p)) ||
+ !_stricmp(p, "mpg") || !_stricmp(p, "mid") || !_stricmp(p, "midi") ||
+ !_stricmp(p, "mpeg") || !_stricmp(p, "url") || !_stricmp(p, "jpg") ||
+ !_stricmp(p, "mi") ) ) )
+ {
+ PathCombineW(dirmask, SKINTEMPDIR, AutoWide(fn));
+ CreateDirectoryForFileW(dirmask, SKINTEMPDIR);
+ goto do_write;
+ }
+ }
+ }
+ else
+ {
+ fn = scanstr_back(filename, "\\/", filename - 1);
+ p = extension(++fn);
+ if (!_stricmp(p, "txt") || !_stricmp(p, "cur") || !_stricmp(p, "bmp") || !_stricmp(p, "ini"))
+ {
+ int success = 0;
+ if (unzOpenCurrentFile(f) == UNZ_OK)
+ {
+ HANDLE fp;
+
+ PathCombineW(dirmask, SKINTEMPDIR, AutoWide(fn));
+
+do_write:
+ //fp = fopen(dirmask,"wb");
+ fp = CreateFileW(dirmask, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | (isNT ? FILE_FLAG_OVERLAPPED : 0), NULL);
+ if (fp != INVALID_HANDLE_VALUE)
+ {
+ int l = 0, pos = 0, bufNum=0;
+
+ #define SKIN_ZIP_BUFFER_SIZE 2048
+ char buf[SKIN_ZIP_BUFFER_SIZE*2] = {0};
+ success = 1;
+ do
+ {
+ DWORD written = 0;
+ bufNum = !bufNum; // bufNum = (bufNUm + 1) %2;
+ l = unzReadCurrentFile(f, buf+SKIN_ZIP_BUFFER_SIZE*bufNum, SKIN_ZIP_BUFFER_SIZE);
+ if (!l)
+ unzCloseCurrentFile(f);
+ if (isNT)
+ {
+ WaitForSingleObject(asyncIO.hEvent, INFINITE);
+ if (l > 0)
+ {
+ asyncIO.Offset = pos;
+ if (WriteFile(fp, buf+SKIN_ZIP_BUFFER_SIZE*bufNum, l, NULL, &asyncIO) == FALSE
+ && GetLastError() != ERROR_IO_PENDING)
+ {
+ success=0;
+ }
+ pos += l;
+ }
+ }
+ else
+ {
+ if (l > 0)
+ {
+ if (WriteFile(fp, buf+SKIN_ZIP_BUFFER_SIZE*bufNum, l, &written, NULL) == FALSE)
+ success = 0;
+ }
+ }
+ } while (l > 0 && success);
+
+ CloseHandle(fp);
+ }
+ }
+ }
+ }
+ }
+ while (unzGoToNextFile(f) == UNZ_OK);
+ if (isNT && asyncIO.hEvent)
+ {
+ CloseHandle(asyncIO.hEvent);
+ }
+ }
+ unzClose(f);
+ }
+ }
+ }
+ }
+ else skin_directory[0] = 0;
+}
+
+int Skin_PLColors[6] =
+{
+ RGB(0, 255, 0),
+ RGB(255, 255, 255),
+ RGB(0, 0, 0),
+ RGB(0, 0, 198),
+ RGB(0, 255, 0),
+ RGB(0, 0, 0),
+}, Skin_UseGenNums = 0;
+char Skin_PLFont[128] = "";
+wchar_t Skin_PLFontW[128] = L"";
+
+static BOOL CALLBACK skinDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static int *skin_rgn_points, *skin_rgn_numpoints, skin_rgn_numpoints_tot;
+static int *skin_rgn_points_eq, *skin_rgn_numpoints_eq, skin_rgn_numpoints_tot_eq;
+static int *skin_rgn_points_eq_ws, *skin_rgn_numpoints_eq_ws, skin_rgn_numpoints_tot_eq_ws;
+static int *skin_rgn_points_ws, *skin_rgn_numpoints_ws, skin_rgn_numpoints_tot_ws;
+static int *skin_rgn_points_pl, *skin_rgn_numpoints_pl, skin_rgn_numpoints_tot_pl;
+static int *skin_rgn_points_pl_ws, *skin_rgn_numpoints_pl_ws, skin_rgn_numpoints_tot_pl_ws;
+
+int Skin_GetRegionPointList( int eq, int **points, int **counts )
+{
+ if ( !eq )
+ {
+ if ( config_windowshade )
+ {
+ *points = skin_rgn_points_ws;
+ *counts = skin_rgn_numpoints_ws;
+
+ return skin_rgn_numpoints_tot_ws;
+ }
+ else
+ {
+ *points = skin_rgn_points;
+ *counts = skin_rgn_numpoints;
+
+ return skin_rgn_numpoints_tot;
+ }
+ }
+ else if ( eq == 1 )
+ {
+ if ( config_eq_ws )
+ {
+ *points = skin_rgn_points_eq_ws;
+ *counts = skin_rgn_numpoints_eq_ws;
+
+ return skin_rgn_numpoints_tot_eq_ws;
+ }
+ else
+ {
+ *points = skin_rgn_points_eq;
+ *counts = skin_rgn_numpoints_eq;
+
+ return skin_rgn_numpoints_tot_eq;
+ }
+ }
+ else if ( eq == 2 )
+ {
+ if ( config_pe_height == 14 )
+ {
+ *points = skin_rgn_points_pl_ws;
+ *counts = skin_rgn_numpoints_pl_ws;
+
+ return skin_rgn_numpoints_tot_pl_ws;
+ }
+ else
+ {
+ *points = skin_rgn_points_pl;
+ *counts = skin_rgn_numpoints_pl;
+
+ return skin_rgn_numpoints_tot_pl;
+ }
+ }
+
+
+ return 0;
+}
+
+static int getnums( char *section, char *name, const wchar_t *fn, int **list )
+{
+ char buf[ 65535 ] = { 0 }, *p = buf;
+ int n = 0, nn;
+ GetPrivateProfileStringA( section, name, "", buf, sizeof( buf ), AutoChar( fn ) );
+
+ while ( p )
+ {
+ int t = 0;
+ while ( p && ( *p == ' ' || *p == '\t' || *p == ',' ) ) p++;
+ if ( p && *p == '-' ) p++;
+ while ( p && ( *p >= '0' && *p <= '9' ) )
+ {
+ t = 1; p++;
+ }
+ if ( t ) n++;
+ else break;
+ }
+
+ if ( !n )
+ return 0;
+
+ p = buf;
+ list[ 0 ] = (int *) GlobalAlloc( GPTR, sizeof( int ) * n );
+ nn = n;
+ n = 0;
+
+ while ( p && n < nn )
+ {
+ int t = 0;
+ int s = 0, sign = 1;
+
+ while ( p && ( *p == ' ' || *p == '\t' || *p == ',' ) )
+ p++;
+
+ if ( p && *p == '-' )
+ {
+ sign = -1; p++;
+ }
+
+ while ( p && ( *p >= '0' && *p <= '9' ) )
+ {
+ s = s * 10 + *p++ - '0'; t = 1;
+ }
+
+ if ( t )
+ list[ 0 ][ n++ ] = s * sign;
+ else
+ break;
+ }
+ return n;
+}
+
+static int hexGetPrivateProfileInt( char *sec, char *key, int def, const wchar_t *fn )
+{
+ char str[ 100 ] = { 0 }, *s = str;
+
+ if ( !GetPrivateProfileStringA( sec, key, "", str, sizeof( str ), AutoChar( fn ) ) || !*str )
+ return def;
+
+ if ( s && *s == '#' )
+ s++;
+
+ if ( s )
+ def = strtol( s, &s, 16 );
+
+ int r = ( def >> 16 ) & 255;
+ int g = ( def >> 8 ) & 255;
+ int b = def & 255;
+
+ return RGB( r, g, b );
+}
+
+HCURSOR Skin_Cursors[ N_CURSORS ];
+
+static void Skin_LoadCursors( void )
+{
+ static struct
+ {
+ int cid;
+ const wchar_t *fn;
+ }
+ cursor_loads[ N_CURSORS ] =
+ {
+ // main, non windowshade, start 0, end 8
+ {IDC_LRSCROLL, L"VolBal.cur"}, // vol & bal
+ {IDC_LRSCROLL, L"Posbar.cur"}, // pos
+ {IDC_NORMALCURSOR, L"WinBut.cur"}, //wshade
+ {IDC_NORMALCURSOR, L"Min.cur"}, //min
+ {IDC_DANGER, L"Close.cur"}, //close
+ {IDC_NORMALCURSOR, L"MainMenu.cur"}, //mainmenu
+ {IDC_MOVEMAIN, L"TitleBar.cur"}, // titelbar
+ {IDC_LRSCROLL, L"SongName.cur"},
+ {IDC_NORMALCURSOR, L"Normal.cur"},
+ // main, windowshade, start 9, end 14
+ {IDC_NORMALCURSOR, L"WinBut.cur"}, //wshade
+ {IDC_NORMALCURSOR, L"Min.cur"}, //min
+ {IDC_LRSCROLL, L"WSPosbar.cur"}, // seeker
+ {IDC_DANGER, L"Close.cur"}, //close
+ {IDC_NORMALCURSOR, L"MMenu.cur"}, //mainmenu
+ {IDC_NORMALCURSOR, L"WSNormal.cur"},
+ // playlist editor, normal, start 15 end 20
+ {IDC_NORMALCURSOR, L"PWinBut.cur"}, //wshade
+ {IDC_DANGER, L"PClose.cur"}, //close
+ {IDC_MOVEMAIN, L"PTBar.cur"}, // titelbar
+ {IDC_UDSCROLL, L"PVScroll.cur"},
+ {IDC_RESIZE, L"PSize.cur"},
+ {IDC_NORMALCURSOR, L"PNormal.cur"},
+ // playlist editor, windowshade, start 21 end 24
+ {IDC_NORMALCURSOR, L"PWinBut.cur"}, //wshade
+ {IDC_DANGER, L"PClose.cur"}, //close
+ {IDC_LRSCROLL, L"PWSSize.cur"}, //size
+ {IDC_NORMALCURSOR, L"PWSNorm.cur"},
+ // equalizer start 25, end 28
+ {IDC_UDSCROLL, L"EQSlid.cur"},
+ {IDC_DANGER, L"EQClose.cur"}, //close
+ {IDC_MOVEMAIN, L"EQTitle.cur"}, // titelbar
+ {IDC_NORMALCURSOR, L"EQNormal.cur"},
+ };
+
+ int x;
+
+ for ( x = 0; x < N_CURSORS; x++ )
+ {
+ if ( Skin_Cursors[ x ] )
+ DestroyCursor( Skin_Cursors[ x ] );
+
+ Skin_Cursors[ x ] = 0;
+ }
+
+ for ( x = 0; x < N_CURSORS; x++ )
+ {
+ HCURSOR hc = 0;
+
+ if ( config_skin[ 0 ] )
+ {
+ wchar_t sn[ MAX_PATH ] = { 0 };
+ PathCombineW( sn, skin_directory, cursor_loads[ x ].fn );
+ hc = (HCURSOR) LoadImageW( NULL, sn, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE );
+ }
+
+ if ( !hc )
+ {
+ hc = (HCURSOR) LoadImageW( hMainInstance, MAKEINTRESOURCEW( cursor_loads[ x ].cid ), IMAGE_CURSOR, 0, 0, 0 );
+ }
+
+ Skin_Cursors[ x ] = hc;
+ }
+}
+
+#define COLOR_ERROR (0xff00ff)
+
+static ARGB32 parseColor( const char *color, int *error )
+{
+ *error = 0;
+
+ if ( color == NULL || *color == '\0' )
+ {
+ *error = 1;
+
+ return COLOR_ERROR;
+ }
+
+ if ( strchr( color, ',' ) )
+ {
+ int r = 0, g = 0, b = 0;
+
+ if ( sscanf( color, "%d,%d,%d", &r, &g, &b ) != 3 )
+ {
+ *error = 1;
+
+ return COLOR_ERROR;
+ }
+
+ return RGB( r, g, b ); // our colors are reversed internally
+ }
+
+ if ( *color == '#' )
+ {
+ int r = 0, g = 0, b = 0;
+
+ if ( sscanf( color, "#%02x%02x%02x", &r, &g, &b ) != 3 )
+ {
+ *error = 1;
+
+ return COLOR_ERROR;
+ }
+
+ return RGB( r, g, b );
+ }
+
+ *error = 1;
+
+ return COLOR_ERROR;
+}
+
+static void Skin_LoadFreeformColors( const wchar_t *fn )
+{
+ WASABI_API_PALETTE->Reset();
+ FILE *f = _wfopen( fn, L"rt" );
+
+ if ( f )
+ {
+ char buffer[ 1024 ] = { 0 };
+
+ if ( fgets( buffer, 1024, f ) )
+ {
+ size_t len = strlen( buffer );
+
+ if ( buffer[ len - 1 ] == '\n' )
+ buffer[ len - 1 ] = 0;
+
+ if ( !strcmp( buffer, "[colors]" ) )
+ {
+ WASABI_API_PALETTE->StartTransaction();
+
+ while ( !feof( f ) )
+ {
+ fgets( buffer, 1024, f );
+
+ char *equal_pt = strchr( buffer, '=' );
+
+ if ( equal_pt )
+ {
+ *equal_pt = 0;
+ int error = 0;
+ ARGB32 color = parseColor( equal_pt + 1, &error );
+
+ if ( !error )
+ {
+ wchar_t utf8_expand[ 1024 ] = { 0 };
+
+ MultiByteToWideCharSZ( CP_UTF8, 0, buffer, -1, utf8_expand, 1024 );
+
+ WASABI_API_PALETTE->AddColor( utf8_expand, color );
+ }
+ }
+ }
+
+ WASABI_API_PALETTE->EndTransaction();
+ }
+ }
+
+ fclose( f );
+ }
+}
+
+BOOL Skin_Check_Modern_Support()
+{
+ wchar_t fn[ MAX_PATH ] = { 0 };
+
+ PathCombineW( fn, skin_directory, L"skin.xml" );
+
+ if ( PathFileExistsW( fn ) && !GetModuleHandleW( L"gen_ff.dll" ) )
+ {
+ g_skinmissinggenff = 1;
+
+ return FALSE;
+ }
+
+ g_skinmissinggenff = 0;
+
+ return TRUE;
+}
+
+void Skin_Load(void)
+{
+ Skin_CleanupZip();
+ make_skin_dir();
+ g_skinmissinggenff = 0;
+
+ if (skin_rgn_points) GlobalFree(skin_rgn_points);
+ if (skin_rgn_numpoints) GlobalFree(skin_rgn_numpoints);
+ skin_rgn_numpoints = NULL;
+ skin_rgn_points = NULL;
+
+ if (skin_rgn_points_ws) GlobalFree(skin_rgn_points_ws);
+ if (skin_rgn_numpoints_ws) GlobalFree(skin_rgn_numpoints_ws);
+ skin_rgn_numpoints_ws = NULL;
+ skin_rgn_points_ws = NULL;
+
+ if (skin_rgn_points_eq) GlobalFree(skin_rgn_points_eq);
+ if (skin_rgn_numpoints_eq) GlobalFree(skin_rgn_numpoints_eq);
+ skin_rgn_numpoints_eq = NULL;
+ skin_rgn_points_eq = NULL;
+
+ if (skin_rgn_points_eq_ws) GlobalFree(skin_rgn_points_eq_ws);
+ if (skin_rgn_numpoints_eq_ws) GlobalFree(skin_rgn_numpoints_eq_ws);
+ skin_rgn_numpoints_eq_ws = NULL;
+ skin_rgn_points_eq_ws = NULL;
+
+ if (skin_rgn_points_pl) GlobalFree(skin_rgn_points_pl);
+ if (skin_rgn_numpoints_pl) GlobalFree(skin_rgn_numpoints_pl);
+ skin_rgn_numpoints_pl = NULL;
+ skin_rgn_points_pl = NULL;
+
+ if (skin_rgn_points_pl_ws) GlobalFree(skin_rgn_points_pl_ws);
+ if (skin_rgn_numpoints_pl_ws) GlobalFree(skin_rgn_numpoints_pl_ws);
+ skin_rgn_numpoints_pl_ws = NULL;
+ skin_rgn_points_pl_ws = NULL;
+
+ skin_rgn_numpoints_tot = 0;
+ skin_rgn_numpoints_tot_ws = 0;
+ skin_rgn_numpoints_tot_eq = 0;
+ skin_rgn_numpoints_tot_eq_ws = 0;
+ skin_rgn_numpoints_tot_pl = 0;
+ skin_rgn_numpoints_tot_pl_ws = 0;
+
+ int t_Skin_PLColors[6] =
+ {
+ RGB(0, 255, 0),
+ RGB(255, 255, 255),
+ RGB(0, 0, 0),
+ RGB(0, 0, 198),
+ RGB(0, 255, 0),
+ RGB(0, 0, 0),
+ };
+ memcpy(Skin_PLColors, t_Skin_PLColors, sizeof(Skin_PLColors));
+ Skin_PLFont[0] = 0;
+ Skin_PLFontW[0] = 0;
+ Skin_UseGenNums = !config_skin[0];
+
+ // load default freeform colors
+ if (!config_skin[0])
+ {
+ WASABI_API_PALETTE->Reset();
+ WASABI_API_PALETTE->StartTransaction();
+ WASABI_API_PALETTE->AddColor(L"wasabi.popupmenu.background.selected", RGB(0x75, 0x74, 0x8B));
+ WASABI_API_PALETTE->AddColor(L"wasabi.popupmenu.background", RGB(0x38, 0x37, 0x57));
+ WASABI_API_PALETTE->AddColor(L"wasabi.popupmenu.text", RGB(0xFF, 0xFF, 0xFF));
+ WASABI_API_PALETTE->AddColor(L"wasabi.popupmenu.text.selected", RGB(0xFF, 0xFF, 0xFF));
+ WASABI_API_PALETTE->AddColor(L"wasabi.popupmenu.text.inactive", RGB(0x73, 0x73, 0x89));
+ WASABI_API_PALETTE->AddColor(L"wasabi.popupmenu.frame", RGB(0x75, 0x74, 0x8B));
+ WASABI_API_PALETTE->AddColor(L"wasabi.popupmenu.separator", RGB(0x75, 0x74, 0x8B));
+ WASABI_API_PALETTE->AddColor(L"wasabi.tooltip.background", RGB(0x38, 0x37, 0x57));
+ WASABI_API_PALETTE->AddColor(L"wasabi.tooltip.text", RGB(0xFF, 0xFF, 0xFF));
+ WASABI_API_PALETTE->AddColor(L"wasabi.tooltip.frame", RGB(0x75, 0x74, 0x8B));
+ WASABI_API_PALETTE->EndTransaction();
+ }
+
+ if (skin_directory[0])
+ {
+ if (!Skin_Check_Modern_Support())
+ {
+ Skin_LoadCursors();
+ return;
+ }
+
+ wchar_t fn[MAX_PATH] = {0};
+ PathCombineW(fn, skin_directory, L"region.txt");
+ skin_rgn_numpoints_tot = getnums("Normal", "NumPoints", fn, &skin_rgn_numpoints);
+ if (skin_rgn_numpoints_tot)
+ {
+ int all_p;
+ if ((all_p = getnums("Normal", "PointList", fn, &skin_rgn_points)))
+ {
+ int o = 0;
+ int x;
+ for (x = 0; x < skin_rgn_numpoints_tot; x ++)
+ o += skin_rgn_numpoints[x];
+ if (o == all_p / 2 && !(all_p & 1)) goto s1;
+ // else MessageBox(NULL,"region.txt:\n[Normal]\npoints in PointList\ndon't match NumPoints","Error in skin:",0);
+ }
+ }
+
+ if (skin_rgn_numpoints) GlobalFree(skin_rgn_numpoints);
+ if (skin_rgn_points) GlobalFree(skin_rgn_points);
+ skin_rgn_numpoints_tot = 0;
+ skin_rgn_numpoints = NULL;
+ skin_rgn_points = NULL;
+
+s1:
+ skin_rgn_numpoints_tot_ws = getnums("WindowShade", "NumPoints", fn, &skin_rgn_numpoints_ws);
+ if (skin_rgn_numpoints_tot_ws)
+ {
+ int all_p;
+ if ((all_p = getnums("WindowShade", "PointList", fn, &skin_rgn_points_ws)))
+ {
+ int o = 0;
+ int x;
+ for (x = 0; x < skin_rgn_numpoints_tot_ws; x ++)
+ o += skin_rgn_numpoints_ws[x];
+ if (o == all_p / 2 && !(all_p & 1)) goto s2;
+ // else MessageBox(NULL,"region.txt:\n[Windowshade]\npoints in PointList\ndon't match NumPoints","Error in skin:",0);
+ }
+ }
+ if (skin_rgn_numpoints_ws) GlobalFree(skin_rgn_numpoints_ws);
+ if (skin_rgn_points_ws) GlobalFree(skin_rgn_points_ws);
+ skin_rgn_numpoints_ws = NULL;
+ skin_rgn_numpoints_tot_ws = 0;
+ skin_rgn_points_ws = NULL;
+
+s2:
+ skin_rgn_numpoints_tot_eq = getnums("Equalizer", "NumPoints", fn, &skin_rgn_numpoints_eq);
+ if (skin_rgn_numpoints_tot_eq)
+ {
+ int all_p;
+ if ((all_p = getnums("Equalizer", "PointList", fn, &skin_rgn_points_eq)))
+ {
+ int o = 0;
+ int x;
+ for (x = 0; x < skin_rgn_numpoints_tot_eq; x ++)
+ o += skin_rgn_numpoints_eq[x];
+ if (o == all_p / 2 && !(all_p & 1)) goto s3;
+ // else MessageBox(NULL,"region.txt:\n[Equalizer]\npoints in PointList\ndon't match NumPoints","Error in skin:",0);
+ }
+ }
+ if (skin_rgn_numpoints_eq) GlobalFree(skin_rgn_numpoints_eq);
+ if (skin_rgn_points_eq) GlobalFree(skin_rgn_points_eq);
+ skin_rgn_numpoints_eq = NULL;
+ skin_rgn_numpoints_tot_eq = 0;
+ skin_rgn_points_eq = NULL;
+
+s3:
+ skin_rgn_numpoints_tot_eq_ws = getnums("EqualizerWS", "NumPoints", fn, &skin_rgn_numpoints_eq_ws);
+ if (skin_rgn_numpoints_tot_eq_ws)
+ {
+ int all_p;
+ if ((all_p = getnums("EqualizerWS", "PointList", fn, &skin_rgn_points_eq_ws)))
+ {
+ int o = 0;
+ int x;
+ for (x = 0; x < skin_rgn_numpoints_tot_eq_ws; x ++)
+ o += skin_rgn_numpoints_eq_ws[x];
+ if (o == all_p / 2 && !(all_p & 1)) goto s4;
+ // else MessageBox(NULL,"region.txt:\n[EqualizerWS]\npoints in PointList\ndon't match NumPoints","Error in skin:",0);
+ }
+ }
+ if (skin_rgn_numpoints_eq_ws) GlobalFree(skin_rgn_numpoints_eq_ws);
+ if (skin_rgn_points_eq_ws) GlobalFree(skin_rgn_points_eq_ws);
+ skin_rgn_numpoints_eq_ws = NULL;
+ skin_rgn_numpoints_tot_eq_ws = 0;
+ skin_rgn_points_eq_ws = NULL;
+
+s4:
+ /*skin_rgn_numpoints_tot_pl = getnums("Playlist", "NumPoints", fn, &skin_rgn_numpoints_pl);
+ if (skin_rgn_numpoints_tot_pl)
+ {
+ int all_p;
+ if ((all_p = getnums("Playlist", "PointList", fn, &skin_rgn_points_pl)))
+ {
+ int o = 0;
+ int x;
+ for (x = 0; x < skin_rgn_numpoints_tot_pl; x ++)
+ o += skin_rgn_numpoints_pl[x];
+ if (o == all_p / 2 && !(all_p & 1)) goto s5;
+ // else MessageBox(NULL,"region.txt:\n[Playlist]\npoints in PointList\ndon't match NumPoints","Error in skin:",0);
+ }
+ }*/
+ if (skin_rgn_numpoints_pl) GlobalFree(skin_rgn_numpoints_pl);
+ if (skin_rgn_points_pl) GlobalFree(skin_rgn_points_pl);
+ skin_rgn_numpoints_pl = NULL;
+ skin_rgn_numpoints_tot_pl = 0;
+ skin_rgn_points_pl = NULL;
+
+
+//s5:
+ /*skin_rgn_numpoints_tot_pl_ws = getnums("PlaylistWS", "NumPoints", fn, &skin_rgn_numpoints_pl_ws);
+ if (skin_rgn_numpoints_tot_pl_ws)
+ {
+ int all_p;
+ if ((all_p = getnums("PlaylistWS", "PointList", fn, &skin_rgn_points_pl_ws)))
+ {
+ int o = 0;
+ int x;
+ for (x = 0; x < skin_rgn_numpoints_tot_pl_ws; x ++)
+ o += skin_rgn_numpoints_pl_ws[x];
+ if (o == all_p / 2 && !(all_p & 1)) goto s6;
+ // else MessageBox(NULL,"region.txt:\n[PlaylistWS]\npoints in PointList\ndon't match NumPoints","Error in skin:",0);
+ }
+ }*/
+// if (skin_rgn_numpoints_pl_ws) GlobalFree(skin_rgn_numpoints_pl_ws);
+// if (skin_rgn_points_pl_ws) GlobalFree(skin_rgn_points_pl_ws);
+// skin_rgn_numpoints_pl_ws = NULL;
+// skin_rgn_numpoints_tot_pl_ws = 0;
+// skin_rgn_points_pl_ws = NULL;
+
+//s6:
+// ;
+
+#if 0
+ {
+ char str[1024] = {0};
+ PathCombine(fn, skin_directory, "mb.ini");
+ GetPrivateProfileString("Winamp", "MBOpen", "", str, sizeof(str), fn);
+ str[1023] = 0;
+ if (str[0])
+ {
+ if (hMBWindow)
+ {
+ if (g_skinloadedmanually) SendMessageW(hMainWindow, WM_USER, (WPARAM)0, IPC_MBOPEN);
+ SendMessageW(hMainWindow, WM_USER, (WPARAM)str, IPC_MBOPEN);
+ }
+ else
+ {
+ extern char page_nav[1024];
+ if (g_skinloadedmanually) config_mb_open = 1;
+ lstrcpy(page_nav, str);
+ }
+ }
+ }
+#endif
+
+ PathCombineW(fn, skin_directory, L"pledit.txt");
+
+ Skin_PLColors[0] = hexGetPrivateProfileInt("Text", "Normal", Skin_PLColors[0], fn);
+ Skin_PLColors[1] = hexGetPrivateProfileInt("Text", "Current", Skin_PLColors[1], fn);
+ Skin_PLColors[2] = hexGetPrivateProfileInt("Text", "NormalBG", Skin_PLColors[2], fn);
+ Skin_PLColors[3] = hexGetPrivateProfileInt("Text", "SelectedBG", Skin_PLColors[3], fn);
+ Skin_PLColors[4] = hexGetPrivateProfileInt("Text", "mbFG", Skin_PLColors[4], fn);
+ Skin_PLColors[5] = hexGetPrivateProfileInt("Text", "mbBG", Skin_PLColors[5], fn);
+
+ char plfont[256] = {0};
+
+ GetPrivateProfileStringA("Text", "Font", "", plfont, 256, AutoChar(fn));
+ MultiByteToWideCharSZ(CP_UTF8, 0, plfont, -1, Skin_PLFontW, sizeof(Skin_PLFontW)/sizeof(*Skin_PLFontW));
+ WideCharToMultiByteSZ(CP_ACP, 0, Skin_PLFontW, -1, Skin_PLFont, sizeof(Skin_PLFont)/sizeof(*Skin_PLFont), 0, 0);
+ // used to allow for the gen.bmp numbers support in 5.64 - need skin to say as too many have junk where it's taken from
+ Skin_UseGenNums = GetPrivateProfileIntW(L"Misc", L"UseGenNums", 0, fn);
+
+ PathCombineW(fn, skin_directory, L"colors.ini");
+ Skin_LoadFreeformColors(fn);
+ }
+ Skin_LoadCursors();
+}
+
+void Skin_Random(void)
+{
+ if (config_randskin)
+ {
+ HANDLE h;
+ WIN32_FIND_DATAW d = {0};
+ int v, x;
+ wchar_t dirmask[MAX_PATH] = {0};
+ PathCombineW(dirmask, SKINDIR, L"*");
+ x = 1;
+ h = FindFirstFileW(dirmask, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if (wcscmp(d.cFileName, L".") && wcscmp(d.cFileName, L"..")) x++;
+ }
+ else if (!_wcsicmp(extensionW(d.cFileName), L"zip") || !_wcsicmp(extensionW(d.cFileName), L"wsz") || !_wcsicmp(extensionW(d.cFileName), L"wal"))
+ x++;
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+ v = warand() % x;
+ if (!v)
+ {
+ config_skin[0] = 0;
+ return ;
+ }
+ x = 1;
+ h = FindFirstFileW(dirmask, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ int t = 0;
+ if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if (wcscmp(d.cFileName, L".") && wcscmp(d.cFileName, L"..")) t = 1;
+ }
+ else if (!_wcsicmp(extensionW(d.cFileName), L"zip") || !_wcsicmp(extensionW(d.cFileName), L"wsz") || !_wcsicmp(extensionW(d.cFileName), L"wal")) t = 1;
+ if (t)
+ {
+ if (x == v)
+ {
+ StringCchCopyW(config_skin, MAX_PATH, d.cFileName);
+ break;
+ }
+ x++;
+ }
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_REFRESHSKIN, 0);
+
+ if (prefs_last_page == 40 && IsWindow(prefs_hwnd))
+ {
+ prefs_last_page = 0;
+ prefs_dialog(1);
+ prefs_last_page = 40;
+ prefs_dialog(1);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/SysCallbacks.cpp b/Src/Winamp/SysCallbacks.cpp
new file mode 100644
index 00000000..23245732
--- /dev/null
+++ b/Src/Winamp/SysCallbacks.cpp
@@ -0,0 +1,201 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author: Ben Allison benski@nullsoft.com
+** Created:
+**/
+#include "main.h"
+#include "SysCallbacks.h"
+#include <api/syscb/callbacks/syscb.h>
+#include "../nu/AutoLock.h"
+using namespace Nullsoft::Utility;
+
+SysCallbacks::SysCallbacks()
+{
+ reentry=0;
+ inCallback=false;
+}
+
+//note: it's OK to add in the middle of an issueCallback
+//because new callbacks go at the end of the list
+//and the lockguard prevents list corruption
+int SysCallbacks::syscb_registerCallback(SysCallback *cb, void *param)
+{
+ AutoLock lock(callbackGuard LOCKNAME("SysCallbacks::syscb_registerCallback"));
+ int event_type = cb->getEventType();
+ //CallbackList *&callbacks = callback_map[event_type];
+ //if (!callbacks)
+ // callbacks = new CallbackList;
+ //callbacks->push_back(cb);
+ EventMap::iterator find = callback_map.find(event_type);
+ CallbackList* callbacks = 0;
+ if (find != callback_map.end())
+ {
+ callbacks = find->second;
+ }
+ else
+ {
+ callbacks = new CallbackList();
+ callback_map.insert({ event_type, callbacks });
+ }
+
+ if (callbacks)
+ {
+ callbacks->push_back(cb);
+ }
+ return 1;
+}
+
+int SysCallbacks::syscb_deregisterCallback(SysCallback *cb)
+{
+ AutoLock lock(callbackGuard LOCKNAME("SysCallbacks::syscb_deregisterCallback"));
+ if (inCallback)
+ deleteMeAfterCallbacks.push_back(cb);
+ else
+ {
+ int event_type = cb->getEventType();
+ EventMap::iterator find = callback_map.find(event_type);
+ if (find != callback_map.end())
+ {
+ CallbackList *callbacks = find->second;
+ if (callbacks)
+ {
+ //callbacks->eraseAll(cb);
+ auto it = callbacks->begin();
+ while ( it != callbacks->end())
+ {
+ if (*it != cb)
+ {
+ it++;
+ continue;
+ }
+
+ it = callbacks->erase(it);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+int SysCallbacks::syscb_issueCallback(int event_type, int msg, intptr_t param1 , intptr_t param2)
+{
+ AutoLock lock(callbackGuard LOCKNAME("SysCallbacks::syscb_issueCallback"));
+ reentry++;
+ inCallback=true;
+ EventMap::iterator find = callback_map.find(event_type);
+ if (find != callback_map.end())
+ {
+ CallbackList *callbacks = find->second;
+ if (callbacks)
+ {
+ for (size_t i=0;i<callbacks->size();i++)
+ {
+ SysCallback *callback = callbacks->at(i);
+ //if (!deleteMeAfterCallbacks.contains(callback))
+ // callback->notify(msg, param1, param2);
+ bool found = false;
+ for (auto obj : deleteMeAfterCallbacks)
+ {
+ if (obj == callback)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ callback->notify(msg, param1, param2);
+ }
+ }
+ }
+
+ inCallback=false;
+ reentry--;
+ if (reentry==0)
+ {
+ for ( SysCallback *l_sys_call_back : deleteMeAfterCallbacks )
+ {
+ for (EventMap::iterator itr=callback_map.begin(); itr != callback_map.end(); itr++)
+ {
+ CallbackList *callbacks = itr->second;
+ if (callbacks)
+ {
+ //callbacks->eraseAll(cb);
+ auto it = callbacks->begin();
+ while (it != callbacks->end())
+ {
+ if (*it != l_sys_call_back )
+ {
+ it++;
+ continue;
+ }
+
+ it = callbacks->erase(it);
+ }
+ }
+ }
+ }
+ deleteMeAfterCallbacks.clear();
+ }
+ return 1;
+}
+
+SysCallback *SysCallbacks::syscb_enum(int event_type, size_t n)
+{
+ AutoLock lock(callbackGuard LOCKNAME("SysCallbacks::syscb_enum"));
+ // TODO: maybe check !deleteMeAfterCallbacks.contains(callbacks[i])
+ if (event_type)
+ {
+ EventMap::iterator find = callback_map.find(event_type);
+ if (find != callback_map.end())
+ {
+ CallbackList *callbacks = find->second;
+ if (callbacks)
+ {
+ if (n <= callbacks->size())
+ {
+ SysCallback *callback = callbacks->at(n);
+ if (callback)
+ callback->AddRef(); // benski> don't be fooled. most objects don't actually support reference counting
+ return callback;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // enumerates ALL syscallbacks
+ for (EventMap::iterator itr=callback_map.begin(); itr != callback_map.end(); itr++)
+ {
+ CallbackList *callbacks = itr->second;
+ if (callbacks)
+ {
+ if (n >= callbacks->size())
+ {
+ n-=callbacks->size();
+ }
+ else
+ {
+ SysCallback *callback = callbacks->at(n);
+ if (callback)
+ callback->AddRef(); // benski> don't be fooled. most objects don't actually support reference counting
+ return callback;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+#define CBCLASS SysCallbacks
+START_DISPATCH;
+CB(API_SYSCB_SYSCB_REGISTERCALLBACK, syscb_registerCallback)
+CB(API_SYSCB_SYSCB_DEREGISTERCALLBACK, syscb_deregisterCallback)
+CB(API_SYSCB_SYSCB_ISSUECALLBACK, syscb_issueCallback)
+CB(API_SYSCB_SYSCB_ENUM, syscb_enum)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/SysCallbacks.h b/Src/Winamp/SysCallbacks.h
new file mode 100644
index 00000000..809a80db
--- /dev/null
+++ b/Src/Winamp/SysCallbacks.h
@@ -0,0 +1,35 @@
+#ifndef NULLSOFT_SYSCALLBACKSH
+#define NULLSOFT_SYSCALLBACKSH
+
+#include <api/syscb/api_syscb.h>
+#include "../nu/AutoLock.h"
+#include <map>
+#include <vector>
+
+class SysCallbacks : public api_syscb
+{
+public:
+ static const char *getServiceName() { return "System Callback API"; }
+ static const GUID getServiceGuid() { return syscbApiServiceGuid; }
+public:
+ SysCallbacks();
+ int syscb_registerCallback(SysCallback *cb, void *param = NULL);
+ int syscb_deregisterCallback(SysCallback *cb);
+ int syscb_issueCallback(int eventtype, int msg, intptr_t param1 = 0, intptr_t param2 = 0);
+ SysCallback *syscb_enum(int eventtype, size_t n);
+
+protected:
+ RECVS_DISPATCH;
+private:
+ Nullsoft::Utility::LockGuard callbackGuard;
+ typedef std::vector<SysCallback*> CallbackList;
+ typedef std::map<int, CallbackList*> EventMap;
+ EventMap callback_map;
+ CallbackList deleteMeAfterCallbacks;
+ bool inCallback;
+ volatile int reentry;
+};
+
+extern SysCallbacks *sysCallbacks;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/TIMING.H b/Src/Winamp/TIMING.H
new file mode 100644
index 00000000..2f35446b
--- /dev/null
+++ b/Src/Winamp/TIMING.H
@@ -0,0 +1,24 @@
+#ifndef _TIMING_H_
+#define _TIMING_H_
+
+
+//#define TIMING
+
+
+#if defined(TIMING) && !defined(__alpha)
+void _timingPrint(void);
+void _timingInit(void);
+void _timingLeave(int);
+void _timingEnter(int);
+#define timingPrint() _timingPrint()
+#define timingInit() _timingInit()
+#define timingLeave(x) _timingLeave(x)
+#define timingEnter(x) _timingEnter(x)
+#else
+#define timingPrint()
+#define timingInit()
+#define timingLeave(x)
+#define timingEnter(x)
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/TIMING.cpp b/Src/Winamp/TIMING.cpp
new file mode 100644
index 00000000..905ce748
--- /dev/null
+++ b/Src/Winamp/TIMING.cpp
@@ -0,0 +1,77 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include "timing.h"
+
+#ifdef TIMING
+#ifndef __alpha
+
+
+static struct {
+ unsigned int st_time[2];
+ unsigned int cycles;
+ unsigned int calls;
+} timingInfo[64];
+
+static int timingEnters;
+
+static void rdtsc(unsigned int t[2])
+{
+ __asm
+ {
+ mov esi, t
+ _emit 0xf
+ _emit 0x31
+ mov [esi], eax
+ mov [esi+4], edx
+ }
+}
+
+void _timingInit()
+{
+ memset(timingInfo,0,sizeof(timingInfo));
+}
+
+void _timingEnter(int which)
+{
+// if (!timingEnters++) __asm cli
+ rdtsc(timingInfo[which].st_time);
+}
+
+void _timingLeave(int which)
+{
+ unsigned int t[2];
+ rdtsc(t);
+// if (!--timingEnters) __asm sti
+ if (t[1]==timingInfo[which].st_time[1])
+ {
+ timingInfo[which].cycles += t[0]-timingInfo[which].st_time[0];
+ }
+ else
+ {
+ timingInfo[which].cycles += t[0]+(0xffffffff-timingInfo[which].st_time[0]);
+ }
+ timingInfo[which].calls++;
+}
+
+void _timingPrint()
+{
+ int x;
+ FILE *fp = fopen("C:\\timings.txt","a+t");
+ for (x = 0; x < sizeof(timingInfo)/sizeof(timingInfo[0]); x ++)
+ {
+ if (timingInfo[x].calls)
+ fprintf(fp,"%d: %d calls, %d clocks/call\n",x,timingInfo[x].calls,timingInfo[x].cycles/timingInfo[x].calls);
+ }
+ _timingInit();
+ fclose(fp);
+}
+
+#endif
+#endif
diff --git a/Src/Winamp/TagProvider.cpp b/Src/Winamp/TagProvider.cpp
new file mode 100644
index 00000000..6c8ea722
--- /dev/null
+++ b/Src/Winamp/TagProvider.cpp
@@ -0,0 +1,47 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+
+#include "main.h"
+#include "TagProvider.h"
+#include "tagz.h"
+/* --- TagProvider --- */
+
+wchar_t *TagProvider::GetTag(const wchar_t *name, ifc_tagparams *parameters)
+{
+ const wchar_t *filename = (const wchar_t *)parameters->GetParameter(&filenameParameterID);
+ if (!filename)
+ return 0;
+
+ wchar_t *tag = Winamp::GetTag(name, filename);
+ if (tag == reinterpret_cast<wchar_t *>(-1))
+ return 0;
+
+ if (!tag)
+ tag = Winamp::GetExtendedTag(name, filename);
+
+ if (tag == reinterpret_cast<wchar_t *>(-1))
+ return 0;
+ return tag;
+}
+
+void TagProvider::FreeTag(wchar_t *tag)
+{
+ free(tag);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS TagProvider
+START_DISPATCH;
+CB(IFC_TAGPROVIDER_GET_TAG, GetTag);
+VCB(IFC_TAGPROVIDER_FREE_TAG, FreeTag);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/TagProvider.h b/Src/Winamp/TagProvider.h
new file mode 100644
index 00000000..e5ffe334
--- /dev/null
+++ b/Src/Winamp/TagProvider.h
@@ -0,0 +1,28 @@
+#include "../tagz/ifc_tagprovider.h"
+#include "api.h"
+#include <api/service/waservicefactorybase.h>
+
+class TagProvider : public ifc_tagprovider
+{
+public:
+ wchar_t *GetTag(const wchar_t *name, ifc_tagparams *parameters);
+ void FreeTag(wchar_t *Tag);
+protected:
+ RECVS_DISPATCH;
+};
+extern TagProvider *tagProvider;
+
+// {9490752F-23BF-4923-86F1-E1186543EC64}
+static const GUID WinampTagProviderGUID =
+{ 0x9490752f, 0x23bf, 0x4923, { 0x86, 0xf1, 0xe1, 0x18, 0x65, 0x43, 0xec, 0x64 } };
+
+
+/*
+class TagProviderFactory : public waServiceBase<ifc_tagprovider, TagProviderFactory> {
+public:
+ TagProviderFactory() : waServiceBase<ifc_tagprovider, TagProviderFactory>(WinampTagProviderGUID) {}
+ static const char *getServiceName() { return "Winamp Tag Provider"; }
+ virtual api_tagprovider *getService() { return tagProvider; }
+ static FOURCC getServiceType() { return api_tagprovider::getServiceType(); }
+};
+*/
diff --git a/Src/Winamp/TempFileCOM.cpp b/Src/Winamp/TempFileCOM.cpp
new file mode 100644
index 00000000..117b75a5
--- /dev/null
+++ b/Src/Winamp/TempFileCOM.cpp
@@ -0,0 +1,126 @@
+#include "TempFileCOM.h"
+#include <shlwapi.h>
+
+enum
+{
+ DISP_TEMPFILE_WRITE_STRING,
+ DISP_TEMPFILE_CLOSE,
+ DISP_TEMPFILE_GET_FILENAME,
+ DISP_TEMPFILE_DELETE,
+};
+
+TempFileCOM::TempFileCOM(const wchar_t *ext)
+{
+ ref=1;
+
+ wchar_t tempPath[MAX_PATH-14] = {0};
+ GetTempPathW(MAX_PATH-14, tempPath);
+ GetTempFileNameW(tempPath, L"tfc", 0, filename);
+ if (ext)
+ {
+ PathRemoveExtensionW(filename);
+ PathAddExtensionW(filename, ext);
+ }
+ hFile = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0);
+ wchar_t BOM = 0xFEFF;
+ DWORD written = 0;
+ WriteFile(hFile, &BOM, 2, &written, NULL);
+}
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT TempFileCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ bool unknowns = false;
+ for (unsigned int i = 0;i != cNames;i++)
+ {
+ CHECK_ID("WriteString", DISP_TEMPFILE_WRITE_STRING);
+ CHECK_ID("Close", DISP_TEMPFILE_CLOSE);
+ CHECK_ID("GetFilename", DISP_TEMPFILE_GET_FILENAME);
+ CHECK_ID("Delete", DISP_TEMPFILE_DELETE);
+
+ rgdispid[i] = DISPID_UNKNOWN;
+ unknowns = true;
+
+ }
+ if (unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT TempFileCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT TempFileCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT TempFileCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch (dispid)
+ {
+ case DISP_TEMPFILE_WRITE_STRING:
+ {
+ const wchar_t *str = pdispparams->rgvarg[0].bstrVal;
+ DWORD written=0;
+ WriteFile(hFile, str, (DWORD)wcslen(str)*sizeof(wchar_t), &written, NULL);
+ return S_OK;
+ }
+ case DISP_TEMPFILE_CLOSE:
+ CloseHandle(hFile);
+ hFile=INVALID_HANDLE_VALUE;
+ return S_OK;
+ case DISP_TEMPFILE_GET_FILENAME:
+ {
+ BSTR tag = SysAllocString(filename);
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_BSTR;
+ V_BSTR(pvarResult) = tag;
+ return S_OK;
+ }
+ case DISP_TEMPFILE_DELETE:
+ DeleteFileW(filename);
+ return S_OK;
+ }
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP TempFileCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+
+ULONG TempFileCOM::AddRef(void)
+{
+ return (ULONG)++ref;
+}
+
+
+ULONG TempFileCOM::Release(void)
+{
+ if (--ref == 0)
+ delete this;
+
+ return (ULONG)ref;
+}
diff --git a/Src/Winamp/TempFileCOM.h b/Src/Winamp/TempFileCOM.h
new file mode 100644
index 00000000..84fde665
--- /dev/null
+++ b/Src/Winamp/TempFileCOM.h
@@ -0,0 +1,21 @@
+#pragma once
+#include <ocidl.h>
+#include <windows.h>
+
+class TempFileCOM : public IDispatch
+{
+public:
+ TempFileCOM(const wchar_t *extension);
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ HANDLE hFile;
+ wchar_t filename[MAX_PATH];
+ size_t ref;
+}; \ No newline at end of file
diff --git a/Src/Winamp/Ui.cpp b/Src/Winamp/Ui.cpp
new file mode 100644
index 00000000..b20a0ec8
--- /dev/null
+++ b/Src/Winamp/Ui.cpp
@@ -0,0 +1,1290 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include <malloc.h>
+#include "api.h"
+#include "resource.h"
+
+int minimize_hack_winamp;
+
+#define inreg(x,y,x2,y2) \
+ ((mouse_x <= ( x2 ) && mouse_x >= ( x ) && \
+ mouse_y <= ( y2 ) && mouse_y >= ( y )))
+
+static int mouse_x, mouse_y, mouse_type, mouse_stats;
+
+static int do_titlebar_clicking;
+
+static int do_buttonbar();
+static int do_shuffle();
+static int do_peeq();
+static int do_repeat();
+static int do_eject();
+static int do_icon();
+static int do_posbar();
+static int do_volbar();
+static int do_panbar();
+static int do_songname();
+static int do_titlebar();
+static int do_titlebuttons();
+static int do_timedisplay();
+static int do_clutterbar();
+
+static BOOL HasParent(HWND hwnd)
+{
+ return ((0 != (WS_CHILD & GetWindowLongPtrW(hwnd, GWL_STYLE))) && NULL != GetParent(hwnd));
+}
+
+void ui_handlemouseevent(int x, int y, int type, int stats)
+{
+ mouse_x = x;
+ mouse_y = y;
+ mouse_type = type;
+ mouse_stats = stats;
+ if (do_titlebar_clicking || (!do_posbar() &&
+ !do_volbar() && !do_panbar() && !do_songname()))
+ {
+ if (do_titlebar_clicking || !(do_buttonbar()+
+ do_shuffle()+
+ do_repeat()+
+ do_eject()+
+ do_peeq()+
+ do_icon()+
+ do_clutterbar()+
+ do_timedisplay()))
+ {
+ if (do_titlebar_clicking || !do_titlebuttons()) do_titlebar();
+ }
+ }
+}
+
+static int __do_buttons(int which)
+{
+ int m = WINAMP_BUTTON1 + which;
+ if (which == 5)
+ {
+ if (mouse_stats & MK_CONTROL) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_LOC,0);
+ else if (mouse_stats & MK_SHIFT) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_DIR,0);
+ else SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_PLAY,0);
+ }
+ else
+ {
+ if (mouse_stats & MK_SHIFT) m += 100;
+ else if (mouse_stats & MK_CONTROL) m += 110;
+ SendMessageW(hMainWindow,WM_COMMAND,m,0);
+ }
+ return 0;
+}
+
+static int do_clutterbar_active;
+static int do_clutterbar()
+{
+ int en=0,t=0;
+
+ if (mouse_type == -2)
+ return 0;
+
+ if (inreg(11,24,19,31))
+ {
+ en=1;
+ if (mouse_type == -1)
+ {
+ POINT p = {14,25};
+ extern HMENU g_submenus_options;
+ HMENU hmenu = g_submenus_options;
+ if (config_dsize)
+ {
+ p.x *= 2;
+ p.y *= 2;
+ }
+ ClientToScreen(hMainWindow,&p);
+ DoTrackPopup(hmenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON, p.x, p.y, hMainWindow);
+ }
+ if (mouse_stats & MK_LBUTTON)
+ {
+ wchar_t songnameStr[128] = {0};
+ draw_songname(getStringW(IDS_OPTIONS_MENU,songnameStr,128),&t,-1);
+ }
+ }
+ if (inreg(11,32,19,39))
+ {
+ en=2;
+ if (mouse_type == -1) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_AOT,0);
+ if (mouse_stats & MK_LBUTTON)
+ {
+ wchar_t songnameStr[128] = {0};
+ if (config_aot)
+ draw_songname(getStringW(IDS_DISABLE_AOT,songnameStr,128),&t,-1);
+ else
+ draw_songname(getStringW(IDS_ENABLE_AOT,songnameStr,128),&t,-1);
+ }
+ }
+ if (inreg(11,40,19,47))
+ {
+ en=3;
+ if (mouse_type == -1)
+ {
+ if (FileName[0]) in_infobox(hMainWindow,FileName);
+ }
+ if (mouse_stats & MK_LBUTTON)
+ {
+ wchar_t songnameStr[128] = {0};
+ draw_songname(getStringW(IDS_FILE_INFO_BOX,songnameStr,128),&t,-1);
+ }
+ }
+ if (inreg(11,48,19,55))
+ {
+ en=4;
+ if (mouse_type == -1) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_DSIZE,0);
+ if (mouse_stats & MK_LBUTTON)
+ {
+ wchar_t songnameStr[128] = {0};
+ if (config_dsize) draw_songname(getStringW(IDS_DISABLE_DOUBLESIZE_MODE,songnameStr,128),&t,-1);
+ else draw_songname(getStringW(IDS_ENABLE_DOUBLESIZE_MODE,songnameStr,128),&t,-1);
+ }
+ }
+ if (inreg(11,56,19,62))
+ {
+ en=5;
+ if (mouse_type == -1)
+ {
+ POINT p={14,56};
+ extern HMENU g_submenus_vis;
+ if (config_dsize) {p.x*=2;p.y*=2;}
+ ClientToScreen(hMainWindow,&p);
+ DoTrackPopup(g_submenus_vis, TPM_LEFTALIGN|TPM_RIGHTBUTTON, p.x, p.y, hMainWindow);
+ }
+ if (mouse_stats & MK_LBUTTON)
+ {
+ wchar_t songnameStr[128] = {0};
+ draw_songname(getStringW(IDS_VISUALIZATION_MENU,songnameStr,128),&t,-1);
+ }
+ }
+ if (inreg(9,20,19,65) && mouse_stats & MK_LBUTTON)
+ {
+ draw_clutterbar(1+en);
+ do_clutterbar_active=1;
+ return 1;
+ }
+ if (do_clutterbar_active || mouse_type == -1)
+ {
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ do_clutterbar_active=0;
+ draw_clutterbar(0);
+ }
+ return 0;
+}
+
+static int do_timedisplay()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (((!config_windowshade && inreg(36,26,96,39)) ||
+ (config_windowshade && inreg(129,3,129+28,3+6))
+ ) && mouse_type == 1)
+ {
+ config_timeleftmode = !config_timeleftmode;
+ if (!config_timeleftmode)
+ {
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_ELAPSED,MF_CHECKED);
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_REMAINING,MF_UNCHECKED);
+ }
+ else
+ {
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_ELAPSED,MF_UNCHECKED);
+ CheckMenuItem(main_menu,WINAMP_OPTIONS_REMAINING,MF_CHECKED);
+ }
+ SendMessageW(hMainWindow,WM_TIMER,UPDATE_DISPLAY_TIMER+4,0);
+ return 1;
+ }
+ if (playing && inreg(27,40,99,61) && mouse_type == 1)
+ {
+ config_sa++;
+ if (config_sa > 2) config_sa = 0;
+ set_visopts();
+ sa_setthread(config_sa);
+ return 1;
+ }
+ if (config_windowshade && inreg(78,4,116,11) && mouse_type == 1)
+ {
+ config_sa++;
+ if (config_sa > 2) config_sa = 0;
+ set_visopts();
+ sa_setthread(config_sa);
+ return 1;
+ }
+ if (config_windowshade && inreg(168,2,213+11,11) && mouse_type == 1)
+ {
+ int which = 5 - (mouse_x < 215) - (mouse_x < 204) - (mouse_x < 195) - (mouse_x < 186) - (mouse_x < 176);
+ __do_buttons(which);
+ return 1;
+ }
+ return 0;
+}
+
+static int do_titlebar()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (do_titlebar_clicking || config_easymove || mouse_y < 14)
+ {
+ static int clickx, clicky;
+ switch (mouse_type)
+ {
+ case 1:
+ if (!do_titlebar_clicking)
+ {
+ EnterCriticalSection(&embedcs);
+ {
+ typedef struct
+ {
+ int open;
+ int at;
+ RECT r;
+ embedWindowState *isemb;
+ } rec;
+ int x;
+ int cnt = 5+embedwndlist_cnt;
+ embedWindowState *p=embedwndlist;
+ rec *a = (rec *)_malloca(cnt * sizeof(rec));
+ //rec *a = (rec*)malloc(cnt * sizeof(rec));
+ memset(a,0,cnt * sizeof(rec));
+
+ a[0].at=1;
+ a[0].open=1;
+ EstMainWindowRect(&a[0].r);
+ EstEQWindowRect(&a[1].r);a[1].open=config_eq_open;
+ EstPLWindowRect(&a[2].r);a[2].open=config_pe_open;
+ //EstMBWindowRect(&a[3].r);a[3].open=config_mb_open;
+ EstVidWindowRect(&a[4].r);a[4].open=config_video_open;
+
+ for (x = 5; x < cnt && p; x ++)
+ {
+ a[x].open=IsWindowVisible(p->me) && !HasParent(p->me);
+ a[x].isemb=p;
+ a[x].r = p->r;
+ p->attached=0;
+ p = p->link;
+ }
+
+ x=0;
+
+ do_titlebar_clicking=1;
+
+ if ((!!config_snap) ^ (!!(mouse_stats & MK_SHIFT)))
+ {
+ int t = 0;
+ for (;;)
+ {
+ if (a[x].open&&a[x].at) for (int b = 0; b < cnt; b ++)
+ {
+ if (b != x && !a[b].at && IsWindowAttached(a[x].r,a[b].r))
+ {
+ a[b].at=1;
+ t=1;
+ }
+ }
+ if (!x)
+ {
+ if (!t) break;
+ t=0;
+ }
+ x++;
+ x%=cnt;
+ }
+ if (a[1].at) do_titlebar_clicking|=2;
+ if (a[2].at) do_titlebar_clicking|=4;
+ if (a[3].at) do_titlebar_clicking|=8;
+ if (a[4].at) do_titlebar_clicking|=16;
+ for (x = 5; x < cnt && a[x].isemb; x ++)
+ a[x].isemb->attached = a[x].at;
+ }
+
+ _freea(a);
+ }
+ LeaveCriticalSection(&embedcs);
+ clickx=mouse_x;
+ clicky=mouse_y;
+ }
+ return 1;
+ case -1:
+ if (do_titlebar_clicking)
+ {
+ do_titlebar_clicking=0;
+ }
+ return 1;
+ case 0:
+ if (do_titlebar_clicking)
+ {
+ RECT eqr,plr,mwr,mbr,vwr,omwr;
+ embedWindowState *p;
+ int skip_eq = GetParent(hEQWindow) != NULL;
+ //int skip_mb = 1;//GetParent(hMBWindow) != NULL;
+ int skip_pl = GetParent(hPLWindow) != NULL;
+ int skip_vw = GetParent(hVideoWindow) != NULL;
+
+ EnterCriticalSection(&embedcs);
+
+ EstEQWindowRect(&eqr);
+ //EstMBWindowRect(&mbr);
+ EstPLWindowRect(&plr);
+ EstVidWindowRect(&vwr);
+ EstMainWindowRect(&mwr);
+
+ omwr=mwr;
+ MoveRect(&mwr,mouse_x-clickx,mouse_y-clicky);
+
+ // snap to nondocked windows
+ if ((!!config_snap) ^ (!!(mouse_stats & MK_SHIFT)))
+ {
+ embedWindowState *state=embedwndlist;
+ SnapToScreen(&mwr);
+ if (!skip_eq && config_eq_open && !(do_titlebar_clicking&2)) SnapWindowToWindow(&mwr,eqr);
+ if (!skip_pl && config_pe_open && !(do_titlebar_clicking&4)) SnapWindowToWindow(&mwr,plr);
+// if (!skip_mb && config_mb_open && !(do_titlebar_clicking&8)) SnapWindowToWindow(&mwr,mbr);
+ if (!skip_vw && config_video_open && !(do_titlebar_clicking&16)) SnapWindowToWindow(&mwr,vwr);
+
+ while (state)
+ {
+ if (IsWindowVisible(state->me) && !HasParent(state->me) && !state->attached)
+ SnapWindowToWindow(&mwr,state->r);
+ state=state->link;
+ }
+ }
+
+
+ // move docked windows the same amount the the main window has moved
+ {
+ embedWindowState *state=embedwndlist;
+ int movex=mwr.left-omwr.left;
+ int movey=mwr.top-omwr.top;
+ if (do_titlebar_clicking&2) MoveRect(&eqr,movex,movey);
+ if (do_titlebar_clicking&4) MoveRect(&plr,movex,movey);
+ if (do_titlebar_clicking&8) MoveRect(&mbr,movex,movey);
+ if (do_titlebar_clicking&16) MoveRect(&vwr,movex,movey);
+ while (state)
+ {
+ if (!HasParent(state->me) && state->attached) MoveRect(&state->r,movex,movey);
+ state=state->link;
+ }
+ }
+
+ if ((!!config_snap) ^ (!!(mouse_stats & MK_SHIFT)))
+ {
+ // dock the attached windows to the screen
+ if (config_keeponscreen&1)
+ {
+ RECT omwr;
+ int x;
+ p = embedwndlist;
+ for (x=0;;x++) // snap to screen
+ {
+ int op=0;
+ int mask=1<<(x+1);
+ intptr_t isact=(do_titlebar_clicking & mask);
+ int m=do_titlebar_clicking&~mask;
+ RECT *r=NULL;
+ if (x == 0) {op = config_eq_open && !skip_eq; r=&eqr; }
+ else if (x == 1) { op = config_pe_open && !skip_pl; r=&plr; }
+// else if (x == 2) { op = config_mb_open && !skip_mb; r=&mbr; }
+ else if (x == 3) { op = config_video_open && !skip_vw; r=&vwr; }
+ else
+ {
+ if (!p) break;
+ op=IsWindowVisible(p->me) && !HasParent(p->me);
+ isact=p->attached;
+ m=do_titlebar_clicking;
+ r=&p->r;
+ p =p->link;
+ }
+
+ if (op && isact)
+ {
+ embedWindowState *p2 = embedwndlist;
+ RECT oldr=*r;
+ SnapToScreen(r);
+ MoveRect(&mwr,r->left-oldr.left,r->top-oldr.top);
+
+ if (m & 2) MoveRect(&eqr,r->left-oldr.left,r->top-oldr.top);
+ if (m & 4) MoveRect(&plr,r->left-oldr.left,r->top-oldr.top);
+ if (m & 8) MoveRect(&mbr,r->left-oldr.left,r->top-oldr.top);
+ if (m & 16) MoveRect(&vwr,r->left-oldr.left,r->top-oldr.top);
+ while (p2)
+ {
+ if (&p2->r != r && p2->attached)
+ {
+ MoveRect(&p2->r,r->left-oldr.left,r->top-oldr.top);
+ }
+ p2=p2->link;
+ }
+ }
+ } // each window docking to screen
+
+ omwr=mwr;
+ SnapToScreen(&mwr);
+ if (do_titlebar_clicking & 2) MoveRect(&eqr,mwr.left-omwr.left,mwr.top-omwr.top);
+ if (do_titlebar_clicking & 4) MoveRect(&plr,mwr.left-omwr.left,mwr.top-omwr.top);
+ if (do_titlebar_clicking & 8) MoveRect(&mbr,mwr.left-omwr.left,mwr.top-omwr.top);
+ if (do_titlebar_clicking & 16) MoveRect(&vwr,mwr.left-omwr.left,mwr.top-omwr.top);
+ p = embedwndlist;
+ while (p)
+ {
+ if (p->attached)
+ {
+ MoveRect(&p->r,mwr.left-omwr.left,mwr.top-omwr.top);
+ }
+ p=p->link;
+ }
+ } // kepponscreen&1
+
+
+ // dock the attached windows to the non attached windows
+ {
+ int x;
+ p = embedwndlist;
+ for (x = 0;; x ++)
+ {
+ int op=0;
+ int mask=1<<(x+1);
+ intptr_t isact=do_titlebar_clicking & mask;
+ int m = do_titlebar_clicking&~mask;
+ RECT *r=NULL;
+ if (x == 0) { op = config_eq_open; r=&eqr; }
+ else if (x == 1) { op = config_pe_open; r=&plr; }
+// else if (x == 2) { op = config_mb_open; r=&mbr; }
+ else if (x == 3) { op = config_video_open; r=&vwr; }
+ else
+ {
+ if (!p) break;
+ op=IsWindowVisible(p->me) && !HasParent(p->me);
+ isact=p->attached;
+ m=do_titlebar_clicking;
+ r=&p->r;
+ p =p->link;
+ }
+
+ if (!isact && op) // if this isn't docked
+ {
+ int x2;
+ embedWindowState *p2 = embedwndlist;
+ for (x2=0;; x2 ++)
+ {
+ int op2;
+ RECT *r2;
+ int mask2=1<<(x2+1);
+ int isa2=(m & mask2);
+ if (x2 == 0) { op2 = config_eq_open; r2=&eqr; }
+ else if (x2 == 1) { op2 = config_pe_open; r2=&plr; }
+// else if (x2 == 2) { op2 = config_mb_open; r2=&mbr; }
+ else if (x2 == 3) { op2 = config_video_open; r2=&vwr; }
+ else
+ {
+ if (!p2) break;
+ op2=IsWindowVisible(p2->me) && !HasParent(p2->me);
+ isa2=&p2->r != r && p2->attached;
+ r2=&p2->r;
+ p2 =p2->link;
+ }
+
+ if (op2 && isa2)
+ {
+ embedWindowState *p3 = embedwndlist;
+ RECT r4=*r2,r3=*r2;
+ RECT omwr=mwr;
+ SnapWindowToWindow(&r4,*r);
+ MoveRect(&mwr,r4.left-r3.left,r4.top-r3.top);
+ if (m & 2) MoveRect(&eqr,mwr.left-omwr.left,mwr.top-omwr.top);
+ if (m & 4) MoveRect(&plr,mwr.left-omwr.left,mwr.top-omwr.top);
+ if (m & 8) MoveRect(&mbr,mwr.left-omwr.left,mwr.top-omwr.top);
+ if (m & 16) MoveRect(&vwr,mwr.left-omwr.left,mwr.top-omwr.top);
+ while (p3)
+ {
+ if (&p3->r != r && p3->attached)
+ {
+ MoveRect(&p3->r,mwr.left-omwr.left,mwr.top-omwr.top);
+ }
+ p3=p3->link;
+ }
+ }
+ }
+ }
+ }
+ } // dock to nonattached
+ } // if snapping
+
+ {
+ // calculate number of windows to move
+ int deferred_move_count = 1;
+ if (do_titlebar_clicking&2 && !skip_eq) deferred_move_count ++;// final EQ positioning
+ if (do_titlebar_clicking&4 && !skip_pl) deferred_move_count ++;// final PE positioning
+ if (do_titlebar_clicking&16 && !skip_vw) deferred_move_count ++;// final VW positioning
+
+ p = embedwndlist;
+ while (p)
+ {
+ if (p->attached) deferred_move_count ++;
+ p=p->link;
+ }
+
+ HDWP hdwp=BeginDeferWindowPos(deferred_move_count);
+
+ if (do_titlebar_clicking&2 && !skip_eq) // final EQ positioning
+ {
+ SetEQWindowRect(&eqr);
+ hdwp=DeferWindowPos(hdwp,hEQWindow,0,config_eq_wx,config_eq_wy,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ if (do_titlebar_clicking&4 && !skip_pl) // final PE positioning
+ {
+ SetPLWindowRect(&plr);
+ hdwp=DeferWindowPos(hdwp,hPLWindow,0,config_pe_wx,config_pe_wy,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ if (do_titlebar_clicking&16 && !skip_vw) // final VW positioning
+ {
+ SetVidWindowRect(&vwr);
+ hdwp=DeferWindowPos(hdwp,hVideoWindow,0,config_video_wx,config_video_wy,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+
+ SetMainWindowRect(&mwr);
+ hdwp=DeferWindowPos(hdwp,hMainWindow,0,config_wx,config_wy,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+
+ p = embedwndlist;
+ while (p)
+ {
+ if (p->attached)
+ {
+ hdwp=DeferWindowPos(hdwp,p->me,0,p->r.left,p->r.top,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ p=p->link;
+ }
+
+ EndDeferWindowPos(hdwp);
+ }
+ LeaveCriticalSection(&embedcs);
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int title_buttons_active[4];
+static int do_titlebuttons()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (inreg(254,3,262,12)) // windowshade button
+ {
+ if (mouse_type == -1)
+ {
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_WINDOWSHADE,0);
+ draw_tbuttons(-1,-1,-1,0);
+ title_buttons_active[3]=0;
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ title_buttons_active[3]=1;
+ draw_tbuttons(-1,-1,-1,1);
+ }
+ if (mouse_type) return 1;
+ }
+ else if (title_buttons_active[3])
+ {
+ title_buttons_active[3]=0;
+ draw_tbuttons(-1,-1,-1,0);
+ }
+
+
+ if (inreg(244,3,253,12)) // minimize button
+ {
+ if (mouse_type == -1)
+ {
+ if (GetAsyncKeyState(VK_SHIFT)>>15)
+ minimize_hack_winamp=1;
+ else
+ minimize_hack_winamp=0;
+ ShowWindow(hMainWindow,SW_MINIMIZE);
+ draw_tbuttons(-1,0,-1,-1);
+ title_buttons_active[1]=0;
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ title_buttons_active[1]=1;
+ draw_tbuttons(-1,1,-1,-1);
+ }
+ if (mouse_type) return 1;
+ }
+ else if (title_buttons_active[1])
+ {
+ title_buttons_active[1]=0;
+ draw_tbuttons(-1,0,-1,-1);
+ }
+
+ if (inreg(264,3,272,12)) // kill button
+ {
+ if (mouse_type == -1)
+ {
+ title_buttons_active[2]=0;
+ draw_tbuttons(-1,-1,0,-1);
+ if (GetAsyncKeyState(VK_SHIFT)&0x8000)
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_MAIN_WINDOW,0);
+ else
+ WASABI_API_APP->main_shutdown();
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ title_buttons_active[2]=1;
+ draw_tbuttons(-1,-1,1,-1);
+ }
+ if (mouse_type) return 1;
+ }
+ else if (title_buttons_active[2])
+ {
+ title_buttons_active[2]=0;
+ draw_tbuttons(-1,-1,0,-1);
+ }
+
+ if (inreg(5,3,17,13))
+ {
+ if (mouse_stats & MK_LBUTTON && !title_buttons_active[0])
+ {
+ SetTimer(hMainWindow,666,155,NULL);
+ title_buttons_active[0]=1;
+ draw_tbuttons(1,-1,-1,-1);
+ }
+ if (mouse_type) return 1;
+ }
+ else if (title_buttons_active[0])
+ {
+ KillTimer(hMainWindow,666);
+ title_buttons_active[0]=0;
+ draw_tbuttons(0,-1,-1,-1);
+ }
+
+ return 0;
+}
+
+
+static int do_buttonbar_needupdate;
+
+static int do_buttonbar()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (inreg(7+8,15+72,7+123,15+91))
+ {
+ int which = 4 - (mouse_x < 100+7) - (mouse_x < 77+7) - (mouse_x < 53+7) - (mouse_x < 31+7);
+ switch (mouse_type)
+ {
+ case 1: // mousedown
+ draw_buttonbar(which);
+ do_buttonbar_needupdate=1;
+ break;
+ case 0: // mousemove
+ if (mouse_stats & MK_LBUTTON)
+ {
+ draw_buttonbar(which);
+ do_buttonbar_needupdate=1;
+ }
+ break;
+ case -1: // mouseup
+ do_buttonbar_needupdate=0;
+ draw_buttonbar(-1);
+ __do_buttons(which);
+ break;
+ }
+ return 1;
+ }
+ if (do_buttonbar_needupdate)
+ {
+ do_buttonbar_needupdate=0;
+ draw_buttonbar(-1);
+ }
+ return 0;
+}
+
+
+static int do_eq_needupdate, do_pe_needupdate;
+
+static int do_peeq()
+{
+ if (mouse_type == -2)
+ {
+ if (do_eq_needupdate || do_pe_needupdate)
+ {
+ draw_eqplbut(config_eq_open,0,config_pe_open,0);
+ do_eq_needupdate=0;
+ do_pe_needupdate=0;
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (inreg(219,58,219+23,58+12)) // eq
+ {
+ switch (mouse_type)
+ {
+ case 1:
+ draw_eqplbut(config_eq_open,1,config_pe_open,0);
+ do_eq_needupdate=1;
+ break;
+ case 0:
+ if (mouse_stats & MK_LBUTTON)
+ {
+ draw_eqplbut(config_eq_open,1,config_pe_open,0);
+ do_eq_needupdate=1;
+ }
+ break;
+ case -1:
+ do_eq_needupdate=0;
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_EQ,0);
+ break;
+ }
+ return 1;
+ }
+ if (do_eq_needupdate)
+ {
+ draw_eqplbut(config_eq_open,0,config_pe_open,0);
+ do_eq_needupdate=0;
+ }
+ if (inreg(219+23,58,219+23+23,58+12)) // pl
+ {
+ switch (mouse_type)
+ {
+ case 1:
+ draw_eqplbut(config_eq_open,0,config_pe_open,1);
+ do_pe_needupdate=1;
+ break;
+ case 0:
+ if (mouse_stats & MK_LBUTTON)
+ {
+ draw_eqplbut(config_eq_open,0,config_pe_open,1);
+ do_pe_needupdate=1;
+ }
+ break;
+ case -1:
+ do_pe_needupdate=0;
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_PLEDIT,0);
+ SetForegroundWindow(hMainWindow);
+ break;
+ }
+ return 1;
+ }
+ if (do_pe_needupdate)
+ {
+ draw_eqplbut(config_eq_open,0,config_pe_open,0);
+ do_pe_needupdate=0;
+ }
+
+ return 0;
+}
+
+static int do_shuffle_needupdate;
+
+static int do_shuffle()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (inreg(133+7-4+29,75+15,181+7-4-4+29,87+15))
+ {
+ switch (mouse_type)
+ {
+ case 1:
+ draw_shuffle(config_shuffle,1);
+ do_shuffle_needupdate=1;
+ break;
+ case 0:
+ if (mouse_stats & MK_LBUTTON)
+ {
+ draw_shuffle(config_shuffle,1);
+ do_shuffle_needupdate=1;
+ }
+ break;
+ case -1:
+ do_shuffle_needupdate=0;
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_SHUFFLE,0);
+ break;
+ }
+ return 1;
+ }
+ if (do_shuffle_needupdate)
+ {
+ draw_shuffle(config_shuffle,0);
+ do_shuffle_needupdate=0;
+ }
+ return 0;
+}
+
+
+static int do_repeat_needupdate;
+
+static int do_repeat()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (inreg(182+7-4-4+29,75+15,182+29+7-4-4+29,87+15))
+ {
+ switch (mouse_type)
+ {
+ case 1:
+ draw_repeat(config_repeat,1);
+ do_repeat_needupdate=1;
+ break;
+ case 0:
+ if (mouse_stats & MK_LBUTTON)
+ {
+ draw_repeat(config_repeat,1);
+ do_repeat_needupdate=1;
+ }
+ break;
+ case -1:
+ do_repeat_needupdate=0;
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_REPEAT,0);
+ break;
+ }
+ return 1;
+ }
+ if (do_repeat_needupdate)
+ {
+ draw_repeat(config_repeat,0);
+ do_repeat_needupdate=0;
+ }
+ return 0;
+}
+
+static int do_eject_needupdate;
+
+static int do_eject()
+{
+ if (mouse_type == -2)
+ {
+ if (do_eject_needupdate)
+ {
+ draw_eject(0);
+ //do_eject_needupdate=0;
+ return 1;
+ }
+ return 0;
+ }
+ if (inreg(132+7-4+1,60+14+15,132+7-4+22+1,60+14+15+16))
+ {
+ switch (mouse_type)
+ {
+ case 1:
+ draw_eject(1);
+ do_eject_needupdate=1;
+ break;
+ case 0:
+ if (mouse_stats & MK_LBUTTON)
+ {
+ draw_eject(1);
+ do_eject_needupdate=1;
+ }
+ break;
+ case -1:
+ do_eject_needupdate=0;
+ draw_eject(0);
+ if (mouse_stats & MK_CONTROL) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_LOC,0);
+ else if (mouse_stats & MK_SHIFT) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_DIR,0);
+ else SendMessageW(hMainWindow,WM_COMMAND,WINAMP_FILE_PLAY,0);
+ break;
+ }
+ return 1;
+ }
+ if (do_eject_needupdate)
+ {
+ draw_eject(0);
+ do_eject_needupdate=0;
+ }
+ return 0;
+}
+
+
+static int do_icon()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (inreg(246+7,76+15,258+7,90+15))
+ {
+ if (mouse_type == -1)
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_LIGHTNING_CLICK,0);
+ return 1;
+ }
+ return 0;
+}
+
+int do_posbar_active, do_posbar_clickx=14;
+
+static int do_posbar()
+{
+ int a,t;
+
+ if (mouse_type == -2)
+ {
+ if (do_posbar_active)
+ {
+ do_posbar_active=0;
+ return 1;
+ }
+ return 0;
+ }
+
+ if (!playing || !in_mod || !in_mod->is_seekable || PlayList_ishidden(PlayList_getPosition()))
+ {
+ if (mouse_type == -1 && do_posbar_active) do_posbar_active=0;
+ return 0;
+ }
+
+
+ if ((mouse_type == -1
+ || (mouse_type==0 && (mouse_stats&MK_SHIFT) && (mouse_stats&MK_LBUTTON))) && do_posbar_active)
+ {
+ if (mouse_type == -1)
+ do_posbar_active=0;
+ if (config_windowshade)
+ {
+ a = mouse_x - 228;
+ a *= (257-29-10);
+ a/=13;
+ }
+ else {
+ a = mouse_x - do_posbar_clickx - (10+7); // posbar_clickx is offset from start of bar
+ do_posbar_clickx = 14;
+ }
+
+ if (a < 0) a = 0;
+ if (a > 257-29-10) a = 257-29-10;
+ t = MulDiv(in_getlength(),1000 * a,(257-29-10));
+ if (in_seek(t) < 0) StopPlaying(0);
+ else
+ {
+ // ui_drawtime(in_getouttime()/1000,0);
+ }
+ if (mouse_type == -1)
+ {
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ return 1;
+ }
+ }
+ if (mouse_type == 1)
+ if ((inreg(11+7,58+15,256+7,66+15) && !config_windowshade) || (inreg(228,3,228+14,12) && config_windowshade) )
+ {
+ do_posbar_active=1;
+ if (!config_windowshade)
+ {
+ int curpos = 11 + 7 +
+ ((in_getouttime() * (257-10-29)) / in_getlength()) / 1000;
+ if (mouse_x <= curpos + 29 && mouse_x >= curpos-1) do_posbar_clickx = mouse_x - curpos;
+ else do_posbar_clickx = 14;
+ }
+ else do_posbar_clickx = 0;
+ }
+
+ if (do_posbar_active)
+ {
+ if (config_windowshade)
+ {
+ a = mouse_x - 228;
+ a *= (257-29-10);
+ a/=13;
+ }
+ else
+ {
+ a = mouse_x - do_posbar_clickx - (10+7);
+ }
+ if (a < 0) a = 0;
+ if (a > 257-29-10) a = 257-29-10;
+ t = MulDiv(in_getlength(),1000 * a,(257-29-10))/1000;
+ {
+ wchar_t buf[256] = {0}, seekStr[64] = {0};
+ int a=in_getlength();
+ if (in_mod && in_mod->is_seekable)
+ {
+ if (a) draw_positionbar((t*256) / a,1);
+ else draw_positionbar(0,1);
+ }
+ StringCchPrintfW(buf,256, L"%s: %02d:%02d/%02d:%02d (%d%%)",getStringW(IDS_SEEK_TO,seekStr,64),t/60,t%60,
+ a/60,a%60,(t*100)/(a?a:1)
+ );
+ if (config_windowshade) draw_time(t/60,t%60,0);
+ t=0;
+ draw_songname(buf,&t,-1);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void ui_drawtime(int time_elapsed, int mode)
+{
+ if (time_elapsed < 0) time_elapsed = 0;
+ if (!mode && paused)
+ {
+ static int i;
+ draw_time(time_elapsed/60,time_elapsed%60,i);
+ i ^= 1;
+ }
+ else
+ {
+ if (!do_posbar_active || !config_windowshade)
+ draw_time(time_elapsed/60,time_elapsed%60,0);
+ }
+ if (playing)
+ if (!do_posbar_active && in_mod && in_mod->is_seekable) {
+ if (in_getlength()) draw_positionbar((time_elapsed*256) / in_getlength(),mode);
+ else draw_positionbar(0,mode);
+ }
+}
+
+int do_volbar_clickx=4, do_volbar_active;
+
+static int do_volbar()
+{
+ if (mouse_type == -2)
+ {
+ if (do_volbar_active)
+ {
+ do_volbar_active=0;
+ draw_volumebar(config_volume,0);
+ return 1;
+ }
+ return 0;
+ }
+
+ if (mouse_type == -1 && do_volbar_active)
+ {
+ do_volbar_active=0;
+ do_volbar_clickx = 7;
+ draw_volumebar(config_volume,0);
+ in_setvol(config_volume);
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ return 1;
+ }
+
+ if (inreg(107,43+15,107+68,51+15) && mouse_type == 1)
+ {
+ int vs = 107 + (config_volume*51)/255;
+ if (mouse_x < vs+15 && mouse_x >= vs) do_volbar_clickx = mouse_x - vs;
+ else do_volbar_clickx = 7;
+ do_volbar_active=1;
+ }
+
+ if (do_volbar_active)
+ {
+ int v = mouse_x - do_volbar_clickx - (107);
+ // v = (v * 256) / (195-132-12);
+ v = (v*255)/51;
+ if (v < 0) v = 0;
+ if (v > 255) v = 255;
+ config_volume=v;
+ draw_volumebar(config_volume,1);
+ in_setvol(config_volume);
+ update_volume_text(-1);
+ return 1;
+ }
+ return 0;
+}
+
+
+int do_panbar_clickx=4, do_panbar_active;
+
+static int do_panbar()
+{
+ if (mouse_type == -2)
+ {
+ if (do_panbar_active)
+ {
+ draw_panbar(config_pan,0);
+ do_panbar_active=0;
+ return 1;
+ }
+ return 0;
+ }
+
+ if (mouse_type == -1 && do_panbar_active)
+ {
+ do_panbar_active=0;
+ do_panbar_clickx = 7;
+ if (config_pan < 27 && config_pan > -27) config_pan = 0;
+ draw_panbar(config_pan,0);
+ in_setpan(config_pan);
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ return 1;
+ }
+
+ if (inreg(177,43+15,177+38,51+15) && mouse_type == 1)
+ {
+ int vs = 177 + 12 + (config_pan*12)/127;
+ if (mouse_x < vs+15 && mouse_x >= vs) do_panbar_clickx = mouse_x - vs;
+ else do_panbar_clickx = 7;
+ do_panbar_active=1;
+ }
+
+ if (do_panbar_active)
+ {
+ int v = mouse_x - do_panbar_clickx - (177);
+ if (v < 0) v = 0;
+ if (v > 24) v = 24;
+ v-=12;
+ // changed in 5.64 to have a lower limit (~16% vs 24%) and for
+ // holding shift to drop the central clamp (allows 7% balance)
+ if (!(mouse_stats & MK_SHIFT)) if (v < 2 && v > -2) v = 0;
+ v *= 127;
+ v/=12;
+ config_pan = v;
+ draw_panbar(config_pan,1);
+ in_setpan(config_pan);
+ update_panning_text(-1);
+ return 1;
+ }
+ return 0;
+}
+
+
+int ui_songposition = 0;
+int ui_songposition_tts=10;
+int do_songname_clickx = -1;
+int do_songname_active = 0;
+
+void ui_doscrolling()
+{
+ if (!do_clutterbar_active && !ui_songposition_tts && !do_songname_active && !do_volbar_active && !do_panbar_active && !do_posbar_active)
+ {
+ ui_songposition+=5;
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ } else if (ui_songposition_tts) ui_songposition_tts--;
+ else ui_songposition_tts = 10;
+}
+
+static int do_songname()
+{
+ if (mouse_type == -2)
+ return 0;
+ if (mouse_stats & MK_LBUTTON || mouse_type == -1) if (do_songname_active || (inreg(117,24,266,35) && mouse_type == 1))
+ {
+ if (mouse_type == -1)
+ {
+ do_songname_clickx = -1;
+ do_songname_active=0;
+ ui_songposition_tts=10;
+ return 1;
+ }
+ if (do_songname_active)
+ {
+ ui_songposition -= mouse_x - do_songname_clickx;
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+ }
+ do_songname_clickx = mouse_x;
+ do_songname_active=1;
+ return 1;
+ }
+ return 0;
+}
+
+
+void ui_reset()
+{
+ title_buttons_active[0] = title_buttons_active[1] = title_buttons_active[2] = 0;
+ do_clutterbar_active=0;
+ do_songname_clickx = -1;
+ do_songname_active=0;
+ do_buttonbar_needupdate = 0;
+ do_shuffle_needupdate = 0;
+ do_eq_needupdate = do_pe_needupdate = 0;
+ do_repeat_needupdate = 0;
+ do_eject_needupdate = 0;
+ do_posbar_active = 0;
+ do_posbar_clickx = 14;
+ do_volbar_active = 0;
+ do_volbar_clickx = 7;
+ do_panbar_active = 0;
+ do_panbar_clickx = 7;
+ ui_songposition = 0;
+ ui_songposition_tts=0;
+}
+
+
+void ui_handlecursor(void)
+{
+ POINT p = {0};
+ static RECT b_normal[] =
+ {
+ {107,43+15,177+38,51+15},// vol & bal
+ {11+7,58+15,256+7,66+15},// pos
+ {254,3,262,12},//wshade
+ {244,3,253,12},//min
+ {264,3,272,12},//close
+ {5,3,17,13},//mainmenu
+ {0,0,275,13},// titelbar
+ {105,24,266,35},
+ }, b_windowshade[] =
+ {
+ {254,3,262,12},//wshade
+ {244,3,253,12},//min
+ {228,3,228+14,12}, // seeker
+ {264,3,272,12},//close
+ {5,3,17,13},//mainmenu
+ };
+
+ int x;
+
+ if (0 != (WS_DISABLED & GetWindowLongPtrW(hMainWindow, GWL_STYLE)))
+ x = (config_windowshade) ? 14 : 8;
+ else
+ {
+ int b_len;
+
+ RECT r;
+ GetCursorPos(&p);
+ GetWindowRect(hMainWindow,&r);
+ FixMainWindowRect(&r);
+ int mouse_x=p.x-r.left;
+ int mouse_y=p.y-r.top;
+ if (config_dsize) { mouse_x/=2; mouse_y/=2;}
+
+ RECT *b;
+ if (config_windowshade)
+ {
+ b=b_windowshade;
+ b_len = sizeof(b_windowshade)/sizeof(b_windowshade[0]);
+ }
+ else
+ {
+ b=b_normal;
+ b_len = sizeof(b_normal)/sizeof(b_normal[0]);
+ }
+ for (x = 0; x < b_len; x ++)
+ if (inreg(b[x].left,b[x].top,b[x].right,b[x].bottom)) break;
+
+ if (config_windowshade) x+=9;
+ }
+
+
+ if (Skin_Cursors[x]) SetCursor(Skin_Cursors[x]);
+ else SetCursor(LoadCursor(NULL,IDC_ARROW));
+}
+
+#include "../Plugins/General/gen_ml/menu.h"
+BOOL DoTrackPopup(HMENU hMenu, UINT fuFlags, int x, int y, HWND hwnd)
+{
+ if(hMenu == NULL)
+ {
+ return NULL;
+ }
+
+ HWND ml_wnd = (HWND)sendMlIpc(0, 0);
+ if (IsWindow(ml_wnd))
+ {
+ return Menu_TrackPopup(ml_wnd, hMenu, fuFlags, x, y, hwnd, NULL);
+ }
+ else
+ {
+ return TrackPopupMenu(hMenu, fuFlags, x, y, 0, hwnd, NULL);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/UnsignedAttribute.cpp b/Src/Winamp/UnsignedAttribute.cpp
new file mode 100644
index 00000000..e5fe5726
--- /dev/null
+++ b/Src/Winamp/UnsignedAttribute.cpp
@@ -0,0 +1,23 @@
+#include "main.h"
+#include "attributes.h"
+
+_unsigned::_unsigned()
+{
+ value = 0;
+}
+
+_unsigned::_unsigned(uintptr_t defaultValue)
+{
+ value = defaultValue;
+}
+
+uintptr_t _unsigned::operator =(uintptr_t uintValue)
+{
+ value = uintValue;
+ return value;
+}
+
+#define CBCLASS _unsigned
+START_DISPATCH;
+CB(IFC_CONFIGITEM_GETUNSIGNED, GetUnsigned)
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Winamp/UpdateWindow.cpp b/Src/Winamp/UpdateWindow.cpp
new file mode 100644
index 00000000..786c96ce
--- /dev/null
+++ b/Src/Winamp/UpdateWindow.cpp
@@ -0,0 +1,214 @@
+#include "Main.h"
+#include "Browser.h"
+#include "./api.h"
+
+#include "../nu/ns_wc.h"
+#include "menuv5.h"
+#include "ExternalCOM.h"
+#include "wa_dlg.h"
+
+#include "./updateService.h"
+
+UpdateBrowser *updateBrowser=0;
+static WNDPROC oldUpdateProc = 0;
+static BOOL fUnicode = FALSE;
+
+static void CALLBACK UpdateBrowser_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD elapsed)
+{
+ KillTimer(hwnd, eventId);
+
+ if (0 == (WS_VISIBLE & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ {
+ ShowWindow(hwnd, SW_SHOW);
+ }
+
+ embedWindowState *state = (embedWindowState*)(ULONG_PTR)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
+ if(NULL != state)
+ {
+ if (NULL != state->wasabi_window)
+ {
+ state->wasabi_window->activate();
+ return;
+ }
+ else if (NULL != g_dialog_box_parent)
+ {
+ SetTimer(hwnd, eventId, 200, UpdateBrowser_TimerProc);
+ return;
+ }
+ }
+
+ HWND hFrame = hwnd;
+ while (NULL != hFrame && 0 != (WS_CHILD & GetWindowLongPtrW(hFrame, GWL_STYLE)))
+ hFrame = GetAncestor(hFrame, GA_PARENT);
+
+ if (NULL != hFrame && (g_dialog_box_parent == hFrame || hMainWindow == hFrame))
+ hFrame = NULL;
+
+ if (NULL == hFrame) hFrame = hwnd;
+
+ SetWindowPos(hFrame, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ SetForegroundWindow(hFrame);
+
+}
+
+HRESULT UpdateWindow_Show(LPCSTR pszUrl)
+{
+ if (0 != _strnicmp(pszUrl, "http://client.winamp.com", 21))
+ return E_UNEXPECTED;
+
+
+ UpdateService *service;
+ if (SUCCEEDED(UpdateService::CreateInstance(pszUrl, &service)))
+ {
+ HRESULT hr = service->Show();
+ service->Release();
+ if (SUCCEEDED(hr))
+ return hr;
+ }
+
+ updateBrowser = new UpdateBrowser;
+ updateBrowser->CreateHWND();
+ updateBrowser->setVisible(TRUE);
+ updateBrowser->NavigateToName((LPCTSTR)pszUrl);
+ SetTimer(updateBrowser->m_hwnd, 1980, 1000, UpdateBrowser_TimerProc);
+
+ return S_OK;
+}
+
+static LRESULT WINAPI BrowserSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_PAINT:
+ {
+ HDC out = GetDC(hwnd);
+ RECT r;
+ GetClientRect(hwnd, &r);
+ r.left=11;
+ r.top=20;
+ r.right-=8;
+ r.bottom-=14;
+
+ HBRUSH b = CreateSolidBrush(WADlg_getColor(WADLG_WNDBG));
+ FillRect(out, &r, b);
+ DeleteObject(b);
+ ValidateRect(hwnd, &r);
+ }
+ break;
+
+ case WM_USER+0x102:
+ {
+ if (wParam == 1)
+ {
+ ShowWindow(updateBrowser->m_hwnd, SW_SHOW);
+ }
+ else
+ {
+ ShowWindow(updateBrowser->m_hwnd, SW_HIDE);
+ }
+ }
+ break;
+ case WM_USER + 101:
+ {
+ //updateBrowser->setVisible(FALSE);
+ ShowWindow(hwnd, SW_HIDE);
+ ShowWindow(updateBrowser->m_hwnd, SW_HIDE);
+ return 0;
+ }
+ break;
+
+ case WM_NCDESTROY:
+ case WM_DESTROY:
+ updateBrowser->m_hwnd = 0;
+ return 0;
+ break;
+
+ }
+
+
+ if (oldUpdateProc)
+ return (fUnicode) ? CallWindowProcW(oldUpdateProc, hwnd, msg, wParam, lParam) : CallWindowProcA(oldUpdateProc, hwnd, msg, wParam, lParam);
+ else
+ return (fUnicode) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam);
+
+}
+
+HWND UpdateBrowser::CreateHWND()
+{
+ if (!m_hwnd)
+ {
+ state.flags = EMBED_FLAGS_NOWINDOWMENU;
+ state.me = 0;
+ state.r.left = config_wx;
+ state.r.right = config_wx+300;
+ state.r.top = config_wy;
+ state.r.bottom = config_wy+200;
+
+ HWND owner = (HWND) SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM) & state, IPC_GET_EMBEDIF);
+
+ m_hwnd = owner;
+ setLocation(11,20, 300-19, 200-34);
+ fUnicode = IsWindowUnicode(owner);
+ oldUpdateProc = (WNDPROC) ((fUnicode) ? SetWindowLongPtrW(owner, GWLP_WNDPROC, (LONG_PTR)BrowserSubclassProc) :
+ SetWindowLongPtrA(owner, GWLP_WNDPROC, (LONG_PTR)BrowserSubclassProc));
+ SetWindowTextW(owner, getStringW(IDS_WINAMP_UPDATE, NULL, 0));
+ }
+
+ return m_hwnd;
+}
+
+// ---------------------------------------------------------------
+void UpdateBrowser::NavigateToName(LPCTSTR pszUrl)
+{
+ if (!m_pweb) return ;
+ DWORD dwChars = lstrlen (pszUrl) + 1;
+ LPWSTR pwszUrl = (LPWSTR)LocalAlloc (LPTR, dwChars * sizeof (WCHAR));
+ long moptions = navNoReadFromCache | navNoWriteToCache | navNoHistory;
+ VARIANT options;
+ memset( (void*)&options, 0, sizeof(VARIANT));
+ V_VT(&options) = VT_I4;
+ V_I4(&options) = moptions;
+ if (pwszUrl)
+ {
+ MultiByteToWideCharSZ(CP_ACP, 0, (LPCSTR)pszUrl, -1, pwszUrl, dwChars);
+ m_pweb->Navigate (pwszUrl, &options , 0, 0, 0);
+ LocalFree (pwszUrl);
+ }
+}
+
+
+#define VIDEO_GENFF_SIZEREQUEST (WM_USER+2048)
+void UpdateBrowser::Resized(unsigned long width, unsigned long height)
+{
+ updateBrowser->setLocation(11,20, width, height);
+
+ if (GetParent(m_hwnd))
+ SendMessageW(GetParent(m_hwnd), VIDEO_GENFF_SIZEREQUEST, width, height);
+ else
+ SetWindowPos(m_hwnd, 0, 0, 0, width + 19, height + 34, SWP_NOMOVE|SWP_ASYNCWINDOWPOS);
+
+ InvalidateRect(m_hwnd, NULL, TRUE);
+
+}
+
+HRESULT UpdateBrowser::GetExternal(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
+{
+ if (NULL == ppDispatch)
+ return E_POINTER;
+
+ ExternalCOM *external;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (FAILED(hr)) external = NULL;
+
+ *ppDispatch = (IDispatch*) external;
+ return S_OK;
+}
+
+
+void UpdateBrowser::OnNavigateComplete()
+{
+ setVisible(TRUE);
+ RECT r;
+ GetClientRect(m_hwnd, &r);
+ setLocation(11,20, r.right-19, r.bottom-34);
+} \ No newline at end of file
diff --git a/Src/Winamp/VIS.H b/Src/Winamp/VIS.H
new file mode 100644
index 00000000..779e9d8e
--- /dev/null
+++ b/Src/Winamp/VIS.H
@@ -0,0 +1,96 @@
+#ifndef NULLSOFT_VISH
+#define NULLSOFT_VISH
+// Visualization plugin interface
+
+typedef struct winampVisModule
+{
+ char *description; // description of module
+ HWND hwndParent; // parent window (filled in by calling app)
+ HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app)
+ int sRate; // sample rate (filled in by calling app)
+ int nCh; // number of channels (filled in...)
+ int latencyMs; // latency from call of RenderFrame to actual drawing
+ // (calling app looks at this value when getting data)
+ int delayMs; // delay between calls in ms
+
+ // the data is filled in according to the respective Nch entry
+ int spectrumNch;
+ int waveformNch;
+ unsigned char spectrumData[2][576];
+ unsigned char waveformData[2][576];
+
+ void (__cdecl *Config)(struct winampVisModule *this_mod); // configuration dialog
+ int (__cdecl *Init)(struct winampVisModule *this_mod); // 0 on success, creates window, etc
+ int (__cdecl *Render)(struct winampVisModule *this_mod); // returns 0 if successful, 1 if vis should end
+ void (__cdecl *Quit)(struct winampVisModule *this_mod); // call when done
+
+ void *userData; // user data, optional
+} winampVisModule;
+
+typedef struct
+{
+ int version; // VID_HDRVER
+ char *description; // description of library
+ winampVisModule* (__cdecl *getModule)(int);
+} winampVisHeader;
+
+// exported symbols
+#ifdef USE_VIS_HDR_HWND
+typedef winampVisHeader* (__cdecl *winampVisGetHeaderType)(HWND);
+
+// version of current module (0x102 == 1.02)
+#define VIS_HDRVER 0x102
+
+#else
+typedef winampVisHeader* (__cdecl *winampVisGetHeaderType)();
+
+// version of current module (0x101 == 1.01)
+#define VIS_HDRVER 0x101
+
+#endif
+
+// Version note:
+//
+// Updated to 1.02 for 5.36+
+// Added passing of Winamp's main hwnd in the call to the exported winampVisGetHeader()
+// which allows for primarily the use of localisation features with the bundled plugins.
+// If you want to use the new version then either you can edit you version of vis.h or
+// you can add USE_VIS_HRD_HWND to your project's defined list or before use of vis.h
+//
+
+// Miscellaneous notes:
+// * Any window that remains in foreground should optimally pass keystrokes to the parent
+// (Winamp's) window, so that the user can still control it unless escape is pressed or
+// some option key specific to the visualization is pressed.
+// * Storing configuration can be done any where though it's recommended to use the api
+// IPC_GETINIDIRECTORY as the basis of the path to save things to e.g. INIDIR\plugins\plugin.ini
+// * ints are 32 bits and structure members are aligned on the default 8 byte boundaries.
+
+// These are the return values to be used with the uninstall plugin export function:
+// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
+// which determines if Winamp can uninstall the plugin immediately or on winamp restart.
+// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
+// Note: visualization plugins are always uninstalled without a reboot (unlike other plugin types).
+//
+#define VIS_PLUGIN_UNINSTALL_NOW 0x0
+//
+// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
+// that it is down to you to ensure that if uninstall now is returned that it will not
+// cause a crash i.e. don't use if you've been subclassing the main window.
+//
+// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
+//
+
+// For a vis plugin to be correctly detected by Winamp you need to ensure that
+// the exported winampVisGetHeader(..) is exported as an undecorated function
+// e.g.
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+// __declspec(dllexport) winampVisHeader * __cdecl winampVisGetHeader(){ return &plugin; }
+// #ifdef __cplusplus
+// }
+// #endif
+//
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/VIS.cpp b/Src/Winamp/VIS.cpp
new file mode 100644
index 00000000..27075d31
--- /dev/null
+++ b/Src/Winamp/VIS.cpp
@@ -0,0 +1,839 @@
+#include <windowsx.h>
+
+#include "Main.h"
+#include "vis.h"
+#include "fft.h"
+#include <bfc/platform/types.h>
+#include <math.h>
+#include <assert.h>
+#include "./api.h"
+#include "../nsutil/window.h"
+#include "../nu/threadname.h"
+
+static winampVisModule *vis_mod;
+static DWORD WINAPI vis_thread(void *tmp);
+static HANDLE hThread;
+static DWORD visThreadId=0;
+static volatile int killThread;
+static int _nch = 2, _numframes=1;
+int _srate = 44100;
+static wchar_t _visplugin_name[512];
+static int _visplugin_num;
+static char *vsa_data;
+static int vsa_position, vsa_entrysize=577*4;
+static int vsa_length,size=576*4;
+static int vis_stopping;
+static CRITICAL_SECTION cs;
+static HWND external_window = NULL;
+static HWND external_window_host = NULL;
+
+#ifdef _M_IX86
+__inline static int lrint(float flt)
+{
+ int intgr;
+
+ _asm
+ {
+ fld flt
+ fistp intgr
+ }
+
+ return intgr;
+}
+#else
+__inline static int lrint(float flt)
+{
+ return (int)flt;
+}
+#endif
+
+// quantizes to 23 bits - use appropriately
+#define FASTMIN(x,b) { x = b - x; x += (float)fabs(x); x *= 0.5f; x = b - x; }
+
+static size_t vis_refCount=0;
+static winampVisModule *GetVis()
+{
+ winampVisModule *ret = 0;
+ EnterCriticalSection(&cs);
+ if (vis_stopping)
+ {
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+ if (vis_mod)
+ {
+ ret = vis_mod;
+ vis_refCount++;
+ }
+ LeaveCriticalSection(&cs);
+ return ret;
+}
+
+static void DestroyVis()
+{
+ killThread=1;
+ vis_stopping=1;
+
+ if (GetCurrentThreadId() != visThreadId)
+ {
+ HANDLE thisThread = hThread;
+ LeaveCriticalSection(&cs);
+
+ // run message pump. this shouldn't last long.
+ int x=200;
+ while (WaitForSingleObject(thisThread,10) == WAIT_TIMEOUT && x-- > 0)
+ {
+ WASABI_API_APP->app_messageLoopStep();
+ }
+ WaitForSingleObject(thisThread,INFINITE);
+ EnterCriticalSection(&cs);
+ }
+
+ CloseHandle(hThread);
+ if (vis_mod)
+ FreeLibrary(vis_mod->hDllInstance);
+ vis_stopping=0;
+ vis_mod=0;
+
+ hThread=0;
+ killThread=0;
+}
+
+static void ReleaseVis(winampVisModule *vis)
+{
+ if (vis)
+ {
+ EnterCriticalSection(&cs);
+ vis_refCount--;
+ if (vis_refCount == 0)
+ {
+ DestroyVis();
+ }
+
+ LeaveCriticalSection(&cs);
+ }
+}
+
+void vis_init(void)
+{
+ InitializeCriticalSectionAndSpinCount(&cs, 4000);
+}
+
+static char *vsa_get(int timestamp);
+static void vsa_setdatasize();
+
+int vis_running()
+{
+ int running=0;
+ winampVisModule *vis = GetVis();
+ if (vis)
+ {
+ running = !vis_stopping;
+ ReleaseVis(vis);
+ }
+ return running;
+}
+
+static int priorities[5] =
+{
+ THREAD_PRIORITY_LOWEST,
+ THREAD_PRIORITY_BELOW_NORMAL,
+ THREAD_PRIORITY_NORMAL,
+ THREAD_PRIORITY_ABOVE_NORMAL,
+ THREAD_PRIORITY_HIGHEST
+};
+
+void vis_start(HWND hwnd, wchar_t *fn)
+{
+ if (vis_stopping || g_safeMode) return;
+ vis_stop();
+ vsa_deinit();
+ if (!config_visplugin_name[0]) return;
+
+ killThread=0;
+ if (!fn || !*fn)
+ {
+ PathCombineW(_visplugin_name, VISDIR, config_visplugin_name);
+ _visplugin_num=config_visplugin_num;
+ }
+ else
+ {
+ wchar_t buf[MAX_PATH] = {0};
+ wchar_t *p;
+ StringCchCopyW(buf,MAX_PATH,fn);
+ p=wcsstr(buf,L",");
+ if (p)
+ {
+ *p++=0;
+ _visplugin_num=_wtoi(p);
+ }
+ else _visplugin_num=0;
+ if (PathIsFileSpecW(buf) || PathIsRelativeW(buf))
+ PathCombineW(_visplugin_name, VISDIR, buf);
+ else
+ StringCchCopyW(_visplugin_name,512,buf);
+ }
+ hThread = (HANDLE) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) vis_thread,NULL,0,&visThreadId);
+ SetThreadPriority(hThread,priorities[config_visplugin_priority]);
+}
+
+void vis_setprio()
+{
+ if (vis_stopping) return;
+ if (hThread) SetThreadPriority(hThread,priorities[config_visplugin_priority]);
+}
+
+void vis_stop()
+{
+ if (vis_stopping||!hThread) return;
+ EnterCriticalSection(&cs); // go into critical section so vis_mod doesn't suddenly appear out of nowhere
+ winampVisModule *thisVis = vis_mod;
+ LeaveCriticalSection(&cs);
+ ReleaseVis(thisVis);
+}
+
+void vis_setinfo(int srate, int nch)
+{
+ if (srate > 0) _srate = srate;
+ if (nch > 0) _nch = nch;
+ if (!vis_running()) return;
+ EnterCriticalSection(&cs);
+ winampVisModule *vis = GetVis();
+ if (vis)
+ {
+ vis->sRate = _srate;
+ vis->nCh = _nch;
+ ReleaseVis(vis);
+ }
+ LeaveCriticalSection(&cs);
+}
+
+void vis_setextwindow(HWND hwnd)
+{
+ HWND test_window;
+ unsigned int test_window_style_ex;
+ unsigned long window_thread_id;
+
+ EnterCriticalSection(&cs);
+
+ external_window = hwnd;
+ external_window_host = external_window;
+
+ window_thread_id = GetWindowThreadProcessId(external_window, NULL);
+ while(NULL != external_window_host)
+ {
+ test_window = GetAncestor(external_window_host, GA_PARENT);
+ if (NULL != test_window &&
+ window_thread_id == GetWindowThreadProcessId(test_window, NULL))
+ {
+ test_window_style_ex = (unsigned int)GetWindowLongPtrW(test_window, GWL_STYLE);
+ if (0 != (WS_EX_CONTROLPARENT & test_window_style_ex))
+ {
+ external_window_host = test_window;
+ continue;
+ }
+ }
+ break;
+ }
+
+ LeaveCriticalSection(&cs);
+}
+
+static winampVisModule *CreateVis(HINSTANCE visLib)
+{
+ EnterCriticalSection(&cs);
+ winampVisModule *ret = 0;
+ ret = GetVis();
+ if (ret)
+ {
+ LeaveCriticalSection(&cs);
+ return ret;
+ }
+
+ winampVisGetHeaderType pr;
+ pr = (winampVisGetHeaderType) GetProcAddress(visLib,"winampVisGetHeader");
+ if (!pr)
+ {
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+
+ winampVisHeader* pv = pr(hMainWindow);
+ if (!pv)
+ {
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+
+ vis_mod = pv->getModule(_visplugin_num);
+ if (!vis_mod)
+ {
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+
+ vis_mod->sRate = _srate;
+ vis_mod->nCh = _nch;
+ vis_mod->hwndParent = hMainWindow;
+ vis_mod->hDllInstance = visLib;
+
+ vis_refCount++;
+ LeaveCriticalSection(&cs);
+ return vis_mod;
+}
+
+static BOOL vis_process_message(MSG *msg)
+{
+ if (msg->message >= WM_KEYFIRST && msg->message <= WM_KEYLAST &&
+ msg->hwnd == external_window &&
+ NULL != external_window)
+ {
+ return FALSE;
+ }
+
+ if (WM_MOUSEWHEEL == msg->message &&
+ NULL != external_window_host)
+ {
+ POINT cursor;
+ HWND target_window;
+
+ POINTSTOPOINT(cursor, msg->lParam);
+ target_window = WindowFromPoint(cursor);
+
+ if (NULL != target_window &&
+ FALSE == IsChild(external_window_host, target_window ) &&
+ GetWindowThreadProcessId(target_window, NULL) != GetWindowThreadProcessId(external_window_host, NULL))
+ {
+ PostMessageW(hMainWindow, msg->message, msg->wParam, msg->lParam);
+ return TRUE;
+ }
+
+ }
+
+ if (NULL != external_window_host)
+ return IsDialogMessageW(external_window_host, msg);
+
+ return FALSE;
+}
+
+static DWORD WINAPI vis_thread(void *tmp)
+{
+ winampVisModule *vis = 0;
+ MSG Msg;
+ HINSTANCE hLib=0;
+ int t=0;
+ SetThreadName((DWORD)-1, "Vis (plugin) thread");
+ hLib = LoadLibrary(_visplugin_name);
+ if (!hLib)
+ {
+ t=1;
+ }
+ else
+ {
+ vis = CreateVis(hLib);
+ if (!vis)
+ {
+ FreeLibrary(hLib);
+ hLib = 0;
+ t=1;
+ }
+ }
+
+ if (!t)
+ {
+ if (!(config_no_visseh&1))
+ {
+ __try
+ {
+ t = (vis ? vis->Init(vis) : 1);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ t=1;
+ char errstr[512] = {0};
+ char caption[512] = {0};
+ getString(IDS_PLUGINERROR,errstr,512);
+ StringCchCatA(errstr, 512, " (1)");
+ MessageBoxA(NULL,errstr,getString(IDS_ERROR,caption,512),MB_OK|MB_ICONEXCLAMATION);
+ }
+ }
+ else
+ {
+ t = vis->Init(vis);
+ }
+ }
+
+ if (!t)
+ {
+ if (config_disvis) sa_setthread(0);
+ vsa_setdatasize();
+
+ while (!killThread)
+ {
+ if (PeekMessage(&Msg,NULL,0,0,PM_REMOVE))
+ {
+ if (Msg.message == WM_QUIT)
+ break;
+
+ if (FALSE == vis_process_message(&Msg))
+ {
+ TranslateMessage(&Msg);
+ DispatchMessage(&Msg);
+ }
+ }
+ else if (!paused)
+ {
+ static int upd;
+ int p=playing;
+ char *data=0;
+ if (in_mod && p) data = vsa_get(in_mod->GetOutputTime()+vis->latencyMs);
+ if (data)
+ {
+ int l=vis->spectrumNch;
+ for (int n = 0; n < l; n ++)
+ {
+ memcpy(vis->spectrumData[n],data,576);
+ data += 576;
+ }
+ l=vis->waveformNch;
+ for (int n = 0; n < l; n ++)
+ {
+ memcpy(vis->waveformData[n],data,576);
+ data += 576;
+ }
+ }
+ if (!data)
+ {
+ memset(vis->spectrumData,0,576*2);
+ memset(vis->waveformData,0,576*2);
+ }
+ if (p) upd=1;
+ if (upd)
+ if (!(config_no_visseh&1))
+ {
+ __try
+ {
+ if (vis->Render(vis))
+ {
+ break;
+ }
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ char errstr[512] = {0};
+ char caption[512] = {0};
+ getString(IDS_PLUGINERROR,errstr,512);
+ StringCchCatA(errstr, 512, " (2)");
+ MessageBoxA(NULL,errstr,getString(IDS_ERROR,caption,512),MB_OK|MB_ICONEXCLAMATION);
+ break;
+ }
+ }
+ else
+ {
+ if (vis->Render(vis))
+ {
+ break;
+ }
+ }
+ if (!p) upd=0;
+ Sleep(vis->delayMs);
+ }
+ else Sleep(min(1,vis->delayMs));
+ }
+ vsa_deinit();
+ sa_setthread(config_sa);
+ if (!(config_no_visseh&1))
+ {
+ __try
+ {
+ vis->Quit(vis);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ wchar_t errstr[512] = {0};
+ wchar_t caption[512] = {0};
+ getStringW(IDS_PLUGINERROR,errstr,512);
+ StringCchCatW(errstr, 512, L" (3)");
+ MessageBoxW(NULL,errstr,getStringW(IDS_ERROR,caption,512),MB_OK|MB_ICONEXCLAMATION);
+ }
+ }
+ else
+ {
+ vis->Quit(vis);
+ }
+ EnterCriticalSection(&cs);
+ if (killThread)
+ {
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+ else
+ {
+ ReleaseVis(vis);
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+ }
+
+ ReleaseVis(vis);
+ if (hLib)
+ FreeLibrary(hLib);
+ hLib = 0;
+ return 0;
+}
+
+static int last_pos;
+
+static void _vsa_init()
+{
+ vsa_deinit();
+ if (_numframes < 1) _numframes=1;
+ vsa_entrysize = 4+size;
+ vsa_data = (char *) GlobalAlloc(GPTR,vsa_entrysize * _numframes);
+ vsa_position=0;
+ vsa_length = _numframes;
+}
+
+void vsa_init(int numframes)
+{
+ EnterCriticalSection(&cs);
+ if (vis_running())
+ {
+ last_pos=0;
+ _numframes=numframes;
+ _vsa_init();
+ }
+ else
+ {
+ last_pos=0;
+ _numframes=numframes;
+ }
+ LeaveCriticalSection(&cs);
+}
+
+static void vsa_setdatasize()
+{
+ EnterCriticalSection(&cs);
+ winampVisModule *vis = GetVis();
+ if (vis)
+ {
+ size=576*(vis->waveformNch+vis->spectrumNch);
+ _vsa_init();
+ ReleaseVis(vis);
+ }
+
+ LeaveCriticalSection(&cs);
+}
+
+int vsa_add(void *data, int timestamp)
+{
+ if (!vsa_data) return 1;
+ EnterCriticalSection(&cs);
+ if (vsa_data) // check again, it might have gone away while we were waiting on the CS
+ {
+ if (vsa_length < 2)
+ {
+ vsa_position = 0;
+ }
+ char *c = vsa_data + vsa_position*vsa_entrysize;
+ *(int32_t *)c=timestamp;
+
+ memcpy(c+4,data,vsa_entrysize-4);
+ if (++vsa_position >= vsa_length) vsa_position -= vsa_length;
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+ else
+ {
+ LeaveCriticalSection(&cs);
+ return 1;
+ }
+}
+
+void vsa_deinit(void)
+{
+ EnterCriticalSection(&cs);
+ if (vsa_data)
+ {
+ GlobalFree(vsa_data);
+ vsa_data=0;
+ vsa_length=0;
+ }
+ LeaveCriticalSection(&cs);
+}
+
+static char *vsa_get(int timestamp)
+{
+ int i,x, closest=1000000, closest_v = -1;
+ if (!vsa_data) return NULL;
+ if (vsa_length<2)
+ {
+ return vsa_data+4;
+ }
+ EnterCriticalSection(&cs);
+ x=last_pos;
+ if (x >= vsa_length) x=0;
+ for (i = 0; i < vsa_length; i ++)
+ {
+ int *q = (int *)(vsa_data+x*vsa_entrysize);
+ int d = timestamp-*q;
+ if (++x == vsa_length) x=0;
+ if (d < 0) d = -d;
+ if (d < closest)
+ {
+ closest = d;
+ closest_v = x;
+ }
+ else if (closest<200) break;
+ }
+ if (closest_v >= 0)
+ {
+ static char data[576*4];
+ last_pos=closest_v;
+ memcpy(data,vsa_data+vsa_entrysize*closest_v+4,vsa_entrysize-4);
+ LeaveCriticalSection(&cs);
+ return data;
+ }
+ else
+ {
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+}
+
+int vsa_getmode(int *sp, int *wa)
+{
+ int rv=0;
+ winampVisModule *vis = GetVis();
+ if (vis)
+ {
+ EnterCriticalSection(&cs);
+ *sp=vis->spectrumNch;
+ *wa=vis->waveformNch;
+ rv=1;
+
+ LeaveCriticalSection(&cs);
+ ReleaseVis(vis);
+ }
+ else *sp=*wa=0;
+ return rv;
+}
+
+void FillRealSamples_8Bit(unsigned char *data, const int stride, const int channels, float *samples, const float divider)
+{
+ int frame,c;
+ const float p = (float)channels*divider;
+
+ for (frame = 0; frame <512; frame ++)
+ {
+ //done by memset - samples[x*2]=0;
+ for (c=0;c<channels;c++)
+ {
+ samples[frame] += (float)(*data - 128);
+ data+=stride; // jump to the next sample (channels are interleaved)
+ }
+
+ samples[frame] /= p;
+ //done by memset - wavetrum[x*2+1] = 0.0f;
+ }
+ nsutil_window_Hann_F32_IP(samples, 512);
+}
+
+#define SA_DC_FILTER
+void FillRealSamples(char *ptr, const int stride, const int channels, float *samples, const float divider)
+{
+#ifdef SA_DC_FILTER
+ float x1=0, y1=0;
+#endif
+ int frame, c;
+ const float p=(float)channels * divider;
+
+ // we're calculating using only the most significant byte,
+ // because we only end up with 6 bit data anyway
+ // if you want full resolution, check out CVS tag BETA_2005_1122_182830, file: vis.c
+
+ for (frame = 0;frame <512;frame++)
+ {
+ //done by memset - wavetrum[x*2]=0;
+ float x=0;
+ for (c=0;c<channels;c++)
+ {
+ x += (float)(*ptr);
+ ptr+=stride; // jump to the next sample (channels are interleaved)
+ }
+#ifdef SA_DC_FILTER
+ float y = x - x1 + 0.99f * y1;
+ y1=y;
+ x1=x;
+#else
+ float y=x;
+#endif
+ y/=p;
+
+ samples[frame]=y;
+ //done by memset - wavetrum[x*2+1] = 0.0f;
+ }
+ nsutil_window_Hann_F32_IP(samples, 512);
+}
+
+void vsa_addpcmdata(void *_data_buf, int numChannels, int numBits, int ts)
+{
+ char *data_buf = reinterpret_cast<char *>(_data_buf);
+ // begin vis plugin stuff
+ winampVisModule *vis = GetVis();
+ if (vis)
+ {
+ __declspec(align(32)) float wavetrum[512];
+ extern int vsa_add(void *data, int timestamp);
+ char data[576*4*2] = {0};
+ int data_offs=0;
+ int y,x,spectrumChannels, waveformChannels, stride;
+
+ spectrumChannels=min(numChannels,vis->spectrumNch);
+ stride=numBits/8;
+
+ for (y = 0; y < spectrumChannels; y ++)
+ {
+ if (spectrumChannels == 1) // downmix to mono, if necessary
+ {
+ if (numBits == 8)
+ FillRealSamples_8Bit((unsigned char*)data_buf, 1, numChannels, wavetrum, 1.f);
+ else
+ {
+ const int stride=numBits/8; // number of bytes between samples
+ char *ptr = data_buf+y*stride+stride-1; // offset for little endian
+ FillRealSamples(ptr, stride, numChannels, wavetrum, 1.f);
+ }
+ }
+ else // TODO: deal with 'downmixing' to stereo if channels>2
+ {
+ if (numBits == 8)
+ FillRealSamples_8Bit((unsigned char*)data_buf, numChannels, 1, wavetrum, 1.f);
+ else
+ {
+ const int stride=numBits/8; // number of bytes between samples
+ char *ptr = data_buf+y*stride+stride-1; // offset for little endian
+ FillRealSamples(ptr, stride*numChannels, 1, wavetrum, 1.f);
+ }
+ }
+ fft_9(wavetrum);
+ {
+ float la=0;
+ int thisBand=0;
+
+ for (x = 0; x < 256; x ++)
+ {
+ float sinT = wavetrum[x*2];
+ float cosT = wavetrum[x*2+1];
+
+ float thisValue=(float)sqrt(sinT*sinT+cosT*cosT)/16.0f;
+ thisBand++;
+
+ FASTMIN(thisValue, 255.f);
+ data[data_offs++] = lrint((thisValue + la)/2.f);
+ //data[data_offs++] = lrint((thisValue + thisValue + la)/3.f);
+ data[data_offs++] = lrint(thisValue);
+ la=thisValue;
+ }
+ while ((data_offs % 576)!=0)
+ {
+ la/=2;
+ data[data_offs++]=lrint(la);
+ }
+
+ assert((data_offs % 576)==0);
+ }
+ }
+
+ if (numChannels == 1 && vis->spectrumNch == 2) // upmix, if necessary
+ {
+ memcpy(data+data_offs,data+data_offs-576,576);
+ data_offs+=576;
+ }
+
+ waveformChannels=min(numChannels,vis->waveformNch);
+ if (waveformChannels == 1) // downmix to mono, if necessary
+ {
+ char *ptr = data_buf+stride-1; // offset for little endian
+ for (x=0;x<576;x++)
+ {
+ __int32 mix=0;
+ for (int channel=0;channel<numChannels;channel++)
+ {
+ mix += (*ptr);
+ ptr+=stride; // jump to the next sample (channels are interleaved)
+ }
+ data[data_offs++] = (char)(mix / numChannels);
+ }
+ }
+ else // TODO: deal with 'downmixing' to stereo if numChannels>2
+ {
+ for (y = 0; y < waveformChannels; y++)
+ {
+ char *ptr = data_buf+y*stride+stride-1; // offset for little endian
+ for (x=0;x<576;x++)
+ {
+ data[data_offs++] = *ptr;
+ ptr+=stride*numChannels;
+ }
+ }
+ }
+
+ if (numChannels == 1 && vis->waveformNch == 2)
+ {
+ memcpy(data+data_offs,data+data_offs-576,576);
+ //data_offs+=576;
+ }
+ vsa_add(data,ts);
+ ReleaseVis(vis);
+ }
+}
+
+HWND hVisWindow, hPLVisWindow;
+
+LRESULT CALLBACK VIS_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ {
+ RECT r1, r2;
+ int xPos = GET_X_LPARAM(lParam); // horizontal position of cursor
+ int yPos = GET_Y_LPARAM(lParam);
+ if (hwnd == hVisWindow)
+ {
+ GetWindowRect(hMainWindow,&r1);
+ }
+ else GetWindowRect(hPLWindow,&r1);
+ GetWindowRect(hwnd,&r2);
+ xPos += r2.left-r1.left;
+ yPos += r2.top-r1.top;
+ lParam = MAKELPARAM(xPos,yPos);
+ SendMessageW(hwnd == hVisWindow?hMainWindow:hPLWindow,message,wParam,lParam);
+ return 0;
+ }
+ case WM_USER+0xebe:
+ case WM_DROPFILES:
+ return SendMessageW(GetParent(hwnd),message,wParam,lParam);
+ case WM_CREATE:
+ if (NULL != WASABI_API_APP)
+ WASABI_API_APP->app_registerGlobalWindow(hwnd);
+ break;
+ case WM_DESTROY:
+ if (NULL != WASABI_API_APP)
+ WASABI_API_APP->app_unregisterGlobalWindow(hwnd);
+ break;
+ }
+
+ if (FALSE != IsDirectMouseWheelMessage(message))
+ {
+ SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+
+ return DefWindowProcW(hwnd,message,wParam,lParam);
+} \ No newline at end of file
diff --git a/Src/Winamp/VersionCheck.cpp b/Src/Winamp/VersionCheck.cpp
new file mode 100644
index 00000000..38e78cd8
--- /dev/null
+++ b/Src/Winamp/VersionCheck.cpp
@@ -0,0 +1,313 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author: Ben Allison benski@nullsoft.com
+** Created:
+**/
+
+#include "Main.h"
+#include "resource.h"
+#include "api.h"
+#include "language.h"
+
+#include "..\Components\wac_network\wac_network_http_receiver_api.h"
+
+#include "api/service/waServiceFactory.h"
+#include "Browser.h"
+#include "../nu/AutoUrl.h"
+#include "../nu/threadname.h"
+#include "stats.h"
+#include "../nu/threadpool/TimerHandle.hpp"
+
+#include "../WAT/WAT.h"
+
+extern UpdateBrowser *updateBrowser;
+
+class VersionCheckCallback : public ifc_downloadManagerCallback
+{
+public:
+ void OnInit(DownloadToken token)
+ {
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (http)
+ {
+ http->AllowCompression();
+ http->addheader("Accept: */*");
+ }
+ }
+
+ int IsCharDigit(char digit)
+ {
+ WORD type=0;
+ GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return type&C1_DIGIT;
+ }
+
+ void OnFinish(DownloadToken token)
+ {
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (http && http->getreplycode() == 200)
+ {
+ char *buf;
+ size_t size;
+ if (WAC_API_DOWNLOADMANAGER->GetBuffer(token, (void **)&buf, &size) == 0)
+ {
+ // buf[size] = 0;
+ char *p = buf;
+
+ while (size && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n'))
+ {
+ p++;
+ size--;
+ }
+
+ char newVer[6] = {0,};
+ if (size >= 3 && p[1] == '.')
+ {
+ size_t i = 0;
+ while (size && i != 6 && (i == 1 || IsCharDigit(p[i])))
+ {
+ newVer[i] = p[i];
+ newVer[i + 1] = 0;
+ size--;
+ i++;
+ }
+ p += i;
+ while (size && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n'))
+ {
+ size--;
+ p++;
+ }
+
+ char curVer_tmp[ 6 ] = APP_VERSION;
+ char curVer[ 6 ] = { 0 };
+
+ i = 0;
+ size_t j = 0;
+ bool l_has_point = false;
+ while ( i != 6 && j != 6 )
+ {
+ if ( IsCharDigit( curVer_tmp[ j ] ) )
+ {
+ curVer[ i ] = curVer_tmp[ j ];
+ i++;
+ }
+
+ j++;
+
+ if ( !IsCharDigit( curVer_tmp[ j ] ) && !l_has_point )
+ {
+ curVer[ i ] = curVer_tmp[ j ];
+ l_has_point = true;
+
+ i++;
+ j++;
+ }
+ }
+
+ while (lstrlenA(curVer) < 5)
+ StringCchCatA(curVer, 6, "0");
+ while (lstrlenA(newVer) < 5)
+ StringCchCatA(newVer, 6, "0");
+
+ int verDif = strcmp(newVer, curVer);
+ //#if defined(BETA) || defined(NIGHTLY)
+ // if (verDif == 0)
+ // verDif = 1; // if this is a BETA version, then we should upgrade if the versions are equal
+ //#endif
+
+ if (verDif == 0) // same version
+ {
+ char updateNumber[32] = "";
+ char *u = updateNumber;
+ while (size && u != (updateNumber + 31) && *p && *p != '\r' && *p != '\n')
+ {
+ size--;
+ *u++ = *p++;
+ *u = 0;
+ }
+ int update = atoi(updateNumber);
+ if (update > config_newverchk3)
+ {
+ if (config_newverchk3) // only display update if we've already established a serial #
+ verDif = 1;
+ config_newverchk3 = update;
+ }
+ }
+ if (verDif > 0) // same version or older
+ {
+ while (size && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n'))
+ {
+ size--;
+ p++;
+ }
+ if (size)
+ {
+ char *disp = (char *)calloc(size + 1, sizeof(char));
+ memcpy(disp, p, size);
+ disp[size]=0;
+ if (!_strnicmp(p, "http://", 7))
+ {
+ PostMessageW(hMainWindow, WM_WA_IPC, (WPARAM)disp, IPC_UPDATE_URL);
+ }
+ else
+ {
+ if (MessageBoxA(NULL, disp, getString(IDS_WINAMP_UPDATE_MSG,NULL,0), MB_YESNO) == IDYES)
+ {
+ wa::strings::wa_string l_url_new_version( disp );
+ myOpenURL( NULL, l_url_new_version.GetW().c_str() );
+ }
+ free(disp);
+ }
+ }
+ }
+ }
+ }
+ }
+ config_newverchk = getDay();
+ }
+
+ void OnError(DownloadToken token)
+ {
+ config_newverchk = getDay();
+ }
+
+ RECVS_DISPATCH;
+};
+
+#define CBCLASS VersionCheckCallback
+START_DISPATCH;
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
+END_DISPATCH;
+#undef CBCLASS
+
+static VersionCheckCallback versionCheckCallback;
+
+static void CheckVersion(int allowedChannel = 0)
+{
+ if ( WAC_API_DOWNLOADMANAGER )
+ {
+ char url[ 1024 ] = { 0 };
+ char *urlend = 0;
+ size_t urlend_size = 0;
+
+ wa::strings::wa_string l_winamp_product_ver( STR_WINAMP_PRODUCTVER );
+ l_winamp_product_ver.replaceAll( ",", "." );
+
+ StringCchPrintfExA( url, 1024, &urlend, &urlend_size, 0, "http://client.winamp.com/update/latest-version.php?v=%s", l_winamp_product_ver.GetA().c_str() );
+
+ char uid[ 512 ] = "";
+ stats_getuidstr( uid );
+ if ( uid[ 0 ] )
+ StringCchPrintfExA( urlend, urlend_size, &urlend, &urlend_size, 0, "&ID=%s", uid );
+
+ const wchar_t *langIdentifier = langManager ? ( langManager->GetLanguageIdentifier( LANG_IDENT_STR ) ) : 0;
+ if ( langIdentifier )
+ StringCchPrintfA( urlend, urlend_size, "&lang=%s", (char *)AutoUrl( langIdentifier ) );
+
+
+ OSVERSIONINFOEX info;
+ ZeroMemory( &info, sizeof( OSVERSIONINFOEX ) );
+ info.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
+
+ GetVersionEx( (LPOSVERSIONINFO)&info );
+
+ char l_os_version[ 32 ];
+
+ sprintf( l_os_version, "&osver=%u.%u.%u", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber );
+ strcat( url, l_os_version );
+
+ char szAllowedChannel[32];
+ sprintf(szAllowedChannel, "&allowedchannel=%d", allowedChannel);
+ strcat(url, szAllowedChannel);
+
+ WAC_API_DOWNLOADMANAGER->DownloadEx( url, &versionCheckCallback, api_downloadManager::DOWNLOADEX_BUFFER );
+ }
+}
+
+bool DoVerChk(int verchk)
+{
+ return verchk == 1 || (verchk > 1 && verchk + 1 < (int)getDay());
+}
+
+class PingCallback : public ifc_downloadManagerCallback
+{
+public:
+ void OnInit(DownloadToken token)
+ {
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (http)
+ http->addheader("Accept: */*");
+ }
+ RECVS_DISPATCH;
+};
+
+#define CBCLASS PingCallback
+START_DISPATCH;
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit)
+END_DISPATCH;
+#undef CBCLASS
+
+static PingCallback pingCallback;
+
+void Ping(const char *url)
+{
+ if (WAC_API_DOWNLOADMANAGER)
+ WAC_API_DOWNLOADMANAGER->DownloadEx(url, &pingCallback, api_downloadManager::DOWNLOADEX_BUFFER);
+}
+
+void newversioncheck(void)
+{
+ if (isInetAvailable())
+ {
+ if (DoVerChk(config_newverchk))
+ {
+ // go ahead and call this on the main thread to ensure that the GUID gets created w/o a race condition
+ char uid[512]="";
+ stats_getuidstr(uid);
+ CheckVersion(config_newverchk_rc);
+ }
+ if (DoVerChk(config_newverchk2))
+ {
+ char _url[MAX_URL] = {0};
+ char *url=_url;
+ size_t urlsize=MAX_URL;
+
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"http://client.winamp.com/update/client_session.php?v=%s",APP_VERSION);
+
+ char uid[512]="";
+ stats_getuidstr(uid);
+ if (uid[0])
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&ID=%s", uid);
+
+ int values[Stats::NUM_STATS] = {0, };
+ stats.GetStats(values);
+ for (int x = 0; x < Stats::NUM_STATS; x ++)
+ {
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&st%d=%d", x + 1, values[x]);
+ }
+
+ wchar_t stat_str[256] = {0};
+ stats.GetString("skin", stat_str, 256);
+ if (stat_str[0])
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&skin=%s",(char *)AutoUrl(stat_str));
+
+ stats.GetString("colortheme", stat_str, 256);
+ if (stat_str[0])
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&ct=%s",(char *)AutoUrl(stat_str));
+
+ stats.GetString("pmp", stat_str, 256);
+ if (stat_str[0])
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&pmp=%s",(char *)AutoUrl(stat_str));
+
+ const wchar_t *langIdentifier = langManager?(langManager->GetLanguageIdentifier(LANG_IDENT_STR)):0;
+ if (langIdentifier)
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0, "&lang=%s", (char *)AutoUrl(langIdentifier));
+
+ Ping(_url);
+ config_newverchk2 = getDay();
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/VideoAspectAdjuster.h b/Src/Winamp/VideoAspectAdjuster.h
new file mode 100644
index 00000000..c921f28d
--- /dev/null
+++ b/Src/Winamp/VideoAspectAdjuster.h
@@ -0,0 +1,12 @@
+#ifndef NULLSOFT_VIDEOASPECTADJUSTERH
+#define NULLSOFT_VIDEOASPECTADJUSTERH
+
+#include <windows.h>
+
+class VideoAspectAdjuster
+{
+public:
+ virtual void adjustAspect(RECT &rd) = 0;
+ virtual void DrawLogo(HDC out, RECT *canvas_size)=0;
+};
+#endif \ No newline at end of file
diff --git a/Src/Winamp/VideoConfigGroup.cpp b/Src/Winamp/VideoConfigGroup.cpp
new file mode 100644
index 00000000..d9b8e5f5
--- /dev/null
+++ b/Src/Winamp/VideoConfigGroup.cpp
@@ -0,0 +1,41 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "VideoConfigGroup.h"
+#include "WinampAttributes.h"
+
+
+ifc_configitem *VideoConfigGroup::GetItem(const wchar_t *name)
+{
+ if (!wcscmp(name, L"overlay"))
+ return &config_video_overlays;
+ else if (!wcscmp(name, L"YV12"))
+ return &config_video_yv12;
+ else if (!wcscmp(name, L"vsync"))
+ return &config_video_vsync2;
+ else if (!wcscmp(name, L"ddraw"))
+ return &config_video_ddraw;
+ else if (!wcscmp(name, L"gdiplus"))
+ return &config_video_gdiplus;
+ else if (!wcscmp(name, L"autoopen"))
+ return &config_video_autoopen;
+ else if (!wcscmp(name, L"autoclose"))
+ return &config_video_autoclose;
+ else if (!wcscmp(name, L"auto_fs"))
+ return &config_video_auto_fs;
+
+ return 0;
+}
+
+
+#define CBCLASS VideoConfigGroup
+START_DISPATCH;
+CB(IFC_CONFIGGROUP_GETITEM, GetItem)
+CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/VideoConfigGroup.h b/Src/Winamp/VideoConfigGroup.h
new file mode 100644
index 00000000..1b51de52
--- /dev/null
+++ b/Src/Winamp/VideoConfigGroup.h
@@ -0,0 +1,23 @@
+#ifndef NULLSOFT_WINAMP_VIDEOCONFIGGROUP_H
+#define NULLSOFT_WINAMP_VIDEOCONFIGGROUP_H
+
+#include "main.h"
+#include "../Agave/Config/ifc_configgroup.h"
+
+// {2135E318-6919-4bcf-99D2-62BE3FCA8FA6}
+static const GUID videoConfigGroupGUID =
+{ 0x2135e318, 0x6919, 0x4bcf, { 0x99, 0xd2, 0x62, 0xbe, 0x3f, 0xca, 0x8f, 0xa6 } };
+
+class VideoConfigGroup : public ifc_configgroup
+{
+public:
+ ifc_configitem *GetItem(const wchar_t *name);
+ GUID GetGUID() { return videoConfigGroupGUID; }
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern VideoConfigGroup videoConfigGroup;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/VideoFeedFactory.h b/Src/Winamp/VideoFeedFactory.h
new file mode 100644
index 00000000..748cf0b9
--- /dev/null
+++ b/Src/Winamp/VideoFeedFactory.h
@@ -0,0 +1,35 @@
+#ifndef NULLSOFT_WINAMP_VIDEOFEEDFACTORY_H
+#define NULLSOFT_WINAMP_VIDEOFEEDFACTORY_H
+
+#include <api/service/waservicefactorybase.h>
+#include <api/service/services.h>
+#include <api/skin/feeds/api_textfeed.h>
+#include "api.h"
+
+// {BD838BA9-1CE8-4f73-BBC0-58DA5168517F}
+static const GUID videoFeedFactoryGUID =
+{ 0xbd838ba9, 0x1ce8, 0x4f73, { 0xbb, 0xc0, 0x58, 0xda, 0x51, 0x68, 0x51, 0x7f } };
+
+
+class VideoTextFeedFactory : public waServiceBase<svc_textFeed, VideoTextFeedFactory> {
+public:
+ VideoTextFeedFactory() : waServiceBase<svc_textFeed, VideoTextFeedFactory>(videoFeedFactoryGUID) {}
+ static const char *getServiceName() { return "Video Text Feed"; }
+ svc_textFeed *getService() { return videoTextFeed; }
+ static FOURCC getServiceType() { return WaSvc::TEXTFEED; }
+};
+
+// {87291C37-EC56-476b-B813-ED0F6F90C3B7}
+static const GUID playlistFeedFactory =
+{ 0x87291c37, 0xec56, 0x476b, { 0xb8, 0x13, 0xed, 0xf, 0x6f, 0x90, 0xc3, 0xb7 } };
+
+
+class PlaylistTextFeedFactory : public waServiceBase<svc_textFeed, PlaylistTextFeedFactory> {
+public:
+ PlaylistTextFeedFactory() : waServiceBase<svc_textFeed, PlaylistTextFeedFactory>(playlistFeedFactory) {}
+ static const char *getServiceName() { return "Playlist Text Feed"; }
+ svc_textFeed *getService() { return playlistTextFeed; }
+ static FOURCC getServiceType() { return WaSvc::TEXTFEED; }
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/VideoOSD.cpp b/Src/Winamp/VideoOSD.cpp
new file mode 100644
index 00000000..aedb7df0
--- /dev/null
+++ b/Src/Winamp/VideoOSD.cpp
@@ -0,0 +1,537 @@
+#include "Main.h"
+#include "VideoOSD.h"
+
+#include "resource.h"
+
+
+#include "draw.h"
+
+#include "../nu/AutoChar.h"
+#define OSD_TEXT_R 192
+#define OSD_TEXT_G 192
+#define OSD_TEXT_B 192
+#define OSD_TEXT_R_HILITE 255
+#define OSD_TEXT_G_HILITE 255
+#define OSD_TEXT_B_HILITE 255
+#define OSD_VOL_COL_R 0
+#define OSD_VOL_COL_G 0
+#define OSD_VOL_COL_B 192
+#define OSD_VOL_BKCOL_R 0
+#define OSD_VOL_BKCOL_G 0
+#define OSD_VOL_BKCOL_B 64
+
+#define CTRL_PROGRESSTEXT 0
+#define CTRL_PROGRESS 1
+#define CTRL_PROGRESSSPACER 2
+#define CTRL_REW 3
+#define CTRL_PLAY 4
+#define CTRL_PAUSE 5
+#define CTRL_STOP 6
+#define CTRL_FFWD 7
+#define CTRL_VOLSPACER 8
+#define CTRL_VOLTEXT 9
+#define CTRL_VOL 10
+
+#define CTRLTYPE_SYMBOL 0
+#define CTRLTYPE_TEXT 1
+#define CTRLTYPE_PROGRESS 2
+#define CTRLTYPE_SPACER 3
+
+IVideoOSD *temp;
+
+int g_ctrl_type[ NUM_WIDGETS ] =
+{
+ CTRLTYPE_TEXT,
+ CTRLTYPE_PROGRESS,
+ CTRLTYPE_SPACER,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SPACER,
+ CTRLTYPE_TEXT,
+ CTRLTYPE_PROGRESS
+};
+
+
+#define SHOW_STREAM_TITLE_AT_TOP 1
+
+char progStr[64] = {0}, volStr[64] = {0};
+const char *g_ctrl_text[NUM_WIDGETS] =
+ {
+ progStr/*"Progress "*/,
+ "",
+ "",
+ "7", // rew
+ "4", // play
+ ";", // pause
+ "<", // stop
+ "8", // ffwd
+ "",
+ volStr/*"Volume "*/,
+ ""
+ };
+
+
+int g_ctrl_force_width[NUM_WIDGETS] =
+ {
+ 0,
+ 256/*96*/, // progress bar width
+ 32, // spacer width
+ 0, // rew
+ 0, // play
+ 0, // pause
+ 0, // stop
+ 0, // ffwd
+ 32, // spacer width
+ 0,
+ 96/*64*/ // volume bar width
+ };
+
+IVideoOSD::IVideoOSD()
+ : ctrlrects_ready(0), parent(0)
+{
+ temp = this;
+
+ getString(IDS_OSD_PROGRESS_TEXT,progStr,64);
+ getString(IDS_OSD_VOLUME_TEXT,volStr,64);
+
+ last_close_height = 0;
+ last_close_width = 0;
+ osdMemBMW = 0;
+ osdMemBMH = 0;
+ osdLastMouseX = -1;
+ osdLastMouseY = -1;
+ ignore_mousemove_count = 0;
+ osdLastClickItem = 0;
+ show_osd = false;
+
+ for (int i = 0; i < NUM_WIDGETS; i++)
+ SetRect(&ctrlrect[i], 0, 0, 0, 0);
+}
+
+IVideoOSD::~IVideoOSD()
+{
+ KillTimer(parent, (UINT_PTR)this);
+}
+
+bool IVideoOSD::Showing()
+{
+ return show_osd;
+}
+
+bool IVideoOSD::Ready()
+{
+ return !!ctrlrects_ready;
+}
+
+int IVideoOSD::GetBarHeight()
+{
+ return (/*show_osd && */ctrlrects_ready) ? (ctrlrect_all.bottom - ctrlrect_all.top) : 0;
+}
+
+void IVideoOSD::HitTest(int x, int y, int dragging)
+{
+ if (!show_osd) return ;
+
+ // dragging == -1: just a mousemove (no clicking)
+ // dragging == 0: user clicked
+ // dragging == 1: user clicked before, and is now dragging/moving mouse
+
+ if (dragging < 1)
+ osdLastClickItem = -1;
+
+ // transform (x,y) from screen coords into coords relative to the memDC
+ RECT lastfsrect;
+ getViewport(&lastfsrect, parent, 1, NULL);
+ y = y - ((lastfsrect.bottom - lastfsrect.top) - (ctrlrect_all.bottom - ctrlrect_all.top));
+
+ int i0 = 0;
+ int i1 = NUM_WIDGETS;
+ if (dragging == 1)
+ {
+ i0 = osdLastClickItem;
+ i1 = osdLastClickItem + 1;
+ }
+
+ for (int i = i0; i < i1; i++)
+ {
+ if (dragging == 1 || (x >= ctrlrect[i].left && x <= ctrlrect[i].right && y >= ctrlrect[i].top && y <= ctrlrect[i].bottom))
+ {
+ float t = (x - ctrlrect[i].left) / (float)(ctrlrect[i].right - ctrlrect[i].left);
+ if (t < 0) t = 0;
+ if (t > 1) t = 1;
+ if (dragging < 1)
+ osdLastClickItem = i;
+
+ switch (i)
+ {
+ case CTRL_VOL:
+ if (dragging >= 0)
+ {
+ int v = (int)(t * 255);
+ config_volume = v;
+ in_setvol(v);
+ draw_volumebar(config_volume, 0);
+ }
+ return ;
+ case CTRL_PROGRESS:
+
+ if (dragging >= 0)
+ {
+ int len = in_getlength();
+ if (len > 0 && !PlayList_ishidden(PlayList_getPosition()))
+ {
+ if (in_seek((int)(t*len*1000)) < 0)
+ SendMessageW(hMainWindow, WM_WA_MPEG_EOF, 0, 0);
+ }
+ }
+ return ;
+ case CTRL_PAUSE:
+ if (dragging == 0)
+ {
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0);
+ }
+ return ;
+ case CTRL_PLAY:
+ if (dragging == 0)
+ {
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0);
+ }
+ return ;
+ case CTRL_STOP:
+ if (dragging == 0)
+ {
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);
+ }
+ return ;
+ case CTRL_REW:
+ case CTRL_FFWD:
+ if (dragging == 0)
+ {
+ if (i == CTRL_REW)
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON1, 0);
+ else
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON5, 0);
+ }
+ return ;
+ default:
+ if (dragging < 1)
+ osdLastClickItem = -1;
+ break;
+ }
+ }
+ }
+}
+
+void IVideoOSD::Show()
+{
+ if (!show_osd)
+ {
+
+ show_osd = true;
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ RECT r;
+ GetClientRect(parent, &r);
+ r.bottom = r.top + GetBarHeight();
+ InvalidateRect(parent, &r, TRUE);
+ GetClientRect(parent, &r);
+ r.top = r.bottom - GetBarHeight();
+ InvalidateRect(parent, &r, TRUE);
+
+ PostMessageW(parent, WM_USER + 0x888, 0, 0);
+ }
+
+ KillTimer(parent, (UINT_PTR)this);
+ SetTimer(parent, (UINT_PTR)this, 3000, IVideoOSD::TimerCallback);
+
+// Draw();
+}
+
+void CALLBACK IVideoOSD::TimerCallback(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR idEvent, DWORD/* dwTime*/)
+{
+ IVideoOSD *videoOSD = (IVideoOSD *)idEvent;
+ videoOSD->Hide();
+}
+
+void IVideoOSD::Hide()
+{
+
+
+ RECT r;
+ GetClientRect(parent, &r);
+ r.bottom = r.top + GetBarHeight();
+ InvalidateRect(parent, &r, TRUE);
+ GetClientRect(parent, &r);
+ r.top = r.bottom - GetBarHeight();
+ InvalidateRect(parent, &r, TRUE);
+
+ PostMessageW(parent, WM_USER + 0x888, 0, 0);
+
+ if (show_osd)
+ {
+ //MessageBeep(0xFFFFFFFF);
+ show_osd = false;
+ KillTimer(parent, (UINT_PTR)this);
+ SetCursor(NULL);
+ }
+ //ctrlrects_ready = 0;
+}
+
+
+void IVideoOSD::Draw()
+{
+ HDC hdc = GetDC(parent);
+ if (show_osd)
+ {
+ HGDIOBJ osdProgressBrushBg = CreateSolidBrush(RGB(OSD_VOL_BKCOL_R, OSD_VOL_BKCOL_G, OSD_VOL_BKCOL_B));
+ HGDIOBJ osdProgressBrushFg = CreateSolidBrush(RGB(OSD_VOL_COL_R, OSD_VOL_COL_G, OSD_VOL_COL_B));
+ HGDIOBJ osdProgressPenBg = CreatePen(PS_SOLID, 0, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
+ HGDIOBJ osdProgressPenFg = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
+ HGDIOBJ osdProgressPenBgHilite = CreatePen(PS_SOLID, 0, RGB(OSD_TEXT_R_HILITE, OSD_TEXT_G_HILITE, OSD_TEXT_B_HILITE));
+ HGDIOBJ osdBlackBrush = CreateSolidBrush(RGB(0, 0, 0)); //OV_COL_R,OV_COL_G,OV_COL_B));
+ HFONT osdFontSymbol = CreateFontA(OSD_TEXT_SIZE, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, "Webdings");
+
+ HDC osdMemDC = CreateCompatibleDC(hdc);
+ HBITMAP osdMemBM = 0; // memory bitmap (for memDC)
+ HBITMAP osdOldBM = 0; // old bitmap (from memDC)
+
+
+ COLORREF fg = GetTextColor(osdMemDC);
+ COLORREF bg = GetBkColor(osdMemDC);
+ SetTextColor(osdMemDC, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
+ SetBkColor(osdMemDC, RGB(0, 0, 0)); //OV_COL_R,OV_COL_G,OV_COL_B));
+
+ HGDIOBJ oldfont = SelectObject(osdMemDC, osdFontText);
+ HGDIOBJ oldbrush = SelectObject(osdMemDC, osdProgressBrushBg);
+ HGDIOBJ oldpen = SelectObject(osdMemDC, osdProgressPenBg);
+
+ RECT fullr;
+ GetClientRect(parent, &fullr);
+
+ /* ClientToScreen(parent, (LPPOINT)&fullr);
+ ClientToScreen(parent, ((LPPOINT)&fullr) + 1);
+ // transform coords from windows desktop coords (where 0,0==upper-left corner of the primary monitor)
+ // to the coords for the monitor we're displaying on:
+ fullr.top -= m_mon_y;
+ fullr.left -= m_mon_x;
+ fullr.right -= m_mon_x;
+ fullr.bottom -= m_mon_y;
+ */
+ int streaming = (in_getlength() < 0) || !in_mod || !in_mod->is_seekable;
+
+ if (ctrlrects_ready != streaming + 1)
+ {
+ ctrlrects_ready = streaming + 1;
+
+ int net_width = 0;
+ int max_height = 0;
+ int i;
+ for (i = 0; i < NUM_WIDGETS; i++)
+ {
+ SetRect(&ctrlrect[i], 0, 0, 0, 0);
+ if (streaming && (i == CTRL_PROGRESS || i == CTRL_PROGRESSTEXT || i == CTRL_PROGRESSSPACER || i == CTRL_FFWD || i == CTRL_REW))
+ {
+ // disable progress bar + seek arrows when the NSV is a stream
+ ctrlrect[i].right = -1;
+ continue;
+ }
+ else if (g_ctrl_force_width[i] != 0)
+ {
+ SetRect(&ctrlrect[i], 0, 0, g_ctrl_force_width[i], 0);
+ }
+ else
+ {
+ SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
+ SetRect(&ctrlrect[i], 0, 0, 256, 256);
+ ctrlrect[i].bottom = DrawTextA(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE | DT_CALCRECT);
+ }
+ net_width += ctrlrect[i].right - ctrlrect[i].left;
+ max_height = max(max_height, ctrlrect[i].bottom - ctrlrect[i].top);
+ }
+
+ // now we know the size of all the controls; now place them.
+ int x = (fullr.right + fullr.left) / 2 - net_width / 2;
+ SetRect(&ctrlrect_all, 0, 0, 0, 0);
+ for (i = 0; i < NUM_WIDGETS; i++)
+ {
+ if (ctrlrect[i].right >= 0) // if control is not disabled...
+ {
+ int this_width = ctrlrect[i].right - ctrlrect[i].left;
+ int this_height = ctrlrect[i].bottom - ctrlrect[i].top ;
+ if (this_height == 0) this_height = max_height * 2 / 3; // progress bars
+ ctrlrect[i].top = max_height / 2 - this_height / 2;
+ ctrlrect[i].bottom = max_height / 2 + this_height / 2;
+ ctrlrect[i].left = x;
+ ctrlrect[i].right = x + this_width;
+ if (ctrlrect_all.bottom == 0)
+ {
+ ctrlrect_all.top = ctrlrect[i].top ;
+ ctrlrect_all.bottom = ctrlrect[i].bottom;
+ }
+ else
+ {
+ ctrlrect_all.top = min(ctrlrect_all.top , ctrlrect[i].top);
+ ctrlrect_all.bottom = max(ctrlrect_all.bottom, ctrlrect[i].bottom);
+ }
+ x += this_width;
+ }
+ }
+ }
+
+ int w = fullr.right - fullr.left;
+ int h = ctrlrect_all.bottom - ctrlrect_all.top;
+ if (!osdMemBM || osdMemBMW != w || osdMemBMH != h)
+ {
+ if (osdMemBM)
+ {
+ SelectObject(osdMemDC, osdOldBM);
+ DeleteObject(osdMemBM);
+ }
+ osdMemBM = CreateCompatibleBitmap(hdc, w, h);
+ osdOldBM = (HBITMAP)SelectObject(osdMemDC, osdMemBM);
+ osdMemBMW = w;
+ osdMemBMH = h;
+ }
+
+ RECT temp;
+ SetRect(&temp, 0, 0, w, h);
+ FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
+
+ for (int i = 0; i < NUM_WIDGETS; i++)
+ {
+ if (g_ctrl_type[i] == CTRLTYPE_PROGRESS)
+ {
+ int progress = 0;
+ int max_progress = ctrlrect[i].right - ctrlrect[i].left;
+ switch (i)
+ {
+ case CTRL_VOL:
+ progress = config_volume * max_progress / 255;
+ break;
+ case CTRL_PROGRESS:
+ if (playing)
+ {
+ int len = in_getlength();
+ if (len > 0) progress = (in_getouttime() / 1000) * max_progress / len;
+ }
+ if (progress > max_progress) progress = max_progress;
+ break;
+ }
+
+ SelectObject(osdMemDC, osdProgressBrushBg);
+ SelectObject(osdMemDC, (i == osdLastClickItem) ? osdProgressPenBgHilite : osdProgressPenBg);
+ RoundRect(osdMemDC, ctrlrect[i].left, ctrlrect[i].top, ctrlrect[i].right, ctrlrect[i].bottom, 3, 3);
+ SelectObject(osdMemDC, osdProgressBrushFg);
+ SelectObject(osdMemDC, osdProgressPenFg);
+ Rectangle(osdMemDC, ctrlrect[i].left + 1, ctrlrect[i].top + 1, ctrlrect[i].left + progress, ctrlrect[i].bottom);
+ }
+ else if (g_ctrl_type[i] == CTRLTYPE_SYMBOL ||
+ g_ctrl_type[i] == CTRLTYPE_TEXT)
+ {
+ SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
+ SetTextColor(osdMemDC, (i == osdLastClickItem) ? RGB(OSD_TEXT_R_HILITE, OSD_TEXT_G_HILITE, OSD_TEXT_B_HILITE) : RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
+ DrawTextA(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE);
+ }
+ }
+
+ int x0 = fullr.left;
+ int y0 = fullr.bottom - (ctrlrect_all.bottom - ctrlrect_all.top);
+ BitBlt(hdc, x0, y0, w, h, osdMemDC, 0, 0, SRCCOPY);
+
+ // display stream title @ the top:
+#if (SHOW_STREAM_TITLE_AT_TOP)
+ if (1)
+ {
+ RECT temp;
+ SetRect(&temp, 0, 0, w, h);
+ FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
+
+ SelectObject(osdMemDC, osdFontText);
+ SetTextColor(osdMemDC, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
+ AutoChar narrowTitle(FileTitle);
+ wchar_t buf[FILETITLE_SIZE+32] = {0};
+
+ StringCchPrintfW(buf, sizeof(buf)/sizeof(*buf), L"%s (%d %s)", FileTitle ? FileTitle : L"", g_brate, getStringW(IDS_KBPS,NULL,0));
+ if ((config_fixtitles&2))
+ {
+ wchar_t *p = buf;
+ while (p && *p)
+ {
+ if (*p == '_') // replace _ with space
+ *p = ' ';
+ p = CharNextW(p);
+ }
+ }
+ DrawTextW(osdMemDC, buf, -1, &temp, DT_SINGLELINE | DT_CENTER);
+
+ SelectObject(osdMemDC, osdFontSymbol);
+ DrawTextW(osdMemDC, L"2", -1, &temp, DT_SINGLELINE | DT_RIGHT);
+ RECT rr = {0, 0, w, h};
+ DrawTextW(osdMemDC, L"2", -1, &rr, DT_SINGLELINE | DT_RIGHT | DT_CALCRECT);
+ last_close_height = rr.bottom - rr.top;
+ last_close_width = rr.right - rr.left;
+
+
+ int x0 = fullr.left;
+ int y0 = fullr.top;
+ BitBlt(hdc, x0, y0, w, h, osdMemDC, 0, 0, SRCCOPY);
+ }
+
+ SelectObject(osdMemDC, oldpen);
+ SelectObject(osdMemDC, oldbrush);
+ SelectObject(osdMemDC, oldfont);
+ SetTextColor(osdMemDC, fg);
+ SetBkColor(osdMemDC, bg);
+
+ DeleteObject(osdProgressBrushBg);
+ DeleteObject(osdProgressBrushFg);
+ DeleteObject(osdBlackBrush);
+ DeleteObject(osdProgressPenBg);
+ DeleteObject(osdProgressPenFg);
+ DeleteObject(osdProgressPenBgHilite);
+ DeleteObject(osdFontSymbol);
+ if (osdMemDC)
+ {
+ SelectObject(osdMemDC, osdOldBM); // delete our doublebuffer
+ DeleteDC(osdMemDC);
+ }
+ if (osdMemBM) DeleteObject(osdMemBM);
+ }
+#endif
+ ReleaseDC(parent, hdc);
+}
+
+bool IVideoOSD::CloseHitTest(int x, int y)
+{
+ RECT r;
+ GetClientRect(parent, &r);
+ return (x > r.right - last_close_width && y < last_close_height);
+}
+
+bool IVideoOSD::Mouse(int x, int y, WPARAM wParam, bool moving)
+{
+ if (wParam & MK_LBUTTON)
+ {
+ Show();
+ if (CloseHitTest(x, y))
+ return true;
+ ignore_mousemove_count = 2;
+ HitTest(x, y, moving ? 1 : 0);
+ }
+ else
+ {
+ if (((osdLastMouseX - x) || (osdLastMouseY - y)) && (ignore_mousemove_count--))
+ {
+ Show();
+ HitTest(x, y, moving ? -1 : 0);
+ ignore_mousemove_count = 2;
+ }
+ }
+
+ osdLastMouseX = x;
+ osdLastMouseY = y;
+ return false;
+}
+
diff --git a/Src/Winamp/VideoOSD.h b/Src/Winamp/VideoOSD.h
new file mode 100644
index 00000000..fdc55041
--- /dev/null
+++ b/Src/Winamp/VideoOSD.h
@@ -0,0 +1,53 @@
+#ifndef NULLSOFT_VIDEOOSDH
+#define NULLSOFT_VIDEOOSDH
+
+/* Video On Screen Display */
+#include <windows.h>
+
+#define NUM_WIDGETS 11
+
+class IVideoOSD
+{
+public:
+ IVideoOSD();
+ ~IVideoOSD();
+ void SetParent(HWND _parent)
+ {
+ parent=_parent;
+ }
+ bool Showing();
+ bool Ready();
+ void Show();
+ void Hide();
+ void Draw();
+ int GetBarHeight();
+ bool Mouse(int x, int y, WPARAM wParam, bool moving); // return true if we need to close because of this
+
+ int ctrlrects_ready;
+
+ virtual bool MouseDown(int x, int y, WPARAM wParam) {return false;};
+ virtual bool MouseMove(int x, int y, WPARAM wParam) {return false;};
+ virtual bool MouseUp(int x, int y, WPARAM wParam) {return false;};
+
+protected:
+ HWND parent;
+private:
+ bool CloseHitTest(int x, int y);
+ void HitTest(int x, int y, int dragging);
+ int osdLastClickItem;
+
+ int osdMemBMW; // width of memory bitmap
+ int osdMemBMH; // height of memory bitmap
+ int osdLastMouseX; // for WM_MOUSEMOVE thresholding, so osd isn't spastic
+ int osdLastMouseY; // for WM_MOUSEMOVE thresholding, so osd isn't spastic
+ RECT ctrlrect[NUM_WIDGETS]; // relative to [i.e. (0,0) is] upper left corner of the black strip @ the bottom
+ RECT ctrlrect_all; // relative to [i.e. (0,0) is] upper left corner of the black strip @ the bottom
+
+ bool show_osd;
+
+ static void CALLBACK TimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+ int ignore_mousemove_count;
+ int last_close_height, last_close_width;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/VideoOutput.cpp b/Src/Winamp/VideoOutput.cpp
new file mode 100644
index 00000000..9dac1c52
--- /dev/null
+++ b/Src/Winamp/VideoOutput.cpp
@@ -0,0 +1,1040 @@
+#include <windowsx.h>
+
+#include "main.h"
+#include "VideoOutput.h"
+#include "VideoOutputChild.h"
+#include "vid_none.h"
+#include "vid_ddraw.h"
+#include "vid_overlay.h"
+#include "vid_d3d.h"
+#include <cassert>
+#include "directdraw.h"
+#include "video.h"
+#include "api.h"
+#include "WinampAttributes.h"
+#include "resource.h"
+#include "../nu/AutoWide.h"
+#include "stats.h"
+#include "IVideoD3DOSD.h"
+
+extern "C" int is_fullscreen_video;
+#define WM_VIDEO_UPDATE_STATUS_TEXT WM_USER+0x874
+#define WM_VIDEO_OPEN WM_USER+0x875
+#define WM_VIDEO_CLOSE WM_USER+0x876
+#define WM_VIDEO_RESIZE WM_USER+0x877
+#define WM_VIDEO_OSDCHANGE WM_USER+0x888
+#define WM_VIDEO_CREATE WM_USER+0x900
+int g_bitmap_id = IDB_VIDEOLOGO;
+int VideoOutput::class_refcnt = 0;
+wchar_t vidoutbuf_save[1024] = {0};
+
+static bool input_plugin_thread_safe = false;
+
+//#define USE_GDIPLUS_VIDEO_RENDERER
+
+IVideoOSD *posd = new IVideoD3DOSD;
+
+HRESULT(WINAPI *_DirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter) = 0;
+
+void OpenDirectDraw()
+{
+ static int a = 0;
+ if (!_DirectDrawCreate && !a)
+ {
+ a++;
+ HINSTANCE h = LoadLibraryW(L"ddraw.dll");
+ if (h)
+ {
+ *(void**)&_DirectDrawCreate = (void*)GetProcAddress(h, "DirectDrawCreate");
+ }
+ }
+}
+
+HMENU BuildPopupMenu()
+{
+ HMENU menu = GetSubMenu(GetSubMenu(top_menu, 3), 13);
+ {
+ static int menuset = 0;
+ if (!menuset)
+ {
+ InsertMenu(menu, (UINT)-1, MF_BYPOSITION | MF_SEPARATOR, 0, 0);
+ InsertMenuA(menu, (UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(top_menu, 0), "Winamp");
+ menuset = 1;
+ }
+ }
+ updateTrackSubmenu();
+ return menu;
+}
+
+void VideoOutput::mainthread_Create()
+{
+ if (!video_created)
+ {
+ m_video_output = new Direct3DVideoOutput(video_hwnd, this);
+ video_created=true;
+ }
+}
+
+VideoOutput::VideoOutput(HWND parent_hwnd, int initxpos, int initypos)
+ : m_logo(0),
+ m_logo_w(0),
+ m_logo_h(0),
+ userVideo(false)
+{
+ video_palette = 0;
+ video_created = false;
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::VideoOutput"));
+ WNDCLASSW wc = {0, };
+
+ wc.style = CS_DBLCLKS;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpfnWndProc = WndProc;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.lpszClassName = L"WinampVideoChild";
+ wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+ if (!class_refcnt) RegisterClassW(&wc);
+ class_refcnt++;
+
+ m_tracksel = NULL;
+ fs_reparented_rgn = 0;
+ fs_reparented = 0;
+ m_ignore_change = false;
+ fs_has_resized = false;
+ m_opened = 0;
+
+ last_fullscreen_exit_time = 0;
+
+ curSubtitle = NULL;
+ m_statusmsg = 0;
+ m_bufferstate = -1;
+ m_msgcallback = 0;
+ m_msgcallback_tok = 0;
+ video_hwnd = 0;
+
+ aspect = 1.0;
+ m_need_change = false;
+
+ is_fs = 0;
+ memset(&oldfsrect, 0, sizeof(oldfsrect));
+ memset(&lastfsrect, 0, sizeof(lastfsrect));
+
+ m_video_output = NULL;
+ resetSubtitle();
+ m_lastbufinvalid = NULL;
+
+ CreateWindowExW(0, wc.lpszClassName, L"WinampVideoChildWindow",
+ parent_hwnd ? WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS :
+ (WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX)),
+ 0, 0, 1, 1,
+ parent_hwnd, NULL, wc.hInstance, (void*)this);
+ posd->SetParent(video_hwnd);
+}
+
+VideoOutput::~VideoOutput()
+{
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::~VideoOutput"));
+ free(m_statusmsg);
+ posd->Hide();
+ if (m_video_output) m_video_output->close();
+ m_video_output = 0;
+ DestroyWindow(video_hwnd);
+ if (m_logo)
+ DeleteObject(m_logo);
+ m_logo = 0;
+ if (posd)
+ {
+ delete posd;
+ posd = NULL;
+ }
+}
+
+void VideoOutput::LoadLogo()
+{
+ static wchar_t logo_tmp[MAX_PATH];
+ if(!logo_tmp[0]) StringCchPrintfW(logo_tmp,MAX_PATH,L"%s\\videologo.bmp",CONFIGDIR);
+ if(PathFileExistsW(logo_tmp)) m_logo = (HBITMAP)LoadImageW(0,logo_tmp,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
+
+ if(!m_logo) m_logo = (HBITMAP)LoadImage(hMainInstance, MAKEINTRESOURCE(g_bitmap_id), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+ BITMAP bm;
+ GetObject(m_logo, sizeof(BITMAP), &bm);
+ m_logo_w = bm.bmWidth;
+ m_logo_h = bm.bmHeight;
+ if (m_logo_h < 0)
+ m_logo_h = -m_logo_h;
+}
+
+void VideoOutput::UpdateText(const wchar_t *videoInfo)
+{
+ {
+ //AutoLock lock(textGuard);
+ StringCchCopyW(vidoutbuf_save, 1023, (wchar_t*)videoInfo); // 1023 so that we can guarantee that this will be null terminated even in the middle of a strcpy
+ }
+ PostMessageW(hVideoWindow, WM_VIDEO_UPDATE_STATUS_TEXT, (WPARAM)vidoutbuf_save, 0);
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_VIDEOINFO, IPC_CB_MISC);
+}
+
+INT_PTR VideoOutput::extended(INT_PTR param1, INT_PTR param2, INT_PTR param3)
+{
+ switch (param1) // nonlocking commands
+ {
+ case VIDUSER_GET_VIDEOHWND:
+ return (INT_PTR)video_hwnd;
+
+ case VIDUSER_SET_INFOSTRING:
+ if (param2)
+ UpdateText(AutoWide((const char *)param2));
+ return 0;
+
+ case VIDUSER_SET_INFOSTRINGW:
+ if (param2)
+ UpdateText((const wchar_t *)param2);
+ return 0;
+ }
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::extended"));
+ switch (param1)
+ {
+ case VIDUSER_SET_PALETTE:
+ {
+ RGBQUAD *palette = (RGBQUAD *)param2;
+ if (m_video_output)
+ m_video_output->setPalette(palette);
+ else
+ video_palette = palette;
+ return 0;
+ }
+
+ case VIDUSER_SET_VFLIP:
+ {
+ if (m_video_output)
+ m_video_output->setVFlip(param2);
+ return 0;
+ }
+
+ case VIDUSER_SET_TRACKSELINTERFACE:
+ m_tracksel = (ITrackSelector *)param2;
+ return 0;
+
+ case VIDUSER_OPENVIDEORENDERER:
+ {/*
+ userVideo = true;
+ m_video_output = (VideoRenderer *)param2;
+ VideoOpenStruct *openStruct = (VideoOpenStruct *)param3;
+ int x = openUser(openStruct->w, openStruct->h, openStruct->vflip, openStruct->aspectratio, openStruct->fmt);
+ if (x)
+ {
+ m_video_output = 0;
+ userVideo = false;
+ return 0;
+ }
+ else*/
+ return 1;
+ }
+ case VIDUSER_CLOSEVIDEORENDERER:
+ close();
+ userVideo = false;
+ return 1;
+
+ case VIDUSER_GETPOPUPMENU:
+ return (INT_PTR)BuildPopupMenu();
+
+ case VIDUSER_SET_THREAD_SAFE:
+ input_plugin_thread_safe = !!param2;
+ break;
+ }
+ return 0;
+}
+
+int VideoOutput::get_latency()
+{
+ return config_video_vsync2 ? 15 : 0;
+}
+
+void VideoOutput::adjustAspect(RECT &rd)
+{
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::adjustAspect"));
+
+ if (posd->Showing() /*&& config_video_osd*/)
+ {
+ rd.top += posd->GetBarHeight();
+ rd.bottom -= posd->GetBarHeight();
+ }
+
+ if (config_video_aspectadj)
+ {
+ int outh = rd.bottom - rd.top;
+ int outw = rd.right - rd.left;
+
+ double outputaspect = aspect;
+
+ if (config_video_useratio && config_video_ratio1 && config_video_ratio2)
+ {
+ RECT r;
+ getViewport(&r, hVideoWindow, 1, NULL);
+ int screenx = r.right - r.left;
+ int screeny = r.bottom - r.top;
+
+ if (screenx && screeny)
+ {
+ outputaspect *= config_video_ratio1 * screeny / ((double)screenx * (double)config_video_ratio2);
+ }
+ }
+
+ int newh = (int)((outputaspect * height * outw) / (double)width);
+ int neww = (int)((width * outh) / (height * outputaspect));
+
+ if (outh > newh) // black bars on top and bottom
+ {
+ int d = outh - newh;
+ rd.top += d / 2;
+ rd.bottom -= d - d / 2;
+ }
+ else if (outw > neww) // black bars on left and right
+ {
+ int d = outw - neww;
+ rd.left += d / 2;
+ rd.right -= d - d / 2;
+ }
+ }
+}
+
+LRESULT CALLBACK VideoOutput::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+
+ if (uMsg == g_scrollMsg) // can't check against variables in case statements
+ {
+ wParam <<= 16;
+ uMsg = WM_MOUSEWHEEL;
+ }
+
+ if (FALSE != IsDirectMouseWheelMessage(uMsg))
+ {
+ SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+
+ switch (uMsg)
+ {
+ case WM_MOUSEWHEEL:
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+
+ case WM_CREATE:
+ {
+ VideoOutput *vid = (VideoOutput *)((CREATESTRUCT *)lParam)->lpCreateParams;
+ vid->video_hwnd = hwnd;
+ SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)vid);
+ }
+ return 0;
+ default: /// pass it on to the other window procedure
+ VideoOutput *_This = (VideoOutput*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
+ if (_This)
+ return _This->WindowProc(hwnd, uMsg, wParam, lParam);
+ else
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+}
+
+void VideoOutput::notifyBufferState(int bufferstate) /* 0-255*/
+{
+ m_bufferstate = bufferstate;
+ if (bufferstate == -1 || bufferstate == 255 || (GetTickCount() - m_lastbufinvalid > 500)) // don't want to do this too often
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::notifyBufferState"));
+ if (!m_video_output || !m_video_output->onPaint(video_hwnd))
+ InvalidateRect(video_hwnd, 0, TRUE);
+ m_lastbufinvalid = GetTickCount();
+ }
+}
+
+void VideoOutput::DrawLogo(HDC out, RECT *canvas_size)
+{
+ int bufferState = m_bufferstate;
+ if (m_logo && config_video_logo)
+ {
+ HDC dc = CreateCompatibleDC(NULL);
+ SelectObject(dc, m_logo);
+ int xp = (canvas_size->right - canvas_size->left - m_logo_w) / 2;
+ int yp = (canvas_size->bottom - canvas_size->top - m_logo_h) / 2;
+ BitBlt(out, xp, yp, m_logo_w, m_logo_h, dc, 0, 0, SRCCOPY);
+
+ if (bufferState != -1)
+ {
+ if (bufferState < 16) bufferState = 16;
+
+ HGDIOBJ oldobj1 = SelectObject(out, CreateSolidBrush(RGB(0, 0, 0)));
+ HGDIOBJ oldobj2 = SelectObject(out, CreatePen(PS_SOLID, 0, RGB(0, 0, 0)));
+ Rectangle(out, canvas_size->left, canvas_size->top, canvas_size->right, yp);
+ if (m_statusmsg)
+ Rectangle(out, canvas_size->left, yp + m_logo_h, canvas_size->right, canvas_size->bottom);
+ else
+ {
+ Rectangle(out, canvas_size->left, yp + m_logo_h + 2 + 9, canvas_size->right, canvas_size->bottom);
+ Rectangle(out, xp + ((bufferState *(m_logo_w + 2)) >> 8), yp + m_logo_h + 2, canvas_size->right, yp + 9 + m_logo_h + 2);
+ }
+ Rectangle(out, canvas_size->left, yp, xp - 1, yp + m_logo_h + 9 + 2);
+ Rectangle(out, xp + m_logo_w + 1, yp, canvas_size->right, yp + m_logo_h + 2);
+ DeleteObject(SelectObject(out, oldobj2));
+ DeleteObject(SelectObject(out, oldobj1));
+ }
+
+ if (m_statusmsg)
+ {
+ RECT subr = {0, yp + m_logo_h + 2, canvas_size->right, canvas_size->bottom};
+ SetTextColor(out, RGB(255, 255, 255));
+ SetBkMode(out, TRANSPARENT);
+ DrawTextA(out, m_statusmsg, -1, &subr, DT_TOP | DT_CENTER | DT_NOCLIP | DT_NOPREFIX);
+ }
+ else
+ {
+ yp += m_logo_h + 2;
+ if (bufferState)
+ {
+ HGDIOBJ oldobj1 = SelectObject(out, CreateSolidBrush(RGB(128, 128, 128)));
+ HGDIOBJ oldobj2 = SelectObject(out, CreatePen(PS_SOLID, 0, RGB(255, 255, 255)));
+ Rectangle(out, xp - 1, yp, xp + ((bufferState *(m_logo_w + 2)) >> 8), yp + 9);
+ DeleteObject(SelectObject(out, oldobj2));
+ DeleteObject(SelectObject(out, oldobj1));
+ }
+ }
+ DeleteDC(dc);
+ }
+}
+
+void VideoOutput::PaintLogo(int bufferState)
+{
+ // TODO: ask renderer to draw this shiz
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::PaintLogo"));
+
+ PAINTSTRUCT p;
+ BeginPaint(video_hwnd, &p);
+ RECT r;
+ GetClientRect(video_hwnd, &r);
+ HDC out = p.hdc;
+
+ HRGN hrgn = CreateRectRgnIndirect(&r);
+ HBRUSH b = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ FillRgn(out, hrgn, b);
+ DeleteObject(b);
+ DeleteObject(hrgn);
+
+ DrawLogo(out, &r);
+
+ EndPaint(video_hwnd, &p);
+}
+
+// the big window procedure
+LRESULT VideoOutput::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ // the follow messages are handled w/o a lock
+ switch (uMsg)
+ {
+ case WM_USER + 0x1:
+ m_need_change = true;
+ break;
+
+ case WM_USER + 0x2:
+ m_ignore_change = !!lParam;
+ break;
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case ID_VIDEOWND_VIDEOOPTIONS:
+ prefs_last_page = 24;
+ prefs_dialog(1);
+ break;
+
+ case ID_VID_AUDIO0:
+ case ID_VID_AUDIO1:
+ case ID_VID_AUDIO2:
+ case ID_VID_AUDIO3:
+ case ID_VID_AUDIO4:
+ case ID_VID_AUDIO5:
+ case ID_VID_AUDIO6:
+ case ID_VID_AUDIO7:
+ case ID_VID_AUDIO8:
+ case ID_VID_AUDIO9:
+ case ID_VID_AUDIO10:
+ case ID_VID_AUDIO11:
+ case ID_VID_AUDIO12:
+ case ID_VID_AUDIO13:
+ case ID_VID_AUDIO14:
+ case ID_VID_AUDIO15:
+ {
+ VideoOutput *out = (VideoOutput *)video_getIVideoOutput();
+ if (!out)
+ break;
+
+ out->getTrackSelector()->setAudioTrack(LOWORD(wParam) - ID_VID_AUDIO0);
+ break;
+ }
+ case ID_VID_VIDEO0:
+ case ID_VID_VIDEO1:
+ case ID_VID_VIDEO2:
+ case ID_VID_VIDEO3:
+ case ID_VID_VIDEO4:
+ case ID_VID_VIDEO5:
+ case ID_VID_VIDEO6:
+ case ID_VID_VIDEO7:
+ case ID_VID_VIDEO8:
+ case ID_VID_VIDEO9:
+ case ID_VID_VIDEO10:
+ case ID_VID_VIDEO11:
+ case ID_VID_VIDEO12:
+ case ID_VID_VIDEO13:
+ case ID_VID_VIDEO14:
+ case ID_VID_VIDEO15:
+ {
+ VideoOutput *out = (VideoOutput *)video_getIVideoOutput();
+ if (!out) break;
+ out->getTrackSelector()->setVideoTrack(LOWORD(wParam) - ID_VID_VIDEO0);
+ break;
+ }
+ }
+ break;
+ case WM_RBUTTONUP:
+ if (!is_fs)
+ {
+ POINT p;
+ GetCursorPos(&p);
+ DoTrackPopup(BuildPopupMenu(), TPM_RIGHTBUTTON | TPM_LEFTBUTTON, p.x, p.y, hwnd);
+ }
+ break;
+ case WM_LBUTTONDOWN: // putting this here prevents a deadlock, but allows a race condition over video drawing =(
+ {
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+
+ if (is_fs && config_video_osd)
+ {
+ if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
+ {
+ if (posd->MouseDown(x, y, wParam))
+ videoToggleFullscreen();
+ }
+ }
+ else
+ {
+ SetCapture(video_hwnd);
+ clickx = x;
+ clicky = y;
+ SetFocus(video_hwnd);
+ }
+ }
+ break;
+ case WM_MOUSEMOVE:
+ {
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+ if (is_fs && config_video_osd)
+ {
+ if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
+ {
+ posd->MouseMove(x, y, wParam);
+ }
+ }
+ else if (GetCapture() == video_hwnd && config_easymove)
+ {
+ POINT p = { x, y};
+ ClientToScreen(hVideoWindow, &p);
+ p.x -= clickx;
+ p.y -= clicky;
+ SendMessageW(hVideoWindow, WM_USER + 0x100, 1, (LPARAM)&p);
+ }
+ }
+ break;
+ case WM_LBUTTONUP:
+ {
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+ if (GetCapture() == video_hwnd)
+ ReleaseCapture();
+ if (is_fs && config_video_osd)
+ {
+ if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
+ if (posd->MouseUp(x, y, wParam))
+ videoToggleFullscreen();
+ }
+ SetFocus(hVideoWindow);
+ }
+ break;
+ }
+
+ switch (uMsg)
+ {
+ case WM_VIDEO_OSDCHANGE:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_VIDEO_OSDCHANGE"));
+ if (m_video_output)
+ {
+ m_video_output->Refresh();
+ m_video_output->timerCallback();
+ }
+ }
+ break;
+ case WM_SHOWWINDOW:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SHOWWINDOW"));
+ if (wParam == TRUE // being shown
+ && !m_logo) // logo hasn't been loaded yet
+ LoadLogo();
+ }
+ break;
+ case WM_INITMENUPOPUP:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_INITMENUPOPUP"));
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam); // for popup menus
+ }
+
+ case WM_WINDOWPOSCHANGED:
+ case WM_SIZE:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SIZE"));
+ if (m_video_output)
+ {
+ m_video_output->OnWindowSize();
+ if (is_fs)
+ if ( ((IVideoD3DOSD *)posd)->isOSDInited() )
+ ((IVideoD3DOSD *)posd)->UpdateOSD(hwnd, this);
+ }
+ }
+ break;
+
+ case WM_TIMER:
+ case WM_WINDOWPOSCHANGING:
+ case WM_MOVE:
+ case WM_MOVING:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_TIMER, etc"));
+ if (m_video_output && !m_ignore_change)
+ m_video_output->timerCallback();
+
+ if (uMsg == WM_TIMER)
+ return 0;
+ }
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_LBUTTONDBLCLK"));
+ videoToggleFullscreen();
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_PAINT"));
+ if (m_video_output && m_video_output->onPaint(hwnd))
+ return 0;
+ PaintLogo(m_bufferstate);
+ }
+
+ return 0;
+ break;
+
+ case WM_PRINTCLIENT:
+ {
+ //AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_PAINT"));
+ //if (m_video_output && m_video_output->onPaint(hwnd))
+ // return 0;
+ RECT r;
+ GetClientRect(video_hwnd, &r);
+ DrawLogo((HDC)wParam, &r);
+ }
+
+ return 0;
+ break;
+
+ case WM_KEYDOWN:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_KEYDOWN"));
+ if (wParam == VK_ESCAPE && is_fs)
+ {
+ videoToggleFullscreen();
+ //remove_fullscreen();
+ return 1;
+ }
+ if (!is_fs)
+ {
+ if (wParam == '3' || LOWORD(wParam) == 192 /* ` */)
+ {
+ SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM50, 0); return 0;
+ }
+ if (wParam == '1')
+ {
+ SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM100, 0); return 0;
+ }
+ if (wParam == '2')
+ {
+ SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM200, 0); return 0;
+ }
+ }
+ if (wParam == ' ')
+ {
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0); return 0;
+ }
+ if(wParam == 'F' && (GetAsyncKeyState(VK_SHIFT)&0x8000) && !(GetAsyncKeyState(VK_CONTROL)&0x8000))
+ {
+ SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_VERTICALLYFLIP, 0); return 0;
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_COMMAND"));
+ switch (LOWORD(wParam))
+ {
+ case ID_VIDEOWND_VERTICALLYFLIP:
+ {
+ int new_fliprgb = !config_video_fliprgb;//IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_FLIPRGB)?1:0;
+ config_video_fliprgb = 0;
+ videoSetFlip(new_fliprgb);
+ config_video_fliprgb = new_fliprgb;
+ break;
+ }
+
+ case ID_VIDEOWND_ZOOMFULLSCREEN:
+ videoGoFullscreen();
+ break;
+
+ case ID_VIDEOWND_ZOOM200:
+ case ID_VIDEOWND_ZOOM100:
+ case ID_VIDEOWND_ZOOM50:
+ if (m_video_output)
+ UpdateVideoSize(width, height, aspect, LOWORD(wParam));
+ else
+ UpdateVideoSize(320, 240, 1.0, LOWORD(wParam));
+ break;
+
+ default:
+ SendMessageW(hMainWindow, WM_COMMAND, wParam, lParam);
+ break;
+ }
+ }
+ break;
+
+ case WM_SETCURSOR:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SETCURSOR"));
+ if (is_fs)
+ {
+ SetCursor(posd->Showing() ? LoadCursor(NULL, IDC_ARROW) : NULL);
+ return TRUE;
+ }
+ else
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ {
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SYSCOMMAND"));
+ // eat screen saver message when fullscreen
+ if (((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER) && config_video_noss &&
+ video_isVideoPlaying())
+ {
+ return -1;
+ }
+ }
+ break;
+ }
+
+ if (m_msgcallback)
+ {
+ return m_msgcallback(m_msgcallback_tok, hwnd, uMsg, wParam, lParam);
+ }
+
+ return (DefWindowProc(hwnd, uMsg, wParam, lParam));
+}
+
+void VideoOutput::fullscreen()
+{
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::fullscreen"));
+ if (!m_video_output || !m_opened)
+ return ;
+
+ if (is_fs)
+ return ;
+
+ // TODO: let the video renderer handle fullscreen itself, if it can.
+
+ /*if (last_fullscreen_exit_time + 250 > GetTickCount()) // gay hack
+ return ; // dont let you go back and forth too quickly
+ */
+
+ GetWindowRect(hVideoWindow, &oldfsrect); // save the old coordinates
+ getViewport(&lastfsrect, video_hwnd, 1, NULL);
+ if (GetParent(hVideoWindow))
+ {
+ fs_reparented_rgn = CreateRectRgn(0, 0, 0, 0);
+ GetWindowRgn(hVideoWindow, fs_reparented_rgn);
+
+ fs_reparented = SetParent(hVideoWindow, NULL);
+ SetWindowRgn(hVideoWindow, NULL, FALSE);
+
+ ScreenToClient(fs_reparented, (LPPOINT)&oldfsrect);
+ ScreenToClient(fs_reparented, ((LPPOINT)&oldfsrect) + 1);
+ }
+
+ is_fullscreen_video = true;
+ is_fs = true;
+ //m_video_output->Fullscreen(true);
+ SetWindowPos(hVideoWindow, HWND_TOPMOST, lastfsrect.left, lastfsrect.top, lastfsrect.right - lastfsrect.left, lastfsrect.bottom - lastfsrect.top, SWP_DRAWFRAME | SWP_NOACTIVATE);
+ SetFocus(hVideoWindow);
+
+ resetSubtitle();
+}
+
+extern "C" HWND hExternalVisWindow;
+
+int VideoOutput::openUser(int w, int h, int vflip, double aspectratio, unsigned int fmt)
+{
+// TODO
+ return 1;
+}
+
+int VideoOutput::open(int w, int h, int vflip, double aspectratio, unsigned int fmt)
+{
+ if (!video_created)
+ SendMessageW(hVideoWindow, WM_VIDEO_CREATE, 0, 0);
+
+ if (!h || !w || !fmt) // check this after creating the video window. some plugins use this call to open the video output early
+ return 0;
+
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::open"));
+
+ if (!m_need_change)
+ stats.IncrementStat(Stats::VIDEOS_PLAYED);
+
+ if (hExternalVisWindow)
+ PostMessageW(hExternalVisWindow, WM_USER + 1666, 1, 15);
+
+ m_opened = false;
+ userVideo = false;
+ width = w;
+ height = h;
+
+ type = fmt;
+ aspect = aspectratio;
+ if (m_video_output)
+ {
+ if (type == VIDEO_MAKETYPE('N','O','N','E'))
+ {
+ m_opened = true;
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC);
+ OpenVideoSize(width, height, aspect);
+ fs_has_resized = is_fs;
+ return 0;
+ }
+ else if (m_video_output->OpenVideo(w, h, type, vflip, aspect))
+ {
+ if (video_palette)
+ m_video_output->setPalette(video_palette);
+ video_palette = 0;
+ DoTheVistaVideoDance();
+ InvalidateRect(video_hwnd, NULL, TRUE);
+ m_opened = true;
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC);
+ if (!m_need_change) //don't update size when renegotiating video output
+ {
+ OpenVideoSize(width, height, aspect);
+ fs_has_resized = is_fs;
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void VideoOutput::draw(void *frame)
+{
+ if (!frame)
+ return ;
+ AutoLock autoLock(guard LOCKNAME("VideoOutput::draw"));
+
+ if (m_video_output)
+ {
+ m_video_output->displayFrame((const char *)frame, 0, 0);
+ }
+}
+
+extern wchar_t draw_vw_info_lastb[512];
+
+void VideoOutput::close()
+{
+ UpdateText(L"");
+ AutoLock autoLock(guard);
+ if (!m_opened)
+ return ;
+ m_opened = false;
+ if (m_video_output)
+ {
+ m_video_output->drawSubtitle(0);
+ m_video_output->close();
+ }
+ m_bufferstate = -1;
+
+ draw_vw_info_lastb[0] = 0;
+ input_plugin_thread_safe = false; // reset this
+ InvalidateRect(video_hwnd, NULL, true);
+ PostMessageW(hVideoWindow, WM_VIDEO_CLOSE, 0, 0);
+}
+
+int VideoOutput::is_fullscreen()
+{
+ return is_fs;
+}
+
+void VideoOutput::showStatusMsg(const char *text)
+{
+ AutoLock autoLock(guard);
+ m_statusmsg = _strdup(text);
+ PaintLogo(m_bufferstate);
+ //InvalidateRect(video_hwnd, NULL, TRUE);
+}
+
+void VideoOutput::drawSubtitle(SubsItem *item)
+{
+ AutoLock autoLock(guard);
+ if (item == curSubtitle)
+ return ;
+ curSubtitle = item;
+
+ if (m_video_output)
+ m_video_output->drawSubtitle(item);
+}
+
+void VideoOutput::resetSubtitle()
+{
+ AutoLock autoLock(guard);
+ curSubtitle = NULL;
+ if (m_video_output)
+ m_video_output->resetSubtitle();
+ // InvalidateRect(this->getHwnd(), 0, TRUE);
+}
+
+void VideoOutput::remove_fullscreen()
+{
+ AutoLock autoLock(guard);
+ if (!is_fs)
+ {
+ is_fullscreen_video = false;
+ return ;
+ }
+
+ posd->Hide();
+ posd->ctrlrects_ready = 0; //tofix
+
+ if (m_video_output)
+ {
+ // m_video_output->Fullscreen(false);
+ }
+
+ resetSubtitle();
+
+ is_fs = 0;
+
+ if (fs_reparented)
+ {
+ SetParent(hVideoWindow, fs_reparented);
+ SetWindowRgn(hVideoWindow, fs_reparented_rgn, FALSE);
+ fs_reparented = 0;
+ SetWindowPos(hVideoWindow, HWND_TOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right - oldfsrect.left, oldfsrect.bottom - oldfsrect.top, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ else
+ SetWindowPos(hVideoWindow, config_aot ? HWND_TOPMOST : HWND_NOTOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right - oldfsrect.left, oldfsrect.bottom - oldfsrect.top, SWP_NOACTIVATE);
+
+ last_fullscreen_exit_time = GetTickCount();
+
+ posd->Hide();
+
+ if (!m_opened && m_video_output)
+ {
+ m_video_output->close();
+ }
+
+ is_fullscreen_video = false;
+
+ if (fs_has_resized)
+ {
+ fs_has_resized = false;
+ if (config_video_updsize)
+ UpdateVideoSize(width, height, aspect);
+ }
+}
+
+void VideoOutput::UpdateVideoSize(int newWidth, int newHeight, double newAspect, int zoom)
+{
+ if (!m_opened)
+ return;
+
+ // fill in default values if we have 0s
+ if (!newWidth)
+ newWidth = 320;
+ if (!newHeight)
+ newHeight = 240;
+
+ switch (zoom)
+ {
+ case ID_VIDEOWND_ZOOM200:
+ newWidth *= 2;
+ newHeight *= 2;
+ break;
+ case ID_VIDEOWND_ZOOM50:
+ newWidth /= 2;
+ newHeight /= 2;
+ break;
+ }
+
+ // establish a minimum window size
+ if (newWidth < 256)
+ newWidth = 256;
+ if (newHeight < 64)
+ newHeight = 64;
+
+ if (newAspect > 0.001) // floating point can be weird about checking == 0
+ {
+ if (newAspect < 1.0)
+ newWidth = (int)((double)newWidth / newAspect);
+ else
+ newHeight = (int)((double)newHeight * newAspect);
+ }
+
+ //SendNotifyMessage(hVideoWindow, WM_VIDEO_RESIZE, newWidth, newHeight);
+ PostMessageW(hVideoWindow, WM_VIDEO_RESIZE, newWidth, newHeight);
+}
+
+void VideoOutput::OpenVideoSize(int newWidth, int newHeight, double newAspect)
+{
+ // fill in default values if we have 0s
+ if (!newWidth)
+ newWidth = 320;
+ if (!newHeight)
+ newHeight = 240;
+
+ // establish a minimum window size
+ if (newWidth < 256)
+ newWidth = 256;
+ if (newHeight < 64)
+ newHeight = 64;
+
+ if (newAspect > 0.001) // floating point can be weird about checking == 0
+ {
+ if (newAspect < 1.0)
+ newWidth = (int)((double)newWidth / newAspect);
+ else
+ newHeight = (int)((double)newHeight * newAspect);
+ }
+
+ PostMessageW(hVideoWindow, WM_VIDEO_OPEN, newWidth, newHeight);
+}
+
+void VideoOutput::SetVideoPosition(int x, int y, int width, int height)
+{
+ AutoLock autoLock(guard);
+
+ SetWindowPos(getHwnd(), 0, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
+} \ No newline at end of file
diff --git a/Src/Winamp/VideoOutput.h b/Src/Winamp/VideoOutput.h
new file mode 100644
index 00000000..d50faa36
--- /dev/null
+++ b/Src/Winamp/VideoOutput.h
@@ -0,0 +1,97 @@
+#ifndef NULLSOFT_VIDEOOUTPUTH
+#define NULLSOFT_VIDEOOUTPUTH
+
+extern "C" {
+#include "main.h" // would rather not do this.
+};
+#include <ddraw.h>
+
+#include "../nu/AutoLock.h"
+
+#include "VideoOSD.h"
+#include "VideoAspectAdjuster.h"
+#include "vid_d3d.h"
+
+class VideoRenderer;
+
+extern IVideoOSD *posd;
+
+#define VIDEO_OPEN_
+
+#define SHOW_STREAM_TITLE_AT_TOP 1
+void ResizeVideoWindowToCurrent();
+void updateTrackSubmenu();
+using namespace Nullsoft::Utility;
+class VideoOutput : public IVideoOutput, public VideoAspectAdjuster
+{
+public:
+ VideoOutput(HWND parent_hwnd = NULL, int initxpos = CW_USEDEFAULT, int initypos = CW_USEDEFAULT);
+ ~VideoOutput();
+ int open(int w, int h, int vflip, double aspectratio, unsigned int fmt);
+ void close();
+ void draw(void *frame);
+ void drawSubtitle(SubsItem *item);
+ void showStatusMsg(const char *text);
+ void notifyBufferState(int bufferstate); /* 0-255*/
+ int get_latency();
+ void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { m_msgcallback_tok = token; m_msgcallback = msgcallback; }
+ void fullscreen();
+ void remove_fullscreen();
+ int is_fullscreen();
+ void adjustAspect(RECT &rd);
+ INT_PTR extended(INT_PTR param1, INT_PTR param2, INT_PTR param3);
+ int isVideoPlaying() { return m_opened; }
+ DWORD GetWidthHeightDWORD() { return width | (height << 16); }
+ ITrackSelector *getTrackSelector() { return m_tracksel; }
+ void SetVideoPosition(int x, int y, int width, int height);
+ HWND getHwnd() { return video_hwnd; }
+
+ void mainthread_Create();
+
+private:
+ void UpdateText(const wchar_t *videoInfo);
+
+ int openUser(int w, int h, int vflip, double aspectratio, unsigned int fmt);
+ void LoadLogo();
+ void OpenVideoSize(int newWidth, int newHeight, double newAspect);
+ VideoRenderer *FindBestRenderer();
+ void PaintLogo(int bufferState);
+ void DrawLogo(HDC canvas, RECT *canvas_size);
+ void resetSubtitle();
+ void UpdateVideoSize(int newWidth, int newHeight, double aspect = 1.0, int zoom = ID_VIDEOWND_ZOOM100);
+ bool is_fs, fs_has_resized;
+ unsigned int last_fullscreen_exit_time;
+ LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ static int class_refcnt;
+ static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ HWND video_hwnd;
+ double aspect;
+ int width, height;
+ unsigned int type;
+
+
+ RECT oldfsrect; // the old window rect, BEFORE fullscreen mode was entered
+ RECT lastfsrect; // the most recent bounding rect when in fullscreen mode
+ int m_bufferstate;
+ SubsItem *curSubtitle;
+ LRESULT (*m_msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void *m_msgcallback_tok;
+ Direct3DVideoOutput *m_video_output;
+ char *m_statusmsg;
+ bool m_need_change, m_ignore_change;
+ bool m_opened;
+ HBITMAP m_logo;
+ int m_logo_w, m_logo_h;
+ int m_lastbufinvalid;
+ HWND fs_reparented;
+ HRGN fs_reparented_rgn;
+ ITrackSelector *m_tracksel;
+ LockGuard guard, textGuard;
+ int clickx, clicky;
+ RGBQUAD *video_palette;
+// IVideoOSD osd;
+ bool userVideo;
+ bool video_created;
+};
+
+#endif
diff --git a/Src/Winamp/VideoOutputChild.cpp b/Src/Winamp/VideoOutputChild.cpp
new file mode 100644
index 00000000..bd3956d1
--- /dev/null
+++ b/Src/Winamp/VideoOutputChild.cpp
@@ -0,0 +1,2 @@
+#include "main.h"
+#include "VideoOutputChild.h"
diff --git a/Src/Winamp/VideoOutputChild.h b/Src/Winamp/VideoOutputChild.h
new file mode 100644
index 00000000..80bbdd57
--- /dev/null
+++ b/Src/Winamp/VideoOutputChild.h
@@ -0,0 +1,35 @@
+#ifndef NULLSOFT_VIDEOOUTPUTCHILDH
+#define NULLSOFT_VIDEOOUTPUTCHILDH
+
+
+class SubsItem;
+#include <windows.h>
+#include "VideoAspectAdjuster.h"
+
+/*
+ VideoRenderer is the base classes for the various video rendering classes
+*/
+
+class VideoRenderer
+{
+public:
+ virtual ~VideoRenderer()
+ {
+ }
+ virtual int create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int type, int flipit, double aspectratio) = 0; //return 1 if ok
+ virtual int needChange() = 0; //return 1 if need to renegociate video output
+ virtual int onPaint(HWND hwnd) { return 0; } //return 1 if override
+ virtual void displayFrame(const char *buf, int size, int time) = 0;
+ virtual void close()= 0; // hides any output of the video
+ virtual void timerCallback() { }
+ virtual void setPalette(RGBQUAD *pal) { }
+ virtual void drawSubtitle(SubsItem *item) { }
+ virtual void resetSubtitle() { }
+ virtual void setVFlip(int on) { }
+ virtual void Refresh()=0;
+
+};
+
+
+
+#endif
diff --git a/Src/Winamp/VideoOutputChildDDraw.cpp b/Src/Winamp/VideoOutputChildDDraw.cpp
new file mode 100644
index 00000000..470a86ce
--- /dev/null
+++ b/Src/Winamp/VideoOutputChildDDraw.cpp
@@ -0,0 +1,66 @@
+#include "main.h"
+#include "VideoOutputChildDDraw.h"
+#include <ddraw.h>
+
+class MonitorFinder
+{
+public:
+ MonitorFinder(HMONITOR hm) : m_monitor_to_find(hm), m_found_devguid(0)
+ {}
+
+ HMONITOR m_monitor_to_find;
+ int m_found_devguid;
+ GUID m_devguid;
+};
+
+static BOOL WINAPI DDEnumCallbackEx(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm)
+{
+ MonitorFinder *ovo = (MonitorFinder *)lpContext;
+ if (ovo->m_found_devguid) return 1;
+ if (hm == ovo->m_monitor_to_find)
+ {
+ ovo->m_devguid = *lpGUID;
+ ovo->m_found_devguid = 1;
+ }
+ return 1;
+}
+
+void VideoOutputChildDDraw::update_monitor_coords()
+{
+ //find the correct monitor if multiple monitor support is present
+ m_mon_x = 0;
+ m_mon_y = 0;
+
+ HMONITOR hm = MonitorFromWindow(parent, 0);
+ if (hm)
+ {
+ HINSTANCE hdd = LoadLibraryW(TEXT("ddraw.dll"));
+ if (hdd)
+ {
+ typedef BOOL (FAR PASCAL * LPDDENUMCALLBACKEXA)(GUID FAR *, LPSTR, LPSTR, LPVOID, HMONITOR);
+ typedef HRESULT (WINAPI * LPDIRECTDRAWENUMERATEEX)( LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags);
+ LPDIRECTDRAWENUMERATEEX lpDDEnumEx;
+ lpDDEnumEx = (LPDIRECTDRAWENUMERATEEX) GetProcAddress(hdd, "DirectDrawEnumerateExW");
+ if (lpDDEnumEx)
+ {
+ MonitorFinder finder(hm);
+
+ lpDDEnumEx(&DDEnumCallbackEx, &finder, DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES);
+ foundGUID=!!finder.m_found_devguid;
+ if (foundGUID)
+ {
+ m_devguid=finder.m_devguid;
+ MONITORINFOEXW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ if (GetMonitorInfoA(hm, &mi))
+ {
+ m_mon_x = mi.rcMonitor.left;
+ m_mon_y = mi.rcMonitor.top;
+ }
+ }
+ }
+ FreeLibrary(hdd);
+ }
+ }
+}
diff --git a/Src/Winamp/VideoOutputChildDDraw.h b/Src/Winamp/VideoOutputChildDDraw.h
new file mode 100644
index 00000000..f8d1bcf0
--- /dev/null
+++ b/Src/Winamp/VideoOutputChildDDraw.h
@@ -0,0 +1,22 @@
+#ifndef NULLSOFT_VIDEOOUTPUTCHILDDDRAWH
+#define NULLSOFT_VIDEOOUTPUTCHILDDDRAWH
+#include "VideoOutputChild.h"
+
+class VideoOutputChildDDraw : public VideoRenderer
+{
+public:
+ VideoOutputChildDDraw()
+ : adjuster(0), m_mon_x(0), m_mon_y(0), foundGUID(false), parent(0)
+ {
+ }
+ VideoAspectAdjuster *adjuster;
+ void update_monitor_coords();
+ int m_mon_x, m_mon_y;
+ bool foundGUID;
+ GUID m_devguid;
+ HWND parent;
+
+};
+
+
+#endif
diff --git a/Src/Winamp/VideoPreferences.cpp b/Src/Winamp/VideoPreferences.cpp
new file mode 100644
index 00000000..d54f8027
--- /dev/null
+++ b/Src/Winamp/VideoPreferences.cpp
@@ -0,0 +1,2 @@
+#include "Main.h"
+
diff --git a/Src/Winamp/W5S.cpp b/Src/Winamp/W5S.cpp
new file mode 100644
index 00000000..131fc438
--- /dev/null
+++ b/Src/Winamp/W5S.cpp
@@ -0,0 +1,226 @@
+#include "Main.h"
+#include "../Agave/Component/ifc_wa5component.h"
+#include <vector>
+#include "api.h"
+#include "LazyServiceFactory.h"
+
+extern LARGE_INTEGER freq;
+std::vector<ifc_wa5component*> systemComponents;
+std::vector<LazyServiceFactory*> lazyFactories;
+
+enum
+{
+ W5S_LOAD = 0,
+ W5S_LAZYLOAD = 1,
+};
+
+static uint32_t magic_word = 0xdeadbeefUL;
+/* layout (binary)
+0xdeadbeef - 32 bits
+service guid - 128 bits
+service fourcc - 32 bits
+length of service name - 16bits
+service name - see previous
+length of test string - 16 bits
+test string - see previous
+repeat as necessary
+*/
+static int w5s_load_binary_manifest(const wchar_t *filename, const wchar_t *w5s_filename)
+{
+ HANDLE manifest = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if (manifest != INVALID_HANDLE_VALUE)
+ {
+ for(;;)
+ {
+ uint32_t manifest_magic_word;
+ GUID service_guid;
+ FOURCC service_fourcc;
+
+ DWORD bytesRead=0;
+ ReadFile(manifest, &manifest_magic_word, sizeof(manifest_magic_word), &bytesRead, NULL);
+ if (bytesRead == 0) // EOF
+ {
+ CloseHandle(manifest);
+ return W5S_LAZYLOAD;
+ }
+
+ if (bytesRead != sizeof(manifest_magic_word) || memcmp(&manifest_magic_word, &magic_word, sizeof(magic_word)))
+ break;
+
+ bytesRead=0;
+ ReadFile(manifest, &service_guid, sizeof(service_guid), &bytesRead, NULL);
+ if (bytesRead != sizeof(service_guid))
+ break;
+
+ bytesRead=0;
+ ReadFile(manifest, &service_fourcc, sizeof(service_fourcc), &bytesRead, NULL);
+ if (bytesRead != sizeof(service_fourcc))
+ break;
+
+ uint16_t service_name_length;
+ bytesRead=0;
+ ReadFile(manifest, &service_name_length, sizeof(service_name_length), &bytesRead, NULL);
+ if (bytesRead != sizeof(service_name_length))
+ break;
+
+ char *service_name = 0;
+ if (service_name_length)
+ {
+ service_name = (char *)calloc(service_name_length + 1, sizeof(char));
+ if (service_name)
+ {
+ bytesRead=0;
+ ReadFile(manifest, service_name, service_name_length, &bytesRead, NULL);
+ if (bytesRead != service_name_length)
+ {
+ free(service_name);
+ break;
+ }
+ }
+ }
+
+ uint16_t service_test_string_length;
+ bytesRead=0;
+ ReadFile(manifest, &service_test_string_length, sizeof(service_test_string_length), &bytesRead, NULL);
+ if (bytesRead != sizeof(service_test_string_length))
+ break;
+
+ char *service_test_string = 0;
+ if (service_test_string_length)
+ {
+ service_test_string = (char *)calloc(service_test_string_length + 1, sizeof(char));
+ if (service_name)
+ {
+ bytesRead=0;
+ ReadFile(manifest, service_test_string, service_test_string_length, &bytesRead, NULL);
+ if (bytesRead != service_test_string_length)
+ {
+ free(service_name);
+ free(service_test_string);
+ break;
+ }
+ }
+ }
+
+ // if we got here, we're OK :)
+ LazyServiceFactory *factory = new LazyServiceFactory(service_fourcc, service_guid, service_name, service_test_string, w5s_filename);
+ lazyFactories.push_back(factory);
+ WASABI_API_SVC->service_register(factory);
+ }
+
+ // file seems to be malformed, go ahead and load w5s.
+ // any lazy factories we already loaded will self-destruct when the real services load
+ CloseHandle(manifest);
+ return W5S_LOAD;
+ }
+
+ return W5S_LOAD;
+}
+
+void w5s_load(const wchar_t *filename)
+{
+ HMODULE hLib = LoadLibraryW(filename);
+ if (hLib == NULL)
+ {
+ auto err = GetLastError();
+ }
+
+ if (hLib)
+ {
+ typedef ifc_wa5component *(*W5SGetter)();
+ W5SGetter pr = (W5SGetter)GetProcAddress(hLib,"GetWinamp5SystemComponent");
+ if (pr)
+ {
+ ifc_wa5component *mod = pr();
+ if (mod)
+ {
+ if (g_safeMode)
+ {
+ try
+ {
+ int retval = 0;
+ mod->_dispatch(15, &retval);
+ if (!retval)
+ {
+ FreeLibrary(hLib);
+ return;
+ }
+ }
+ catch(...)
+ {
+ FreeLibrary(hLib);
+ return;
+ }
+ }
+ systemComponents.push_back(mod);
+ mod->hModule = hLib;
+ mod->RegisterServices(WASABI_API_SVC);
+ }
+ }
+ }
+}
+
+void w5s_init()
+{
+ WIN32_FIND_DATAW d = {0};
+ wchar_t dirstr[MAX_PATH] = {0};
+
+ // pre-load so we're definitely available to other services which need this
+ PathCombineW(dirstr, SYSPLUGINDIR, L"wasabi2.w5s");
+ w5s_load(dirstr);
+
+ PathCombineW(dirstr, SYSPLUGINDIR, L"*.W5S");
+ HANDLE h = FindFirstFileW(dirstr, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ // due to how this plug-in works, is better to do a filename check to not load in
+ // safe mode as it otherwise causes the FreeLibrary(..) call to crash Winamp :o(
+ if (g_safeMode)
+ {
+ if (!wcsnicmp(d.cFileName, L"UnicodeTaskbarFix.w5s", 21)) continue;
+ if (!wcsnicmp(d.cFileName, L"fpl.w5s", 7)) continue;
+ if (!wcsnicmp(d.cFileName, L"mpcpl.w5s", 9)) continue;
+ }
+
+ if (lstrcmpiW(L"wasabi2.w5s", d.cFileName))
+ {
+ wchar_t manifeststr[MAX_PATH] = {0}, namestr[MAX_PATH] = {0};
+ PathCombineW(manifeststr, SYSPLUGINDIR, d.cFileName);
+ PathRemoveExtensionW(manifeststr);
+ PathAddExtensionW(manifeststr, L".wbm");
+ PathCombineW(namestr, SYSPLUGINDIR, d.cFileName);
+ if (w5s_load_binary_manifest(manifeststr, namestr) == W5S_LOAD)
+ {
+ w5s_load(namestr);
+ }
+ }
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+
+ Wasabi_FindSystemServices();
+}
+
+void w5s_deinit()
+{
+ Wasabi_ForgetSystemServices();
+
+ for ( ifc_wa5component *l_wa5_component : systemComponents )
+ {
+ l_wa5_component->DeregisterServices( WASABI_API_SVC );
+ l_wa5_component = 0;
+ }
+
+ systemComponents.clear();
+
+ //lazyFactories.deleteAll();
+ for ( auto obj : lazyFactories )
+ {
+ delete obj;
+ }
+
+ lazyFactories.clear();
+}
diff --git a/Src/Winamp/W5S.h b/Src/Winamp/W5S.h
new file mode 100644
index 00000000..5dd6bd15
--- /dev/null
+++ b/Src/Winamp/W5S.h
@@ -0,0 +1,2 @@
+#pragma once
+void w5s_load(const wchar_t *filename); \ No newline at end of file
diff --git a/Src/Winamp/WADrawDC.cpp b/Src/Winamp/WADrawDC.cpp
new file mode 100644
index 00000000..36d1af2e
--- /dev/null
+++ b/Src/Winamp/WADrawDC.cpp
@@ -0,0 +1,33 @@
+#include "draw.h"
+#include "WADrawDC.h"
+
+WADrawDC::WADrawDC(HWND _hwnd)
+{
+ hdc = draw_GetWindowDC(_hwnd);
+ hwnd=_hwnd;
+}
+
+WADrawDC::WADrawDC(HDC _hdc, HWND _hwnd)
+{
+ if (!_hdc)
+ {
+ hdc = draw_GetWindowDC(_hwnd);
+ hwnd=_hwnd;
+ }
+ else
+ {
+ hdc=_hdc;
+ hwnd=0; // set to 0 so we know not to call draw_ReleaseDC
+ }
+}
+
+WADrawDC::~WADrawDC()
+{
+ if (hwnd)
+ draw_ReleaseDC(hwnd,hdc);
+}
+
+WADrawDC::operator HDC()
+{
+ return hdc;
+} \ No newline at end of file
diff --git a/Src/Winamp/WADrawDC.h b/Src/Winamp/WADrawDC.h
new file mode 100644
index 00000000..94c90bae
--- /dev/null
+++ b/Src/Winamp/WADrawDC.h
@@ -0,0 +1,14 @@
+#pragma once
+#include <windows.h>
+
+class WADrawDC
+{
+public:
+ WADrawDC(HWND _hwnd);
+ WADrawDC(HDC _hdc, HWND _hwnd);
+ ~WADrawDC();
+ operator HDC();
+private:
+ HDC hdc;
+ HWND hwnd;
+}; \ No newline at end of file
diff --git a/Src/Winamp/WINAMP.sln b/Src/Winamp/WINAMP.sln
new file mode 100644
index 00000000..0ec29204
--- /dev/null
+++ b/Src/Winamp/WINAMP.sln
@@ -0,0 +1,122 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29424.173
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winampv6", "winampv6.vcxproj", "{7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F} = {A929EC04-302E-4B4F-B2A3-65AF63BB088F}
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ {255B68B5-7EF8-45EF-A675-2D6B88147909} = {255B68B5-7EF8-45EF-A675-2D6B88147909}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "albumart", "..\albumart\albumart.vcxproj", "{388476B7-C0A1-4853-B6F4-9A64CA346BA9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Elevator", "..\Elevator\Elevator.vcxproj", "{977153BF-8420-4C8D-AA25-592FAEDB6CBA}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F} = {A929EC04-302E-4B4F-B2A3-65AF63BB088F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ElevatorPS", "..\Elevator\ElevatorPS.vcxproj", "{A929EC04-302E-4B4F-B2A3-65AF63BB088F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "playlist", "..\playlist\playlist.vcxproj", "{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tataki", "..\tataki\tataki.vcxproj", "{255B68B5-7EF8-45EF-A675-2D6B88147909}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Debug|Win32.Build.0 = Debug|Win32
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Debug|x64.ActiveCfg = Debug|x64
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Debug|x64.Build.0 = Debug|x64
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Release|Win32.ActiveCfg = Release|Win32
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Release|Win32.Build.0 = Release|Win32
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Release|x64.ActiveCfg = Release|x64
+ {7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}.Release|x64.Build.0 = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.Build.0 = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.Build.0 = Release|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|Win32.Build.0 = Debug|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|x64.ActiveCfg = Debug|x64
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|x64.Build.0 = Debug|x64
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|Win32.ActiveCfg = Release|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|Win32.Build.0 = Release|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|x64.ActiveCfg = Release|x64
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|x64.Build.0 = Release|x64
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Debug|Win32.Build.0 = Debug|Win32
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Debug|x64.ActiveCfg = Debug|x64
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Debug|x64.Build.0 = Debug|x64
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Release|Win32.ActiveCfg = Release|Win32
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Release|Win32.Build.0 = Release|Win32
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Release|x64.ActiveCfg = Release|x64
+ {977153BF-8420-4C8D-AA25-592FAEDB6CBA}.Release|x64.Build.0 = Release|x64
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Debug|Win32.Build.0 = Debug|Win32
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Debug|x64.ActiveCfg = Debug|x64
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Debug|x64.Build.0 = Debug|x64
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Release|Win32.ActiveCfg = Release|Win32
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Release|Win32.Build.0 = Release|Win32
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Release|x64.ActiveCfg = Release|x64
+ {A929EC04-302E-4B4F-B2A3-65AF63BB088F}.Release|x64.Build.0 = Release|x64
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|Win32.Build.0 = Debug|Win32
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|x64.ActiveCfg = Debug|x64
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|x64.Build.0 = Debug|x64
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|Win32.ActiveCfg = Release|Win32
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|Win32.Build.0 = Release|Win32
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|x64.ActiveCfg = Release|x64
+ {B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|x64.Build.0 = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.ActiveCfg = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.Build.0 = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.ActiveCfg = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.Build.0 = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.ActiveCfg = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.Build.0 = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.ActiveCfg = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.Build.0 = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FC646532-2050-40A5-A2AB-F699F1C071C4}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Winamp/Wasabi.cpp b/Src/Winamp/Wasabi.cpp
new file mode 100644
index 00000000..5236ae50
--- /dev/null
+++ b/Src/Winamp/Wasabi.cpp
@@ -0,0 +1,292 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author: Ben Allison benski@nullsoft.com
+** Created:
+**/
+#include "Main.h"
+#include <api.h>
+
+#include "VideoFeedFactory.h"
+#include "TagProvider.h"
+#include "Singleton.h"
+#include "Random.h"
+#include "DecodeFile.h"
+#include "Language.h"
+#include "ExplorerFindFile.h"
+#include "../config/config.h"
+#include "JSAPI2_Security.h"
+#include "GammaManagerAPI.h"
+#include "PaletteManager.h"
+#include "../nu/ServiceWatcher.h"
+#include "JSAPI2_Creator.h"
+#include "stats.h"
+#include "../nu/Singleton.h"
+#include "handler.h"
+
+ServiceWatcher serviceWatcher;
+
+api_playlistmanager *playlistManager=0;
+api_playlists *AGAVE_API_PLAYLISTS=0;
+api_language *WASABI_API_LNG=0;
+api_downloadManager *WAC_API_DOWNLOADMANAGER=0;
+api_skin *WASABI_API_SKIN=0;
+api_amgsucks *AGAVE_API_AMGSUCKS=0;
+api_albumart *AGAVE_API_ALBUMART=0;
+// ----- Services -----
+api_service *serviceManager = 0;
+VideoTextFeed *videoTextFeed = 0;
+PlaylistTextFeed *playlistTextFeed = 0;
+TagProvider *tagProvider = 0;
+
+SysCallbacks *sysCallbacks = 0;
+MemoryManager *memoryManager = 0;
+GammaManagerAPI *gammaManager = 0;
+PaletteManager *paletteManager = 0;
+Metadata *metadata = 0;
+Application *application = 0;
+DecodeFile *decodeFile = 0;
+URLManager *AGAVE_API_URLMANAGER = 0;
+ThreadPool *WASABI_API_THREADPOOL = 0;
+WinampApi *WASABI_API_WINAMP = 0;
+
+Random random;
+WinampURIHandler winamp_uri_handler;
+Language *langManager = 0;
+ExplorerFindFile *explorerFindFileManager = 0;
+
+
+// ----- Service Factories -----
+static VideoTextFeedFactory *videoTextFeedFactory = 0;
+static PlaylistTextFeedFactory *playlistTextFeedFactory = 0;
+//TagProviderFactory *tagProviderFactory = 0;
+
+static Singleton2<api_syscb, SysCallbacks> syscbsvc;
+static Singleton2<api_config, Config> configSvc;
+Config config;
+static Singleton2<api_stats, Stats> statsSvc;
+// this class is using the RAII concept (resource allocation is initialization)
+// it registers services in its constructor, and deregisters in the destructor
+class WinampServices
+{
+public:
+ WinampServices() :
+ memoryManagerFactory(memoryManager),
+ metadataFactory(metadata),
+ applicationFactory(application),
+ randomFactory(&random, true),
+ decodeFileFactory(decodeFile),
+ languageFactory(langManager),
+ ExplorerFindFileFactory(explorerFindFileManager),
+ urlManagerFactory(AGAVE_API_URLMANAGER),
+ jsapi2_securityFactory(&JSAPI2::security, true),
+ gammaManagerFactory(gammaManager),
+ paletteManagerFactory(paletteManager),
+ threadPoolFactory(WASABI_API_THREADPOOL),
+ winampFactory(WASABI_API_WINAMP)
+ {
+ WASABI_API_SVC->service_register(&jsapi2_creator_factory);
+ WASABI_API_LNG = langManager;
+ uriHandlerFactory.Register(WASABI_API_SVC, &winamp_uri_handler);
+ }
+
+ ~WinampServices()
+ {
+ WASABI_API_SVC->service_deregister(&jsapi2_creator_factory);
+ uriHandlerFactory.Deregister(WASABI_API_SVC);
+ }
+
+ Singleton<api_memmgr, MemoryManager> memoryManagerFactory;
+ Singleton<api_metadata, Metadata> metadataFactory;
+ Singleton<api_application, Application> applicationFactory;
+ Singleton<api_random, Random> randomFactory;
+ Singleton<api_decodefile, DecodeFile> decodeFileFactory;
+ Singleton<api_language, Language> languageFactory;
+ Singleton<api_explorerfindfile, ExplorerFindFile> ExplorerFindFileFactory;
+ Singleton<api_urlmanager, URLManager> urlManagerFactory;
+ Singleton<JSAPI2::api_security, JSAPI2::Security> jsapi2_securityFactory;
+ Singleton<api_colorthemes, GammaManagerAPI> gammaManagerFactory;
+ Singleton<api_palette, PaletteManager> paletteManagerFactory;
+ Singleton<api_threadpool, ThreadPool> threadPoolFactory;
+ Singleton<api_winamp, WinampApi> winampFactory;
+
+ SingletonServiceFactory<svc_urihandler, WinampURIHandler> uriHandlerFactory;
+ JSAPI2CreatorFactory jsapi2_creator_factory;
+};
+
+WinampServices *services=0;
+namespace Wasabi
+{
+ bool loaded = false;
+}
+
+void Wasabi_Load()
+{
+ if (!Wasabi::loaded)
+ {
+ RegisterConfigGroups(); // TODO: this isn't the best place to set up this config stuff, but it's going here now 'cause it's convienent
+
+ serviceManager = new ServiceManager;
+ syscbsvc.RegisterNew(sysCallbacks);
+
+ configSvc.Register(&config);
+ statsSvc.Register(&stats);
+
+ services = new WinampServices();
+
+ videoTextFeed = new VideoTextFeed;
+ serviceManager->service_register(videoTextFeedFactory = new VideoTextFeedFactory);
+
+ playlistTextFeed = new PlaylistTextFeed;
+ serviceManager->service_register(playlistTextFeedFactory = new PlaylistTextFeedFactory);
+
+ tagProvider = new TagProvider;
+ //serviceManager->service_register(tagProviderFactory = new TagProviderFactory);
+
+ // watch for services that might be loaded later by plugins
+ serviceWatcher.WatchWith(serviceManager);
+ serviceWatcher.WatchFor(&WASABI_API_SKIN, skinApiServiceGuid);
+ // register for service callbacks in case any of these don't exist yet
+ WASABI_API_SYSCB->syscb_registerCallback(&serviceWatcher);
+
+ Wasabi::loaded = true;
+ }
+}
+
+void Wasabi_Unload()
+{
+ if (Wasabi::loaded)
+ {
+ //delete textFeeds;
+ //textFeeds=0;
+
+ serviceWatcher.StopWatching();
+ serviceWatcher.Clear();
+
+ // serviceManager->service_deregister(tagProviderFactory);
+ serviceManager->service_deregister(videoTextFeedFactory);
+ serviceManager->service_deregister(playlistTextFeedFactory);
+
+ // delete tagProviderFactory; tagProviderFactory = 0;
+ delete videoTextFeedFactory;
+ videoTextFeedFactory = 0;
+
+ delete playlistTextFeedFactory;
+ playlistTextFeedFactory = 0;
+
+ delete tagProvider;
+ tagProvider = 0;
+
+ delete videoTextFeed;
+ videoTextFeed = 0;
+
+ delete playlistTextFeed;
+ playlistTextFeed = 0;
+
+ WASABI_API_THREADPOOL->Kill();
+
+ delete services;
+
+ configSvc.Deregister();
+ statsSvc.Deregister();
+ syscbsvc.Deregister();
+
+ // delete this last
+ delete static_cast<ServiceManager *>(serviceManager);
+ serviceManager = 0;
+
+ Wasabi::loaded = false;
+ }
+}
+
+// other people's services that we might be interested in
+api_tagz *WINAMP5_API_TAGZ = 0;
+
+void Wasabi_FindSystemServices()
+{
+ waServiceFactory *sf;
+ sf = WASABI_API_SVC->service_getServiceByGuid(tagzGUID);
+ if (sf)
+ WINAMP5_API_TAGZ = (api_tagz *)sf->getInterface();
+
+ sf = WASABI_API_SVC->service_getServiceByGuid(api_playlistmanagerGUID);
+ if (sf)
+ AGAVE_API_PLAYLISTMANAGER = (api_playlistmanager *)sf->getInterface();
+
+ sf = WASABI_API_SVC->service_getServiceByGuid(DownloadManagerGUID);
+ if (sf)
+ WAC_API_DOWNLOADMANAGER = (api_downloadManager *)sf->getInterface();
+
+ sf = WASABI_API_SVC->service_getServiceByGuid(amgSucksGUID);
+ if (sf)
+ AGAVE_API_AMGSUCKS = (api_amgsucks *)sf->getInterface();
+
+ sf = WASABI_API_SVC->service_getServiceByGuid(api_playlistsGUID);
+ if (sf)
+ AGAVE_API_PLAYLISTS = (api_playlists *)sf->getInterface();
+
+ sf = WASABI_API_SVC->service_getServiceByGuid(albumArtGUID);
+ if (sf)
+ AGAVE_API_ALBUMART = (api_albumart *)sf->getInterface();
+}
+
+void Wasabi_ForgetSystemServices()
+{
+ waServiceFactory *sf;
+ if (WINAMP5_API_TAGZ)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(tagzGUID);
+ if (sf)
+ sf->releaseInterface(WINAMP5_API_TAGZ);
+ WINAMP5_API_TAGZ = 0;
+ }
+
+ if (AGAVE_API_PLAYLISTMANAGER)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(api_playlistmanagerGUID);
+ if (sf)
+ sf->releaseInterface(AGAVE_API_PLAYLISTMANAGER);
+ AGAVE_API_PLAYLISTMANAGER = 0;
+ }
+
+ if (WAC_API_DOWNLOADMANAGER)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(DownloadManagerGUID);
+ if (sf)
+ sf->releaseInterface(WAC_API_DOWNLOADMANAGER);
+ WAC_API_DOWNLOADMANAGER = 0;
+ }
+
+ if (WASABI_API_SKIN)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(skinApiServiceGuid);
+ if (sf)
+ sf->releaseInterface(WASABI_API_SKIN);
+ WASABI_API_SKIN = 0;
+ }
+
+ if (AGAVE_API_AMGSUCKS)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(amgSucksGUID);
+ if (sf)
+ sf->releaseInterface(AGAVE_API_AMGSUCKS);
+ AGAVE_API_AMGSUCKS = 0;
+ }
+
+ if (AGAVE_API_PLAYLISTS)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(api_playlistsGUID);
+ if (sf)
+ sf->releaseInterface(AGAVE_API_PLAYLISTS);
+ AGAVE_API_PLAYLISTS = 0;
+ }
+
+ if (AGAVE_API_ALBUMART)
+ {
+ sf = WASABI_API_SVC->service_getServiceByGuid(albumArtGUID);
+ if (sf)
+ sf->releaseInterface(AGAVE_API_ALBUMART);
+ AGAVE_API_ALBUMART = 0;
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/Wasabi.h b/Src/Winamp/Wasabi.h
new file mode 100644
index 00000000..06366664
--- /dev/null
+++ b/Src/Winamp/Wasabi.h
@@ -0,0 +1,7 @@
+#ifndef NULLSOFT_WASABIH
+#define NULLSOFT_WASABIH
+
+
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/WavEncoder.cpp b/Src/Winamp/WavEncoder.cpp
new file mode 100644
index 00000000..20645661
--- /dev/null
+++ b/Src/Winamp/WavEncoder.cpp
@@ -0,0 +1,375 @@
+#include "main.h"
+#include "../nsv/enc_if.h"
+
+#include <mmreg.h>
+#include <msacm.h>
+#include "WavEncoder.h"
+
+
+void initWfx();
+
+
+#define BUFSIZE 0x20000
+
+extern EXT_WFX convert_wfx;
+
+extern WAVEFORMATEX wfx_default;
+
+
+static DWORD FileTell(HANDLE hFile) { return SetFilePointer(hFile, 0, 0, FILE_CURRENT);}
+static void FileAlign(HANDLE hFile) {if (FileTell(hFile)&1) SetFilePointer(hFile, 1, 0, FILE_CURRENT);}
+
+
+#define rev32(X) ((((DWORD)(X)&0xFF)<<24)|(((DWORD)(X)&0xFF00)<<8)|(((DWORD)(X)&0xFF0000)>>8)|(((DWORD)(X)&0xFF000000)>>24))
+
+
+WavEncoder::WavEncoder(int srate, int nch, int bps, int res_srate , int res_bps, int res_nch )
+{
+ m_did_header = 0;
+ m_srate = srate;
+ m_nch = nch;
+ m_bps = bps;
+ m_error = 0;
+ hStream = 0;
+ hStreamResample = 0;
+ //_asm { int 3 };
+ m_acm_resample_buf = NULL;
+ m_acm_resample_outbuf = NULL;
+ m_bytes_done = 0;
+ m_hlen = 0;
+ m_nsam = 0;
+
+ if (res_srate && (res_srate != srate || res_bps != bps || res_nch != nch))
+ {
+ //manual resample (ie: burning)
+ m_acm_buf = (unsigned char *)malloc(BUFSIZE);
+ m_acm_outbuf = (unsigned char *)malloc(BUFSIZE);
+ m_bytes_inbuf = 0;
+ m_bytes_outbuf = 0;
+ m_wfx_src.wFormatTag = WAVE_FORMAT_PCM;
+ m_wfx_src.nChannels = nch;
+ m_wfx_src.nSamplesPerSec = srate;
+ m_wfx_src.nAvgBytesPerSec = srate * nch * (bps >> 3);
+ m_wfx_src.nBlockAlign = nch * (bps >> 3);
+ m_wfx_src.wBitsPerSample = bps;
+ m_wfx_src.cbSize = 0;
+ m_convert_wfx.wfx = wfx_default;
+ m_convert_wfx.wfx.nSamplesPerSec = res_srate;
+ m_convert_wfx.wfx.nChannels = res_nch;
+ m_convert_wfx.wfx.wBitsPerSample = res_bps;
+ m_convert_wfx.wfx.nAvgBytesPerSec = res_srate * res_nch * (res_bps / 8);
+ m_convert_wfx.wfx.nBlockAlign = res_nch * (res_bps / 8);
+ m_convert_wfx.wfx.cbSize = 0;
+ MMRESULT rs = acmStreamOpen(&hStream, 0, &m_wfx_src, &m_convert_wfx.wfx, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
+ if (rs || !hStream)
+ {
+ m_error = 1;
+ return ;
+ }
+ ZeroMemory(&ahd, sizeof(ahd));
+ ahd.cbStruct = sizeof(ahd);
+ ahd.pbSrc = m_acm_buf;
+ ahd.cbSrcLength = BUFSIZE;
+ ahd.pbDst = m_acm_outbuf;
+ ahd.cbDstLength = BUFSIZE;
+ if (acmStreamPrepareHeader(hStream, &ahd, 0)) m_error = 1;
+ return ;
+ }
+
+ //resample defined in config
+
+ // fucko: don't use compression settings if we're in a sep process, just generate raw wav
+ // sep process isn't the best way, but we'll give it a shot
+ if (!config_wav_convert)
+ {
+ m_acm_buf = NULL;
+ m_acm_outbuf = NULL;
+ }
+ else
+ {
+ m_acm_buf = (unsigned char *)malloc(BUFSIZE);
+ m_acm_outbuf = (unsigned char *)malloc(BUFSIZE);
+ m_bytes_inbuf = 0;
+ m_bytes_outbuf = 0;
+ initWfx();
+ m_convert_wfx = convert_wfx;
+
+ m_wfx_src.wFormatTag = WAVE_FORMAT_PCM;
+ m_wfx_src.nChannels = nch;
+ m_wfx_src.nSamplesPerSec = srate;
+ m_wfx_src.nAvgBytesPerSec = srate * nch * (bps >> 3);
+ m_wfx_src.nBlockAlign = nch * (bps >> 3);
+ m_wfx_src.wBitsPerSample = bps;
+ m_wfx_src.cbSize = 0;
+ MMRESULT rs = acmStreamOpen(&hStream, 0, &m_wfx_src, &m_convert_wfx.wfx, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
+ if (rs)
+ {
+ // need resampling
+ WAVEFORMATEX wfx1;
+ ZeroMemory(&wfx1, sizeof(wfx1));
+ wfx1.wFormatTag = WAVE_FORMAT_PCM;
+ if (acmFormatSuggest(0, &m_convert_wfx.wfx, &wfx1, sizeof(WAVEFORMATEX), ACM_FORMATSUGGESTF_WFORMATTAG)) m_error = 1;
+ else if (acmStreamOpen(&hStream, 0, &wfx1, &m_convert_wfx.wfx, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME)) m_error = 1;
+ else if (acmStreamOpen(&hStreamResample, 0, &m_wfx_src, &wfx1, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME)) m_error = 1;
+ else
+ {
+ ZeroMemory(&ahdResample, sizeof(ahdResample));
+ ahdResample.cbStruct = sizeof(ahdResample);
+ ahdResample.pbSrc = m_acm_resample_buf = (unsigned char *)malloc(BUFSIZE);
+ ahdResample.cbSrcLength = BUFSIZE;
+ ahdResample.pbDst = m_acm_resample_outbuf = (unsigned char *)malloc(BUFSIZE);
+ ahdResample.cbDstLength = BUFSIZE;
+ if (acmStreamPrepareHeader(hStreamResample, &ahdResample, 0)) m_error = 1;
+ m_bytes_inbuf_resample = 0;
+ m_bytes_outbuf_resample = 0;
+ }
+ }
+
+ if (!hStream)
+ {
+ m_error = 1;
+ return ;
+ }
+
+ ZeroMemory(&ahd, sizeof(ahd));
+ ahd.cbStruct = sizeof(ahd);
+ ahd.pbSrc = m_acm_buf;
+ ahd.cbSrcLength = BUFSIZE;
+ ahd.pbDst = m_acm_outbuf;
+ ahd.cbDstLength = BUFSIZE;
+ if (acmStreamPrepareHeader(hStream, &ahd, 0)) m_error = 1;
+ }
+}
+
+WavEncoder::~WavEncoder()
+{
+ free(m_acm_buf);
+ free(m_acm_outbuf);
+ free(m_acm_resample_buf);
+ free(m_acm_resample_outbuf);
+ if (hStream)
+ {
+ if (ahd.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) acmStreamUnprepareHeader(hStream, &ahd, 0);
+ acmStreamClose(hStream, 0);
+ }
+ if (hStreamResample)
+ {
+ if (ahdResample.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) acmStreamUnprepareHeader(hStreamResample, &ahdResample, 0);
+ acmStreamClose(hStreamResample, 0);
+ }
+}
+
+int WavEncoder::Encode(int framepos, void *in, int in_avail, int *in_used, void *out, int out_avail)
+{
+ char *pin = (char *)in;
+ char *pout = (char *)out;
+ int retval = 0;
+
+ if (!m_did_header && config_wav_do_header)
+ {
+ int s = 44;
+ if (hStream)
+ {
+ s = 4 + 4 + 12 - 4;
+
+ int t;
+ if (m_convert_wfx.wfx.wFormatTag == WAVE_FORMAT_PCM) t = 0x10;
+ else t = sizeof(WAVEFORMATEX) + m_convert_wfx.wfx.cbSize;
+ s += 4 + t;
+ if (s&1) s++;
+
+ if (m_convert_wfx.wfx.wFormatTag != WAVE_FORMAT_PCM)
+ s += 12;
+
+ s += 8;
+ }
+ if (out_avail < s) return 0;
+ //xx bytes of randomness
+ m_hlen = s;
+ m_did_header = 1;
+ out_avail -= s;
+ pout += s;
+ retval = s;
+ }
+
+ if (!hStream)
+ {
+ //no ACM conversion
+ int l = min(out_avail, in_avail);
+ memcpy(pout, pin, l);
+ *in_used = l;
+ m_bytes_done += l;
+ return l;
+ }
+
+ if (!m_bytes_outbuf)
+ {
+ if (hStreamResample)
+ {
+ if (!m_bytes_outbuf_resample)
+ {
+ DWORD flags = ACM_STREAMCONVERTF_BLOCKALIGN;
+
+ int l = min(in_avail, BUFSIZE - m_bytes_inbuf_resample);
+ if (l < 0) l = 0;
+ if (l > 0) memcpy(m_acm_resample_buf + m_bytes_inbuf_resample, in, l);
+ m_bytes_inbuf_resample += l;
+ *in_used = l;
+ m_nsam += l;
+
+ ahdResample.cbSrcLength = m_bytes_inbuf_resample;
+ acmStreamConvert(hStreamResample, &ahdResample, flags);
+ m_bytes_inbuf_resample -= ahdResample.cbSrcLengthUsed;
+ memcpy(m_acm_resample_buf, m_acm_resample_buf + ahdResample.cbSrcLengthUsed, m_bytes_inbuf_resample); //memmove
+ m_bytes_outbuf_resample = ahdResample.cbDstLengthUsed;
+ }
+ in = (void*)m_acm_resample_outbuf;
+ in_avail = m_bytes_outbuf_resample;
+ m_bytes_outbuf_resample = 0;
+ in_used = NULL;
+ }
+
+ DWORD flags = ACM_STREAMCONVERTF_BLOCKALIGN;
+
+ int l = min(in_avail, BUFSIZE - m_bytes_inbuf);
+ if (l < 0) l = 0;
+ if (l > 0) memcpy(m_acm_buf + m_bytes_inbuf, in, l);
+ m_bytes_inbuf += l;
+ if (in_used)
+ {
+ *in_used = l;
+ m_nsam += l;
+ }
+
+ if (m_bytes_inbuf)
+ {
+ ahd.cbSrcLength = m_bytes_inbuf;
+ acmStreamConvert(hStream, &ahd, flags);
+ m_bytes_inbuf -= ahd.cbSrcLengthUsed;
+ memcpy(m_acm_buf, m_acm_buf + ahd.cbSrcLengthUsed, m_bytes_inbuf); //memmove
+ m_bytes_outbuf = ahd.cbDstLengthUsed;
+ m_bytes_done += l;
+ }
+ }
+ if (m_bytes_outbuf)
+ {
+ int l = min(out_avail, m_bytes_outbuf);
+ memcpy(pout, m_acm_outbuf, l);
+ m_bytes_outbuf -= l;
+ memcpy(m_acm_outbuf, m_acm_outbuf + l, m_bytes_outbuf);
+ retval += l;
+ }
+
+ return retval;
+}
+
+void WavEncoder::FinishAudio(HANDLE fh, WavEncoder *coder)
+{
+ if (!config_wav_do_header) return ;
+
+ int len, i;
+ const unsigned char ispred1[4] = {0x52 , 0x49 , 0x46 , 0x46 };
+ const unsigned char ispred2[12] = {0x57, 0x41 , 0x56 , 0x45 , 0x66 , 0x6d , 0x74 , 0x20 , 0x10 , 0x0 , 0x0 , 0x0 };
+ char c;
+ int bps = coder->m_bps;
+ int srate = coder->m_srate;
+ int nch = coder->m_nch;
+ len = coder->m_bytes_done;
+ DWORD a;
+
+ FileAlign(fh);
+
+ SetFilePointer(fh, 0, 0, FILE_BEGIN);
+
+ WriteFile(fh, ispred1, sizeof(ispred1), &a, NULL);
+ i = len + (m_hlen) - 8;
+ if (i&1) i++;
+ WriteFile(fh, &i, 4, &a, NULL);
+ WriteFile(fh, ispred2, sizeof(ispred2) - (hStream ? 4 : 0), &a, NULL);
+ if (!hStream)
+ {
+ c = 1;
+ WriteFile(fh, &c, 1, &a, NULL);
+ c = 0;
+ WriteFile(fh, &c, 1, &a, NULL);
+ c = nch;
+ WriteFile(fh, &c, 1, &a, NULL);
+ c = 0;
+ WriteFile(fh, &c, 1, &a, NULL);
+ for (i = 0;i < 32;i += 8)
+ {
+ c = (srate >> i) & 0xff;
+ WriteFile(fh, &c, 1, &a, NULL);
+ }
+ int tmp = srate * nch * (bps / 8);
+ for (i = 0;i < 32;i += 8)
+ {
+ c = (tmp >> i) & 0xff;
+ WriteFile(fh, &c, 1, &a, NULL);
+ }
+ tmp = (bps / 8) * nch;
+ for (i = 0;i < 16;i += 8)
+ {
+ c = (tmp >> i) & 0xff;
+ WriteFile(fh, &c, 1, &a, NULL);
+ }
+ c = bps;
+ WriteFile(fh, &c, 1, &a, NULL);
+ c = 0;
+ WriteFile(fh, &c, 1, &a, NULL);
+
+ const unsigned char iza[4] = {0x64 , 0x61 , 0x74 , 0x61};
+ WriteFile(fh, iza, 4, &a, NULL);
+
+ for (i = 0;i < 32;i += 8)
+ {
+ c = (len >> i) & 0xff;
+ WriteFile(fh, &c, 1, &a, NULL);
+ }
+ }
+ else
+ {
+ int t;
+ if (m_convert_wfx.wfx.wFormatTag == WAVE_FORMAT_PCM) t = 0x10;
+ else t = sizeof(WAVEFORMATEX) + m_convert_wfx.wfx.cbSize;
+ WriteFile(fh, &t, 4, &a, 0);
+ WriteFile(fh, &m_convert_wfx.wfx, t, &a, 0);
+
+ FileAlign(fh);
+
+ DWORD fact_ofs = 0;
+ if (m_convert_wfx.wfx.wFormatTag != WAVE_FORMAT_PCM)
+ {
+ t = rev32('fact');
+ WriteFile(fh, &t, 4, &a, 0);
+ t = 4;
+ WriteFile(fh, &t, 4, &a, 0);
+ fact_ofs = FileTell(fh);
+ SetFilePointer(fh, 4, 0, FILE_CURRENT);
+ }
+
+ t = rev32('data');
+ WriteFile(fh, &t, 4, &a, 0);
+ DWORD data_ofs = FileTell(fh);
+
+ {
+ DWORD t, bw;
+ SetFilePointer(fh, 4, 0, FILE_BEGIN);
+ t = GetFileSize(fh, 0) - 8;
+ WriteFile(fh, &t, 4, &bw, 0);
+ DWORD data_size = GetFileSize(fh, 0) - (data_ofs + 4);
+ SetFilePointer(fh, data_ofs, 0, FILE_BEGIN);
+ WriteFile(fh, &data_size, 4, &bw, 0);
+ if (fact_ofs)
+ {
+ SetFilePointer(fh, fact_ofs, 0, FILE_BEGIN);
+ t = coder->m_nsam / ((coder->m_bps >> 3) * coder->m_nch);
+ WriteFile(fh, &t, 4, &bw, 0);
+ }
+ }
+
+ }
+}
+
+
+int WavEncoder::GetLastError() { return m_error; }
diff --git a/Src/Winamp/WavEncoder.h b/Src/Winamp/WavEncoder.h
new file mode 100644
index 00000000..0daba003
--- /dev/null
+++ b/Src/Winamp/WavEncoder.h
@@ -0,0 +1,48 @@
+#ifndef NULLSOFT_WAVENCODERH
+#define NULLSOFT_WAVENCODERH
+
+#include <mmreg.h>
+#include <msacm.h>
+#include "../nsv/enc_if.h"
+
+#define WFSIZ 0x800
+ struct EXT_WFX
+{
+ WAVEFORMATEX wfx;
+ BYTE crap[WFSIZ];
+};
+class WavEncoder : public AudioCoder
+{
+public:
+ WavEncoder(int srate, int nch, int bps, int res_srate = 0, int res_bps = 0, int res_nch = 0);
+ virtual ~WavEncoder();
+
+ virtual int Encode(int framepos, void *in, int in_avail, int *in_used, void *out, int out_avail);
+ void FinishAudio(HANDLE fh, WavEncoder *coder);
+
+ int GetLastError();
+
+ int m_did_header;
+ int m_nch, m_srate, m_bps;
+ int m_bytes_done;
+ int m_error;
+ int m_hlen;
+ int m_nsam;
+
+
+ EXT_WFX m_convert_wfx;
+
+ WAVEFORMATEX m_wfx_src;
+ HACMSTREAM hStream, hStreamResample;
+
+ ACMSTREAMHEADER ahd, ahdResample;
+
+ unsigned char *m_acm_buf, *m_acm_outbuf;
+ int m_bytes_inbuf, m_bytes_outbuf;
+ unsigned char *m_acm_resample_buf, *m_acm_resample_outbuf;
+ int m_bytes_inbuf_resample, m_bytes_outbuf_resample;
+
+};
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/Winamp.rc b/Src/Winamp/Winamp.rc
new file mode 100644
index 00000000..303c1ddb
--- /dev/null
+++ b/Src/Winamp/Winamp.rc
@@ -0,0 +1,2807 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "wasabicfg.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_PLATE BITMAP "resource/djegg.bmp"
+
+IDB_MAINBITMAP BITMAP "resource/main.bmp"
+
+IDB_CBUTTONS BITMAP "resource/cbuttons.bmp"
+
+IDB_MONOSTEREO BITMAP "resource/monoster.bmp"
+
+IDB_PLAYPAUSE BITMAP "resource/playpaus.bmp"
+
+IDB_SHUFFLEREP BITMAP "resource/shufrep.bmp"
+
+IDB_NUMBERS1 BITMAP "resource/numbers.bmp"
+
+IDB_VOLBAR BITMAP "resource/volume.bmp"
+
+IDB_FONT1 BITMAP "resource/text.bmp"
+
+IDB_POSBAR BITMAP "resource/posbar.bmp"
+
+IDB_TB BITMAP "resource/titlebar.bmp"
+
+IDB_EQMAIN BITMAP "resource/eqmain.bmp"
+
+IDB_PANBAR BITMAP "resource/balance.bmp"
+
+IDB_PLEDIT BITMAP "resource/pledit.bmp"
+
+IDB_EQEX BITMAP "resource/eq_ex.bmp"
+
+IDB_SPLASH BITMAP "resource/splash2.bmp"
+
+IDB_VIDEOLOGO BITMAP "resource/video_logo.bmp"
+
+IDB_VIDEO BITMAP "resource/video.bmp"
+
+IDB_EMBEDWND BITMAP "resource/gen.bmp"
+
+IDB_GENEX BITMAP "resource/genex.bmp"
+
+IDB_TEAM BITMAP "resource/team.bmp"
+
+IDB_EQMAIN_ISO BITMAP "resource/Eqmain_ISO.bmp"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_SPLASH DIALOGEX 0, 0, 202, 111
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL IDB_SPLASH,IDC_SPLASHIMG,"Static",SS_BITMAP,0,0,267,144
+END
+
+IDD_NEWABOUT1 DIALOGEX 0, 0, 301, 207
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "",IDC_ABOUTIMG,"Static",SS_BLACKRECT | SS_CENTERIMAGE,0,0,301,178
+ CTEXT "Copyright © 1997-2023 Winamp SA",IDC_STATIC,0,179,301,8,SS_NOTIFY
+ CTEXT "v%s %s - %s",IDC_ABOUTTEXT,0,188,301,8,SS_CENTERIMAGE
+ RTEXT "Visit ",IDC_STATIC,89,197,20,8
+ CONTROL "www.winamp.com",IDC_WINAMPLINK,"Button",BS_OWNERDRAW | BS_CENTER | BS_VCENTER | BS_FLAT | WS_TABSTOP,108,195,61,11
+ LTEXT " for updates.",IDC_STATIC,168,197,45,8
+END
+
+IDD_LOADPRESET DIALOGEX 0, 0, 171, 156
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+CAPTION "Load EQ preset"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LISTBOX IDC_LOADEQLIST,7,7,157,128,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Load",IDOK,26,139,60,13
+ PUSHBUTTON "&Cancel",IDCANCEL,97,139,47,13
+END
+
+IDD_SAVEPRESET DIALOGEX 0, 0, 171, 161
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+CAPTION "Save EQ preset"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LISTBOX IDC_LOADEQLIST,7,7,157,113,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ EDITTEXT IDC_SAVEPRESET_EDIT,7,122,157,13,ES_AUTOHSCROLL
+ PUSHBUTTON "&Save",IDOK,30,142,47,14
+ PUSHBUTTON "&Cancel",IDCANCEL,93,142,47,14
+END
+
+IDD_OPENLOC DIALOGEX 0, 0, 186, 68
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Open URL"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "Enter a URL to open here:\nFor example: http://www.server.com/file.mp3",IDC_STATIC,7,7,162,18
+ COMBOBOX IDC_URL_NEW,7,28,171,115,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "&Open",IDOK,7,47,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,61,47,50,14
+ PUSHBUTTON "&Reset...",IDRESET,128,47,50,14
+END
+
+IDD_JUMPDLG DIALOGEX 0, 0, 142, 78
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CAPTION | WS_SYSMENU
+CAPTION "Jump to time"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ GROUPBOX "Jump to:",IDC_STATIC,7,7,128,45
+ EDITTEXT IDC_MINUTES,11,17,43,12,ES_AUTOHSCROLL
+ LTEXT "Minutes:Seconds",IDC_STATIC,59,19,56,8
+ LTEXT "Track length:",IDC_STATIC,19,35,43,8
+ LTEXT "0:00",IDC_TRACKLEN,65,35,38,8
+ PUSHBUTTON "&Jump",IDOK,7,57,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,65,57,50,14
+END
+
+IDD_JUMPFILEDLG DIALOGEX 0, 0, 258, 207
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CAPTION | WS_SYSMENU
+CAPTION "Jump to file"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_EDIT1,13,17,231,14,ES_AUTOHSCROLL
+ LISTBOX IDC_SELBOX,7,43,244,139,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Cancel",IDCANCEL,7,186,244,14
+ GROUPBOX "Search for text",IDC_STATIC,7,7,244,30
+END
+
+IDD_EDITENTRY DIALOGEX 0, 0, 241, 62
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit playlist entry"
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ LTEXT "Old",IDC_STATIC,9,10,12,8
+ EDITTEXT IDC_OLD,28,7,206,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP
+ LTEXT "New",IDC_STATIC,9,25,16,8
+ EDITTEXT IDC_NEW,28,22,206,14,ES_AUTOHSCROLL
+ PUSHBUTTON "&OK",IDOK,7,41,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,61,41,50,14
+END
+
+IDD_HTTPGET DIALOGEX 0, 0, 186, 65
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Retrieving file..."
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_URL,7,6,172,21,ES_MULTILINE | ES_READONLY
+ LTEXT "...",IDC_STATUS,7,27,172,19,SS_SUNKEN
+ PUSHBUTTON "Abort",IDCANCEL,7,47,50,11
+END
+
+IDD_NEWPREFS DIALOGEX 0, 0, 386, 256
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Winamp Preferences"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "Tree1",IDC_TREE1,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_BORDER | WS_HSCROLL | WS_TABSTOP,5,5,99,229
+ DEFPUSHBUTTON "Close",IDOK,5,238,99,13
+ CONTROL "",IDC_RECT,"Static",SS_BLACKRECT | NOT WS_VISIBLE,110,5,272,246
+END
+
+IDD_NEWFTYPES DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "File Types",IDC_STATIC,0,0,272,246
+ GROUPBOX "Associated File Types",IDC_STATIC,5,11,130,230
+ LISTBOX IDC_FTYPE_LIST,11,24,54,211,LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Set selection:",IDC_STATIC,70,23,44,8
+ PUSHBUTTON "All",IDC_SELALL,70,33,60,13,BS_CENTER | BS_MULTILINE
+ PUSHBUTTON "Audio Only",IDC_SELALL2,70,50,60,13,BS_CENTER | BS_MULTILINE
+ PUSHBUTTON "Video Only",IDC_SELALL3,70,66,60,13,BS_CENTER | BS_MULTILINE
+ PUSHBUTTON "None",IDC_SELNONE,70,82,60,13,BS_CENTER | BS_MULTILINE
+ CONTROL "Restore file associations on Winamp start",IDC_RSTART,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,70,101,62,26
+ GROUPBOX "File Icon",IDC_STATIC,70,132,59,50,BS_CENTER
+ CONTROL "Slider1",IDC_FILETYPES_ICONSCROLL,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | WS_GROUP | WS_TABSTOP,80,140,13,40
+ ICON IDI_FILEICON,IDC_FILETYPES_ICON,99,151,20,20,NOT WS_VISIBLE
+ GROUPBOX "Playlist Icon",IDC_STATIC,70,186,59,50,BS_CENTER
+ CONTROL "Slider1",IDC_FILETYPES_ICONSCROLL2,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | WS_GROUP | WS_TABSTOP,80,194,13,40
+ ICON IDI_FILEICON,IDC_FILETYPES_ICON2,99,204,20,20,NOT WS_VISIBLE
+ GROUPBOX "Windows Explorer Settings",IDC_STATIC,141,11,124,57
+ CONTROL "Enqueue files on double click\n(default is unchecked)",IDC_ADDFILES,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,148,24,110,18
+ CONTROL "Show Winamp actions in the folder context menus",IDC_DIRCONTEXT,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,148,45,110,18
+ GROUPBOX "Audio CDs",IDC_STATIC,141,72,124,28
+ CONTROL "Launch Winamp for Audio CDs",IDC_CD,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,148,84,110,10
+ GROUPBOX "Winamp Agent",IDC_WATEXT2,141,104,124,86
+ CONTROL "Enable Winamp agent",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,148,116,84,10
+ LTEXT "Winamp Agent will allow you to start Winamp if it is not already running, allow quick access to bookmarks, etc and show an icon in the notification area.",IDC_WATEXT1,148,130,108,41
+ CONTROL "Show icon in notification area",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,175,109,10
+ LTEXT "Tip: Hold down the 'Control' key down when closing this preference page to force a refresh of the file associations.",IDC_STATIC,141,204,124,36
+END
+
+IDD_WIN8_FTYPES DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "File Types",IDC_STATIC,0,0,272,246
+ GROUPBOX "Recognized File Types",IDC_STATIC,5,11,130,230
+ LTEXT "To associate files with Winamp you need to use ",IDC_STATIC,11,24,119,16
+ CONTROL "Set Default Programs",IDC_SET_DEF_PROGRAM,"Button",BS_OWNERDRAW | WS_TABSTOP,51,32,75,10,WS_EX_TRANSPARENT
+ LISTBOX IDC_FTYPE_LIST,11,46,54,176,LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "This list shows all of the supported file extensions which can be associated with Winamp via the link shown above.",IDC_STATIC,70,60,60,62
+ GROUPBOX "File Icon",IDC_STATIC,70,132,59,50,BS_CENTER
+ CONTROL "Slider1",IDC_FILETYPES_ICONSCROLL,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | WS_GROUP | WS_TABSTOP,80,140,13,40
+ ICON IDI_FILEICON,IDC_FILETYPES_ICON,99,151,20,20,NOT WS_VISIBLE
+ GROUPBOX "Playlist Icon",IDC_STATIC,70,186,59,50,BS_CENTER
+ CONTROL "Slider1",IDC_FILETYPES_ICONSCROLL2,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | WS_GROUP | WS_TABSTOP,80,194,13,40
+ ICON IDI_FILEICON,IDC_FILETYPES_ICON2,99,204,20,20,NOT WS_VISIBLE
+ PUSHBUTTON "Refresh",IDC_REFRESH,11,222,54,13,BS_CENTER | BS_MULTILINE
+ GROUPBOX "Windows Explorer Settings",IDC_STATIC,141,11,124,57
+ CONTROL "Enqueue files on double click\n(default is unchecked)",IDC_ADDFILES,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,148,24,110,18
+ CONTROL "Show Winamp actions in the folder context menus",IDC_DIRCONTEXT,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,148,45,110,18
+ GROUPBOX "Audio CDs",IDC_STATIC,141,72,124,28
+ CONTROL "Launch Winamp for Audio CDs",IDC_CD,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,148,84,110,10
+ GROUPBOX "Winamp Agent",IDC_WATEXT2,141,104,124,86
+ CONTROL "Enable Winamp agent",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,148,116,84,10
+ LTEXT "Winamp Agent will allow you to start Winamp if it is not already running, allow quick access to bookmarks, etc and show an icon in the notification area.",IDC_WATEXT1,148,130,108,41
+ CONTROL "Show icon in notification area",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,175,109,10
+ LTEXT "Tip: Hold down the 'Control' key down when closing this preference page to force a refresh of the file associations.",IDC_STATIC,141,204,124,36
+END
+
+IDD_NEWPLUG DIALOGEX 0, 0, 272, 247
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Plug-in settings",IDC_STATIC,0,0,272,246
+ GROUPBOX "Visualization Plug-ins",IDC_STATIC,5,11,260,82
+ LTEXT "Visualization plug-in directory:",IDC_STATIC,13,24,96,8
+ PUSHBUTTON "",IDC_VISDIR,113,22,146,13
+ LTEXT "Visualization plug-in priority:",IDC_STATIC,13,42,98,8
+ CONTROL "Slider1",IDC_VISPRIO,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,113,41,96,10
+ LTEXT "Idle",IDC_STATIC,117,52,14,8
+ LTEXT "Normal",IDC_STATIC,151,52,23,8
+ LTEXT "High",IDC_STATIC,191,52,16,8
+ CONTROL "&Auto execute visualization plug-in on playback",IDC_AUTOEXEC,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,64,163,10
+ CONTROL "&Disable built-in visualization when visualization plug-in active",IDC_DISVIS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,77,207,10
+ GROUPBOX "DSP/Effect plug-in directory",IDC_STATIC,5,96,260,30
+ PUSHBUTTON "",IDC_DSPDIR,11,107,248,13
+ GROUPBOX "Plug-in Developers",IDC_STATIC,5,129,260,53
+ CONTROL "Disable SEH for general purpose plug-ins",IDC_CHECK5,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,141,145,10
+ CONTROL "Disable SEH for visualization plug-ins",IDC_CHECK1,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,154,132,10
+ CONTROL "Disable SEH for DSP plug-ins",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,167,106,10
+ GROUPBOX "Safe Mode",IDC_STATIC,5,186,260,50
+ LTEXT "Using 'Safe Mode' will prevent the loading of 3rd party plug-ins and all detected Visualization and DSP plug-ins.",IDC_STATIC,12,198,186,18
+ PUSHBUTTON "Restart in\nSafe Mode",IDC_SAFEMODE,203,196,56,22,BS_MULTILINE
+ CONTROL "Always run Winamp in 'Safe Mode'",IDC_SAFEMODEALWAYS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,219,125,10
+END
+
+IDD_NEWINPUT DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Input plug-ins",IDC_STATIC,0,0,272,246
+ LTEXT "The plug-ins below allow Winamp to play the various media types that it does. You can select a plug-in and configure, view about boxes, or uninstall them.",IDC_STATIC,6,12,257,17
+ LISTBOX IDC_INPUTS,5,35,260,189,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Configure",IDC_CONF,5,228,50,13,WS_DISABLED
+ PUSHBUTTON "&About",IDC_ABOUT,59,228,50,13,WS_DISABLED
+ PUSHBUTTON "&Uninstall plug-in",IDC_UNINSTINPUT,113,228,62,13,WS_DISABLED
+ CONTROL "Get plug-ins",IDC_PLUGINVERS,"Button",BS_OWNERDRAW | WS_TABSTOP,224,230,41,9
+END
+
+IDD_NEWOUTPUT DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Output plug-ins",IDC_STATIC,0,0,272,246
+ LTEXT "The plug-in selected below determines how Winamp plays audio. If you select a plug-in, Winamp will use it (starting with the next item played) for audio output.",IDC_STATIC,6,12,257,17
+ LISTBOX IDC_OUTPUTS,5,35,260,189,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Configure",IDC_CONF2,5,228,50,13,WS_DISABLED
+ PUSHBUTTON "&About",IDC_ABOUT2,59,228,50,13,WS_DISABLED
+ PUSHBUTTON "&Uninstall plug-in",IDC_UNINSTOUT,113,228,62,13,WS_DISABLED
+ CONTROL "Get plug-ins",IDC_PLUGINVERS,"Button",BS_OWNERDRAW | WS_TABSTOP,224,230,41,9
+END
+
+IDD_NEWVIS DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Visualization plug-ins",IDC_STATIC,0,0,272,246
+ LTEXT "Select a visualization plug-in below. The selected plug-in can be launched using the 'Start' button below, or by using Ctrl+Shift+K from Winamp.",IDC_STATIC,6,12,257,17
+ LISTBOX IDC_VISLIB,5,35,260,173,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Plug-in module:",IDC_STATIC,7,213,50,8
+ COMBOBOX IDC_VISMOD,61,211,204,143,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Start",IDC_VISTEST,5,228,36,13
+ PUSHBUTTON "&Stop",IDC_VISSTOP,45,228,36,13
+ PUSHBUTTON "&Configure",IDC_VISCONF,85,228,48,13
+ PUSHBUTTON "&Uninstall plug-in",IDC_UNINSTVIS,137,228,62,13
+ CONTROL "Get plug-ins",IDC_PLUGINVERS,"Button",BS_OWNERDRAW | WS_TABSTOP,224,230,41,9
+END
+
+IDD_NEWDSP DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "DSP/Effect plug-in",IDC_STATIC,0,0,272,246
+ LTEXT "The plug-in selected below will be active, and will usually modify the sound being played. Select (none) if you do not wish to use a DSP/Effect plug-in.",IDC_STATIC,5,12,261,17
+ LISTBOX IDC_DSPLIB,5,35,260,173,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Plug-in module:",IDC_PLUGINLABEL,7,213,50,8,WS_DISABLED
+ COMBOBOX IDC_DSPMOD,61,211,204,64,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Configure active plug-in",IDC_DSPCONF,5,228,90,13,WS_DISABLED
+ PUSHBUTTON "&Uninstall plug-in",IDC_UNINSTDSP,99,228,62,13,WS_DISABLED
+ CONTROL "Get plug-ins",IDC_PLUGINVERS,"Button",BS_OWNERDRAW | WS_TABSTOP,224,230,41,9
+END
+
+IDD_NEWGEN DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "General purpose plug-ins",IDC_STATIC,0,0,272,246
+ LTEXT "Installed general purpose plug-ins (loaded at startup):",IDC_STATIC,6,12,251,8
+ LISTBOX IDC_GENLIB,5,26,259,198,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Configure selected plug-in",IDC_GENCONF,5,228,96,13,WS_DISABLED
+ PUSHBUTTON "Uninstall selected plug-in",IDC_UNINST,105,228,90,13,WS_DISABLED
+ CONTROL "Get plug-ins",IDC_PLUGINVERS,"Button",BS_OWNERDRAW | WS_TABSTOP,224,230,41,9
+END
+
+IDD_NEWSKIN DIALOGEX 0, 0, 273, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Skins",IDC_STATIC,0,0,272,246
+ LTEXT "Installed skins:",IDC_STATIC,6,12,47,8
+ LISTBOX IDC_SELBOX,6,26,174,152,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "Set skins directory...",IDC_CHDIR,185,26,80,15,BS_CENTER | BS_VCENTER | BS_MULTILINE | NOT WS_TABSTOP
+ CONTROL "&Random skin on play",IDC_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,185,45,81,10
+ CONTROL "&Prompt on install",IDC_SKIN_INSTALL_PROMPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,185,58,81,10
+ PUSHBUTTON "Re&name current skin...",IDC_RENAME_SKIN,185,102,80,15,WS_DISABLED
+ PUSHBUTTON "&Uninstall current skin...",IDC_DELETE_SKIN,185,120,80,14,WS_DISABLED
+ LTEXT "To uninstall / rename a skin without switching skins, right click on the skin you wish to uninstall or rename.",IDC_STATIC,186,137,79,41
+ LTEXT "Current skin information:",IDC_STATIC,6,182,82,8
+ EDITTEXT IDC_EDIT1,6,194,174,45,ES_MULTILINE | ES_READONLY | WS_VSCROLL
+ CONTROL "Get skins",IDC_WINAMPLINK,"Button",BS_OWNERDRAW | BS_CENTER | BS_VCENTER,224,230,41,9
+END
+
+IDD_CLASSIC_VIS DIALOGEX 0, 0, 260, 196
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Classic Visualization Settings",IDC_STATIC,4,3,256,76
+ LTEXT "Winamp Classic skins have a simple visualization in the main window. You can select what kind of visualization here, or click on the visualization to cycle through the modes.",IDC_STATIC,11,15,241,25
+ CONTROL "Spectrum analyzer",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,12,45,74,10
+ CONTROL "Oscilliscope",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,100,45,53,10
+ CONTROL "No visualization",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,172,45,65,10
+ LTEXT "Visualization refresh rate:",IDC_STATIC,11,62,85,8
+ CONTROL "Slider1",IDC_SLIDER3,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,104,61,119,10
+ LTEXT "70fps",IDC_RRATE,227,62,18,8
+ GROUPBOX "Spectrum Analyzer Options",IDC_STATIC,4,82,256,85,BS_LEFT
+ LTEXT "Analyzer coloring style:",IDC_STATIC,11,94,75,8
+ CONTROL "Normal style",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,20,105,54,10
+ CONTROL "Fire style",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,20,115,43,10
+ CONTROL "Line style",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,20,125,45,10
+ LTEXT "Analyzer falloff speed:",IDC_STATIC,160,93,74,8
+ CONTROL "Slider1",IDC_SLIDER1,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,158,102,94,9
+ LTEXT "Slow",IDC_STATIC,160,114,16,8
+ LTEXT "Fast",IDC_STATIC,234,114,14,8
+ CONTROL "Show peaks on analyzer",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,11,137,93,10
+ LTEXT "Analyzer peak falloff speed:",IDC_STATIC,160,130,92,8
+ CONTROL "Slider1",IDC_SLIDER2,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,158,139,93,9
+ LTEXT "Slow",IDC_STATIC,160,151,16,8
+ LTEXT "Fast",IDC_STATIC,234,151,14,8
+ LTEXT "Analyzer band width:",IDC_STATIC,11,151,70,9
+ CONTROL "Thin",IDC_RADIO7,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,88,151,30,10
+ CONTROL "Thick",IDC_RADIO8,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,119,151,34,10
+ GROUPBOX "Oscilliscope Options",IDC_STATIC,4,169,256,27,BS_LEFT
+ LTEXT "Oscilliscope drawing style:",IDC_STATIC,11,181,86,8
+ CONTROL "Dots",IDC_RADIO9,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,109,180,31,10
+ CONTROL "Lines",IDC_RADIO10,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,157,180,33,10
+ CONTROL "Solid",IDC_RADIO11,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,207,180,31,10
+END
+
+IDD_NEWABOUT2 DIALOGEX 0, 0, 301, 205
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "",IDC_ABOUTIMG,"Static",SS_BLACKRECT | SS_CENTERIMAGE,0,0,301,205
+END
+
+IDD_NEWABOUT3 DIALOGEX 0, 0, 301, 207
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_TIPS,0,0,301,206,ES_MULTILINE | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP
+END
+
+IDD_NEWABOUT4 DIALOGEX 0, 0, 301, 207
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ COMBOBOX IDC_VER_COMBO,0,0,110,83,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "",IDC_RELEASED,114,2,133,10,SS_CENTERIMAGE
+ PUSHBUTTON "Search...",IDC_ABOUT_SEARCH,251,0,50,12
+ EDITTEXT IDC_TIPS,0,14,301,192,ES_MULTILINE | ES_NOHIDESEL | ES_READONLY | WS_VSCROLL
+END
+
+IDD_NEWABOUT DIALOGEX 0, 0, 313, 230
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Winamp"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "Winamp",IDC_BUTTON3,"Button",BS_OWNERDRAW | WS_TABSTOP,5,4,75,14
+ CONTROL "Credits",IDC_BUTTON4,"Button",BS_OWNERDRAW | WS_TABSTOP,81,4,75,14
+ CONTROL "Keyboard shortcuts",IDC_BUTTON5,"Button",BS_OWNERDRAW | WS_TABSTOP,157,4,75,14
+ CONTROL "Version history",IDC_BUTTON6,"Button",BS_OWNERDRAW | WS_TABSTOP,233,4,74,14
+ CONTROL "",IDC_RECT,"Static",SS_BLACKRECT | NOT WS_VISIBLE,5,19,302,205
+END
+
+IDD_NEWSHUFFLEOPTS DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Playlist",IDC_STATIC,0,0,272,246
+ GROUPBOX "Playlist Editor Appearance",IDC_STATIC,5,11,260,116,BS_LEFT
+ CONTROL "Show playlist item numbers in Playlist Editor",IDC_PLNUMS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,23,150,10
+ CONTROL "Zero pad item numbers",IDC_PLZEROPAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,23,85,10
+ LTEXT "Playlist font size, in pixels:",IDC_PLFONTSIZE_TEXT,12,36,88,8
+ EDITTEXT IDC_PLFONTSIZE,101,34,30,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,130,34,11,14
+ CONTROL "Use skin or language pack font",IDC_NOCUSTOMFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,48,115,10
+ LTEXT "Use font:",IDC_STATIC_CUSTOMFONT,12,63,30,8
+ COMBOBOX IDC_CUSTOMFONT,46,61,135,163,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Text Direction:",IDC_STATIC,12,80,47,8
+ COMBOBOX IDC_PLDIRECTION,63,78,196,163,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Scroll playlist using Page Up/Down by",IDC_STATIC,12,98,120,8
+ EDITTEXT IDC_PLSCROLL,136,96,28,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,161,96,11,14
+ LTEXT "lines",IDC_STATIC,168,98,23,8
+ CONTROL "Mousewheel scrolls double the above number of lines (default)",IDC_MOUSE_SCROLL_DOUBLE_LINES,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,111,246,10
+ GROUPBOX "Advanced Playback Settings",IDC_STATIC,5,131,260,70
+ CONTROL "Manual playlist advance",IDC_MANUALPLAYLISTADVANCE,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,12,144,94,8
+ LTEXT "When this option is enabled, the playing song will repeat indefinitely if repeat is turned on, or playback will halt after every track if repeat is off.",IDC_STATIC,24,154,235,17
+ CONTROL "When loading multiple files, sort files by name",IDC_RFL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,174,232,8
+ LTEXT "Assume file extension of unknown files is to be (default is ""mp3""):",IDC_STATIC,12,186,211,9
+ EDITTEXT IDC_DEFEXT,226,184,33,12
+ GROUPBOX "Shuffle Morph Rate",IDC_STATIC,5,203,260,37,BS_LEFT
+ CONTROL "Slider1",IDC_PREFS_SHUFFLE_MORPH_RATE,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,11,215,211,10
+ LTEXT "Slow",IDC_STATIC,11,224,17,8
+ LTEXT "Fast",IDC_STATIC,208,224,17,8
+ PUSHBUTTON "Help",IDC_SHUFFLE_HELP,229,214,30,13
+END
+
+IDD_NEWVIDEOOPTS DIALOGEX 0, 0, 272, 248
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Video Preferences",IDC_STATIC,0,0,272,247
+ CONTROL "Enable video support (default: on)",IDC_PREFS_VIDEO_ENABLE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,10,126,10
+ GROUPBOX "Video Playback",IDC_VIDEO_GROUP1,5,23,260,91
+ CONTROL "Display the video window when video playback begins",IDC_PREFS_VIDEO_AUTOOPEN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,35,188,10
+ CONTROL "Close the video window after video playback ends",IDC_PREFS_VIDEO_AUTOCLOSE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,48,174,10
+ CONTROL "Stop playback when video window is closed",IDC_PREFS_VIDEO_STOPCLOSE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,60,155,10
+ CONTROL "Resize video window to fit video",IDC_PREFS_VIDEO_UPDSIZE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,72,117,10
+ CONTROL "Disable Windows screensaver when playing video",IDC_PREFS_VIDEO_NOSS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,85,174,10
+ CONTROL "Display logo when a video is not playing",IDC_PREFS_VIDEO_LOGO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,98,158,10
+ GROUPBOX "Fullscreen Video Playback",IDC_VIDEO_GROUP2,5,117,260,51
+ CONTROL "Enable fullscreen on start",IDC_PREFS_VIDEO_AUTO_FS_ON_START,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,129,100,10
+ CONTROL "Remove fullscreen on stop",IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,141,101,10
+ CONTROL "Enable 'On Screen Display' when in fullscreen mode",IDC_PREFS_VIDEO_OSD,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,153,179,10
+ GROUPBOX "Advanced Video Options",IDC_VIDEO_GROUP3,5,171,260,66
+ CONTROL "Vertically flip videos (for compatibility with old drivers)",IDC_PREFS_VIDEO_FLIPRGB,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,12,183,187,10
+ CONTROL "Lock video aspect ratio",IDC_PREFS_VIDEO_ADJASP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,196,89,10
+ CONTROL "My screen has an aspect ratio of",IDC_USE_SCREENSHAPE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,209,119,10
+ EDITTEXT IDC_SCREENSHAPE1,141,208,15,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT " :",IDC_STATIC1,159,209,8,8
+ EDITTEXT IDC_SCREENSHAPE2,168,208,15,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "(usually 4:3)",IDC_STATIC2,188,209,68,8
+ CONTROL "Synchronize video to screen refresh rate (on by default)",IDC_PREFS_VIDEO_VSYNC,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,222,196,10
+ CONTROL "Slider1",IDC_PREFS_VIDEO_CONTRAST,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | NOT WS_VISIBLE | WS_GROUP | WS_TABSTOP,36,241,98,16
+ CONTROL "Slider1",IDC_PREFS_VIDEO_BRIGHTNESS,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | NOT WS_VISIBLE | WS_GROUP | WS_TABSTOP,138,241,98,16
+ LTEXT "Contrast",IDC_STATIC3,72,252,27,8,NOT WS_VISIBLE
+ LTEXT "Brightness",IDC_STATIC4,168,252,34,8,NOT WS_VISIBLE
+ CTEXT "Winamp restart required",IDC_VIDEO_RESTART,5,237,260,9,SS_CENTERIMAGE | NOT WS_VISIBLE
+ CONTROL "Permanently hide this preference page",IDC_PREFS_VIDEO_HIDE_PREFS,
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,15,22,150,10
+END
+
+IDD_PREFS_CLASSICSKIN DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Tab1",IDC_TAB1,"SysTabControl32",0x0,0,0,271,246
+END
+
+IDD_CLASSIC_UI DIALOGEX 0, 0, 260, 228
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "General Options",IDC_STATIC,4,3,256,79
+ CONTROL "Dim window titlebars when not in focus",IDC_HIGHLIGHT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,15,138,10
+ CONTROL "Dock skinned windows at",IDC_SNAP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,28,95,10
+ EDITTEXT IDC_SNAPW,105,27,17,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "pixels",IDC_STATIC,127,28,18,10,SS_CENTERIMAGE
+ CONTROL "Enable smooth window resizing for resizeable skinned windows",IDC_CHECK2,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,41,230,10
+ CONTROL "Display tooltips in Winamp's windows",IDC_TTIPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,54,133,10
+ CONTROL "Use skinned mouse cursors",IDC_WA_CURSORS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,67,103,10
+ GROUPBOX "Main Window Options",IDC_STATIC,4,85,256,86
+ CONTROL "Display playlist position in the song scroller",IDC_POS_IN_SONGTICKER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,96,150,10
+ CONTROL "Always show Winamp ""Clutterbar"" in main window",IDC_CLUTTERBAR,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,109,173,10
+ CONTROL "Use doublesize setting on equalizer as well as main window",IDC_EQDSIZE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,122,204,10
+ CONTROL "Use skinned font for main window title display\n(no international title support)",IDC_BIFONT,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,11,135,228,16
+ CONTROL "Use alternative font style when 'Double size' is enabled",IDC_BIFONT_ALT,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,21,155,228,10
+ GROUPBOX "Miscellaneous Options",IDC_STATIC,4,174,256,52
+ CONTROL "Oldschool playlist button behavior",IDC_SPLB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,186,125,10
+ CONTROL "Litestep VWM compatible mode (no screen snap)",IDC_KEEPONSCREEN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,199,167,10
+ CONTROL "Always on Litestep Virtual Desktops",IDC_AOVD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,211,133,10
+END
+
+IDD_NEWTITLE DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Titles",IDC_STATIC,0,0,272,246
+ GROUPBOX "Metadata Reading",IDC_STATIC,5,11,260,93
+ LTEXT "Winamp can read extended metadata for titles. Choose when this happens:",IDC_STATIC,12,22,247,8
+ CONTROL "Read metadata when file(s) are loaded into Winamp\n(this can be slow if a large number of files are added at once)",IDC_USEID4,
+ "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | WS_GROUP | WS_TABSTOP,20,34,239,16
+ CONTROL "Read metadata when file(s) are played or viewed in the playlist editor",IDC_USEID3,
+ "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,20,55,239,8
+ CONTROL "Read metadata only when file(s) are played",IDC_USEID5,
+ "Button",BS_AUTORADIOBUTTON,20,68,239,8
+ CONTROL "Read metadata in the background when file(s) are loaded into Winamp or are played or viewed in the playlist editor (default)",IDC_USEID6,
+ "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,20,80,239,16
+ GROUPBOX "Advanced Title Formatting",IDC_STATIC,5,107,260,82
+ CONTROL "Use advanced title formatting when possible",IDC_CHECK1,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,119,153,11
+ LTEXT "Advanced title display format :",IDC_STATIC,22,132,95,8
+ EDITTEXT IDC_FORMAT,22,143,235,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Default",IDC_TAGZ_DEFAULT,180,131,38,11
+ CONTROL "ATF Help",IDC_TAGZ_HELP,"Button",BS_OWNERDRAW | WS_TABSTOP,222,131,35,11
+ LTEXT "Example : ""%artist% - %title%""\nOther field names: %artist%, %album%, %title%, %track%, %year%, %genre%, %comment%, %filename%, %disc%, %rating%, ...",IDC_ATF_INFO,23,159,235,24
+ GROUPBOX "Miscellaneous",IDC_STATIC,5,192,260,40
+ CONTROL "Show underscores in titles as spaces",IDC_CONVERT2,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,204,132,10
+ CONTROL "Show '%20's in titles as spaces",IDC_CONVERT1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,217,113,10
+END
+
+IDD_RENAMESKIN DIALOGEX 0, 0, 241, 62
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Rename Skin"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "Old",IDC_STATIC,9,9,12,8
+ EDITTEXT IDC_OLD,28,7,206,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP
+ LTEXT "New",IDC_STATIC,9,24,16,8
+ EDITTEXT IDC_NEW,28,22,206,14,ES_AUTOHSCROLL
+ PUSHBUTTON "&OK",IDOK,7,41,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,65,41,50,14
+END
+
+IDD_BROWSE_RECDLG DIALOGEX 0, 0, 109, 26
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ CONTROL "Recurse subdirectories",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,4,95,10
+END
+
+IDD_M3U_DELETE DIALOGEX 0, 0, 293, 95
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC,7,7,279,45
+ PUSHBUTTON "Delete",IDC_DELETEM3U,7,73,100,14
+ PUSHBUTTON "Keep",IDC_NODELETE,210,73,76,14
+END
+
+IDD_CRASHDLG$() DIALOGEX 0, 0, 303, 164
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_NOPARENTNOTIFY
+CAPTION "Error Feedback"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "title",IDC_TITLELBL,114,4,185,43
+ CONTROL IDB_BITMAP4,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE | WS_BORDER,7,6,101,36
+ LTEXT "worklblb",IDC_WORKLBL,7,60,278,20
+ LTEXT "12121",IDC_PROGRESS3,7,79,288,26
+ PUSHBUTTON "Cancel",IDCANCEL,7,140,50,14
+ LTEXT "12121",IDC_PROGRESS1,7,148,232,13
+ DEFPUSHBUTTON "Start",IDOK,246,143,50,14
+END
+
+IDD_NEWLANG DIALOGEX 0, 0, 273, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Localization",IDC_STATIC,0,0,272,246
+ GROUPBOX "Installed Language Packs (Double-click to switch)",IDC_STATIC,5,11,260,133
+ LISTBOX IDC_SELBOX,12,24,186,67,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "Switch to",IDC_SELECT_LNG_PACK,203,24,55,13
+ PUSHBUTTON "Re&name...",IDC_RENAME_LNG_PACK,203,43,55,13,WS_DISABLED
+ PUSHBUTTON "&Uninstall...",IDC_DELETE_LNG_PACK,203,61,55,13,WS_DISABLED
+ LTEXT "",IDC_LANG_INFO_STR,12,94,140,8
+ LTEXT "",IDC_LANG_ID_STR,163,94,35,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_EDIT1,12,105,173,32,ES_MULTILINE | ES_READONLY | WS_VSCROLL
+ CONTROL "Find more languages",IDC_WINAMPLINK,"Button",BS_OWNERDRAW | BS_CENTER | BS_VCENTER,189,128,70,9
+ GROUPBOX "Language Pack Directory",IDC_STATIC,5,147,260,31
+ GROUPBOX "Miscellaneous",IDC_STATIC,5,181,260,51
+ CONTROL "Show Language Packs in a sub-menu on the main right-click menu",IDC_SHOW_LNG_PACK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,194,224,10
+ PUSHBUTTON "",IDC_CHDIR,12,159,246,13,BS_CENTER | BS_VCENTER | BS_MULTILINE | NOT WS_TABSTOP
+ CTEXT "Restart of Winamp is required for the language pack change to be applied",IDC_LANG_RESTART_TEXT,5,236,260,18,SS_NOPREFIX | NOT WS_VISIBLE | WS_DISABLED
+ CONTROL "Show install prompt before installing language packs\nAlways ensure you are installing language packs from a safe source.",IDC_LANG_INSTALL_PROMPT,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,12,208,246,16
+END
+
+IDD_NEWSETUP DIALOGEX 0, 0, 276, 258
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "General Preferences",IDC_STATIC,0,0,269,247
+ GROUPBOX "Internet Connection Settings",IDC_STATIC,2,11,260,60
+ CONTROL "Use proxy only for port 80 URLs",IDC_PROXY_ONLY_PORT_80,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,10,116,10
+ COMBOBOX IDC_COMBO2,11,24,248,125,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "(optional) Specify HTTP proxy address: '[user:password@]server:port' ",IDC_STATIC,11,41,248,8
+ EDITTEXT IDC_PROXYSTR,11,53,248,12,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Check for new versions of Winamp at startup",IDC_NEWVERCHECK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,75,161,10
+ CONTROL "Allow Winamp to report anonymous usage statistics",IDC_NEWVERCHECK2,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,102,181,10
+ CONTROL "Show splash screen at startup",IDC_PREFS_SPLASH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,115,113,10
+ CONTROL "Allow &multiple instances",IDC_MINST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,128,91,10
+ LTEXT "Show Winamp in:",IDC_STATIC,7,146,60,8
+ CONTROL "Notification area",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,157,69,10
+ CONTROL "Taskbar",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,169,41,10
+ GROUPBOX "Notification Area Icon",IDC_STATIC,86,147,112,32
+ CONTROL "Slider1",IDC_SYSTRAY_SCROLLER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,86,158,93,13
+ ICON ICON_TB1,IDC_SYSTRAY_ICON,178,158,14,13,NOT WS_VISIBLE
+ CONTROL "Scroll title in the Windows taskbar",IDC_SCROLLTITLE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,182,123,10
+ CONTROL "Show the playlist number in the Windows taskbar",IDC_SHOWPLEDITPOS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,195,173,10
+ GROUPBOX "Priority Class",IDC_STATIC,200,74,62,140
+ RTEXT "Realtime",IDC_STATIC,212,86,28,8
+ RTEXT "High",IDC_STATIC,224,103,16,8
+ RTEXT "Above Normal",IDC_STATIC,217,116,23,16
+ RTEXT "Normal",IDC_STATIC,217,137,23,8
+ RTEXT "Idle",IDC_STATIC,225,155,15,8
+ CONTROL "Slider1",IDC_PREFS_PRIORITY_CLASS,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_TOP | WS_TABSTOP,244,85,13,80
+ LTEXT "Change only if needed. High and Realtime priorities are not recommended.",IDC_STATIC,205,169,52,40,WS_DISABLED
+ CONTROL "Recycle permanently deleted files",IDC_RECYCLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,209,124,10
+ CONTROL "Prevent the mouse wheel from altering the volume",IDC_NO_MOUSEWHEEL,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,5,222,177,10
+ CONTROL "Disable always on top while fullscreen applications are focused",IDC_DROPAOTFS,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,1,234,249,10
+ CONTROL "Join RC Channel",IDC_NEWVERCHECK_RC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,88,161,10
+END
+
+IDD_FILEINFO DIALOGEX 0, 0, 366, 230
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "File Info"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,255,211,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,309,211,50,14
+ EDITTEXT IDC_FN,7,6,352,14,ES_AUTOHSCROLL | ES_READONLY
+ CONTROL "",IDC_TAB1,"SysTabControl32",WS_TABSTOP,7,24,352,184
+END
+
+IDD_FILEINFO_METADATA DIALOGEX 0, 0, 341, 164
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Metadata",IDC_STATIC,0,0,209,164
+ RTEXT "Track #",IDC_STATIC_TRACK,6,11,36,8
+ EDITTEXT IDC_TRACK,45,9,36,12,ES_AUTOHSCROLL
+ RTEXT "Disc #",IDC_STATIC_DISC,86,11,21,8
+ EDITTEXT IDC_DISC,109,9,36,12,ES_AUTOHSCROLL
+ LTEXT "BPM",IDC_STATIC_BPM,152,11,14,8
+ EDITTEXT IDC_BPM,167,9,35,12,ES_AUTOHSCROLL
+ RTEXT "Title",IDC_STATIC_TITLE,6,28,36,8
+ EDITTEXT IDC_TITLE,45,25,157,12,ES_AUTOHSCROLL
+ RTEXT "Artist",IDC_STATIC_ARTIST,6,43,36,8
+ EDITTEXT IDC_ARTIST,46,41,157,12,ES_AUTOHSCROLL
+ RTEXT "Album",IDC_STATIC_ALBUM,6,57,36,8
+ EDITTEXT IDC_ALBUM,46,56,157,12,ES_AUTOHSCROLL
+ RTEXT "Album Artist",IDC_STATIC_ALBUM_ARTIST,2,72,40,8
+ EDITTEXT IDC_ALBUM_ARTIST,46,70,157,12,ES_AUTOHSCROLL
+ RTEXT "Year",IDC_STATIC_YEAR,6,86,36,8
+ EDITTEXT IDC_YEAR,46,84,31,12,ES_AUTOHSCROLL | ES_NUMBER
+ RTEXT "Genre",IDC_STATIC_GENRE,81,86,22,8
+ COMBOBOX IDC_GENRE,106,84,97,159,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ RTEXT "Comment",IDC_STATIC_COMMENT,6,102,36,8
+ EDITTEXT IDC_COMMENT,46,100,157,29,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ RTEXT "Composer",IDC_STATIC_COMPOSER,6,134,36,8
+ EDITTEXT IDC_COMPOSER,46,132,157,12,ES_AUTOHSCROLL
+ RTEXT "Publisher",IDC_STATIC_PUBLISHER,6,150,36,8
+ EDITTEXT IDC_PUBLISHER,46,147,157,12,ES_AUTOHSCROLL
+ GROUPBOX "Format Info",IDC_STATIC,214,0,127,113
+ EDITTEXT IDC_FORMATINFO,218,11,119,96,ES_MULTILINE | ES_READONLY | NOT WS_BORDER
+ GROUPBOX "Replay Gain",IDC_STATIC,214,114,127,33
+ EDITTEXT IDC_REPLAYGAIN,218,125,115,16,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ PUSHBUTTON "Auto-Tag",IDC_AUTOTAG,291,150,50,14
+ EDITTEXT IDC_GN_FILEID,277,150,6,14,ES_AUTOHSCROLL | NOT WS_VISIBLE
+ EDITTEXT IDC_GN_EXTDATA,284,150,6,14,ES_AUTOHSCROLL | NOT WS_VISIBLE
+END
+
+IDD_FILEINFO_ARTWORK DIALOGEX 0, 0, 341, 164
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Artwork editor",IDC_STATIC,0,0,341,164
+ LISTBOX IDC_ARTLIST,6,9,110,101,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Artwork type:",IDC_STATIC,6,115,46,8
+ COMBOBOX IDC_COMBO_ARTTYPE,53,113,63,108,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Load Artwork...",IDC_BUTTON_LOAD,6,129,56,14
+ PUSHBUTTON "Paste Artwork",IDC_BUTTON_PASTENEW,64,129,51,14
+ PUSHBUTTON "Download Art",IDC_BUTTON_DOWNLOAD,6,146,50,14
+ GROUPBOX "(no image)",IDC_STATIC_FRAME,120,5,216,154
+ CONTROL "",IDC_ARTHOLDER,"Static",SS_BITMAP,125,14,152,140
+ PUSHBUTTON "Change...",IDC_BUTTON_CHANGE,281,14,50,14
+ PUSHBUTTON "Save As...",IDC_BUTTON_SAVEAS,281,30,50,14
+ PUSHBUTTON "Copy",IDC_BUTTON_COPY,281,46,50,14
+ PUSHBUTTON "Paste",IDC_BUTTON_PASTE,281,62,49,14
+ PUSHBUTTON "Delete",IDC_BUTTON_DELETE,281,78,50,14
+END
+
+IDD_ARTDOWNLOADER DIALOGEX 0, 0, 301, 262
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Cover Art Downloader"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_SEARCHREFINE_ARTIST,42,18,156,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_SEARCHREFINE_ALBUM,42,36,156,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_SEARCHREFINE_YEAR,234,18,53,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Search",IDC_SEARCHAGAIN,210,36,78,14,WS_DISABLED
+ RTEXT "Year",IDC_STATIC,211,19,16,8
+ GROUPBOX "Select the correct image, or press cancel",IDC_STATIC,8,60,287,159
+ GROUPBOX "",IDC_PLACEHOLDER,10,69,283,148
+ LTEXT "",IDC_STATUS,8,220,287,8
+ PUSHBUTTON "Cancel All",IDC_CANCELALL,189,241,50,14,NOT WS_VISIBLE
+ PUSHBUTTON "Cancel",IDCANCEL,244,241,50,14
+ GROUPBOX "Refine Search",IDC_STATIC,8,7,286,50
+ RTEXT "Artist",IDC_STATIC,19,19,18,8
+ RTEXT "Album",IDC_STATIC,19,38,20,8
+ LTEXT "Cover art downloaded here cannot be viewed on portable media players.",IDC_STATIC_NO_IPOD,8,230,287,8
+END
+
+IDD_ARTDOWNLOADER_SCROLLHOST DIALOGEX 0, 0, 283, 148
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+
+IDD_ARTDOWNLOADER_IMAGE DIALOGEX 0, 0, 101, 136
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_IMAGE,"Static",SS_BITMAP,4,0,93,86
+ LTEXT "",IDC_IMGTEXT,4,88,93,33
+ PUSHBUTTON "Select",IDC_SELECT,25,122,50,14
+END
+
+IDD_ARTDOWNLOADER_SCROLLCHILD DIALOGEX 0, 0, 5, 136
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+
+IDD_AUTOTAGGING DIALOGEX 0, 0, 200, 62
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Working..."
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Your file is being scanned, please wait...",IDC_STATIC,7,7,130,8
+ LTEXT "The Winamp Auto-Tagger is unavailable in this release",IDC_STATIC,7,47,165,8
+ LTEXT "Tip: To Auto-Tag many tracks at once, select them all and use the Auto-Tag option in the right-click Send To menu.",IDC_STATIC,7,19,186,24
+END
+
+IDD_PLAYBACK DIALOGEX 0, 0, 260, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Playback Settings",-1,4,3,256,222
+ GROUPBOX "Playback Thread Priority",-1,10,14,243,37
+ LTEXT "Lowest",-1,17,31,23,8
+ CONTROL "",IDC_PRIORITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,54,27,145,16
+ LTEXT "Highest (default)",-1,213,26,33,18
+ GROUPBOX "Audio",-1,10,55,243,64
+ CONTROL "Allow 24bit",IDC_24BIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,67,50,10
+ CONTROL "Allow surround sound",IDC_SURROUND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,79,83,10
+ CONTROL "Use dither",IDC_DITHER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,91,48,10
+ CONTROL "Force mono",IDC_MONO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,103,53,10
+END
+
+IDD_EQUALIZER_UI DIALOGEX 0, 0, 260, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Equalizer Settings",IDC_STATIC,4,3,256,222
+ LTEXT "Specify the EQ Type and Frequency Bands to use for the Winamp Equalizer.",IDC_STATIC,10,16,243,10
+ LTEXT "EQ Type:",IDC_STATIC_EQ,11,31,70,12,SS_CENTERIMAGE
+ COMBOBOX IDC_EQ,88,31,140,97,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Frequency Bands:",IDC_STATIC_FREQ,11,49,70,12,SS_CENTERIMAGE
+ COMBOBOX IDC_FREQ_BANDS,88,49,140,126,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Use Limiter (helps prevent clipping) [Default: On]",IDC_LIMITER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,67,175,10
+ CTEXT "Restart of Winamp is required for the EQ type change to be applied",IDC_EQ_RESTART_TEXT,10,82,243,8,SS_CENTERIMAGE | NOT WS_VISIBLE | WS_DISABLED
+END
+
+IDD_REPLAY_GAIN_UI DIALOGEX 0, 0, 260, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Replay Gain Settings",-1,4,3,256,222
+ GROUPBOX " ",IDC_REPLAY_GROUP,10,14,243,128
+ CONTROL "Use Replay Gain",IDC_USE_REPLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,14,68,10
+ LTEXT "Amplification mode:",IDC_STATIC_MODE,17,28,63,12,SS_CENTERIMAGE
+ COMBOBOX IDC_REPLAY_MODE,94,28,137,97,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Preferred source:",IDC_STATIC_SOURCE,17,46,58,12,SS_CENTERIMAGE
+ COMBOBOX IDC_REPLAY_SOURCE,94,46,138,126,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Disable if preferred source is not available",IDC_REPLAY_PREFERRED,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,63,148,10
+ LTEXT "Adjustment for files without Replay Gain:",IDC_STATIC_ADJ,17,79,133,8
+ LTEXT "",IDC_NON_REPLAYGAIN_DB,17,93,40,10,SS_CENTERIMAGE
+ CONTROL "",IDC_NON_REPLAYGAIN,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,66,93,177,12
+ LTEXT " Replay Gain Preamp:",IDC_REPLAY_ADJ,16,110,133,8
+ LTEXT "",IDC_REPLAYGAIN_PREAMP_DB,17,124,40,10,SS_CENTERIMAGE
+ CONTROL "",IDC_REPLAYGAIN_PREAMP,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,66,124,177,12
+ GROUPBOX "Replay Gain Analyzer Settings",IDC_RGAS,10,146,243,67,NOT WS_VISIBLE
+ CONTROL "Ask before writing Replay Gain to analyzed files",IDC_RG_ASK,
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,17,159,168,10
+ CONTROL "Ask after each album is scanned",IDC_RG_ALBUM,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_GROUP,27,172,119,10
+ CONTROL "Ask after all files are scanned",IDC_RG_ALL,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,27,185,110,10
+ LTEXT "Replay Gain © 2001 David Robinson and Glen Sawyer",IDC_RGC,17,199,200,8,NOT WS_VISIBLE | WS_DISABLED
+END
+
+IDD_JSAPI2_AUTHORIZATION2 DIALOGEX 0, 0, 186, 86
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT
+CAPTION "Winamp Online Service"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "<title>",IDC_TITLE,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | WS_GROUP,6,6,33,8
+ LTEXT "<set this dialog size to minimum acceptable>",IDC_MESSAGE,41,8,139,16
+ ICON "",IDC_MESSAGEICON,6,18,20,20,SS_REALSIZEIMAGE
+ PUSHBUTTON "&Allow",IDC_BUTTON_ALLOW,75,34,50,14
+ DEFPUSHBUTTON "&Deny",IDC_BUTTON_DENY,130,34,50,14
+ CONTROL "Apply to all &requests from this service",IDC_APPLYTOALL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,51,174,8
+ CONTROL "",IDC_SEPARATOR,"Static",SS_ETCHEDHORZ,0,65,185,1
+ LTEXT " to learn more about Winamp security policy.",IDC_HELPTEXT,6,71,127,8
+END
+
+IDD_NEWABOUT1EGG DIALOGEX 0, 0, 358, 178
+STYLE DS_SETFONT | DS_CONTROL | WS_CHILD
+FONT 7, "Courier New", 0, 0, 0x0
+BEGIN
+ LTEXT "",IDC_ASCII,21,24,329,144
+END
+
+IDD_ABOUT_TRANSLATION DIALOGEX 0, 0, 301, 207
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "Author's Homepage 65533",IDC_AUTHOR_HOMEPAGE,"Button",BS_OWNERDRAW | BS_CENTER | BS_VCENTER,209,186,92,9
+ LTEXT "Language packs by Winamp users are provided as a volunteer service to other Winamp users.",IDC_STATIC,6,7,288,38
+ CONTROL "Author's Homepage 65532",IDC_AUTHOR_HOMEPAGE2,"Button",BS_OWNERDRAW | BS_CENTER | BS_VCENTER,109,186,92,9
+END
+
+IDD_CMDLINE DIALOGEX 0, 0, 430, 300
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "Winamp Commandline Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "These are the commandline options you can use with controlling Winamp in conjunction with external scripting or the controlling of some of Winamp's functionality without writing a native plug-in (though native plug-ins are always preferred):",IDC_STATIC,5,7,419,16
+ EDITTEXT IDC_CMDLINE,5,28,419,267,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP
+END
+
+IDD_FILEINFO_STREAMDATA DIALOGEX 0, 0, 341, 164
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Metadata",IDC_STATIC,0,0,339,79
+ RTEXT "Station",IDC_STATIC_STATION,6,11,36,8
+ EDITTEXT IDC_STATION,46,9,157,12,ES_AUTOHSCROLL | ES_READONLY
+ RTEXT "Genre",IDC_STATIC_GENRE,209,11,26,8
+ EDITTEXT IDC_GENRE,239,9,93,12,ES_AUTOHSCROLL | ES_READONLY
+ RTEXT "Website",IDC_STATIC_URL,6,28,36,8
+ EDITTEXT IDC_URL,46,26,157,12,ES_AUTOHSCROLL | ES_READONLY
+ CONTROL "Stream includes extra metadata",IDC_EXTRA_METADATA,
+ "Button",BS_AUTOCHECKBOX | BS_VCENTER | WS_DISABLED | WS_TABSTOP,215,27,118,10
+ RTEXT "Playing",IDC_STATIC_TITLE,6,45,36,8
+ EDITTEXT IDC_TITLE,46,43,157,12,ES_AUTOHSCROLL | ES_READONLY
+ GROUPBOX "Status",IDC_STATIC,0,82,339,82
+ EDITTEXT IDC_FORMATINFO,5,94,329,64,ES_MULTILINE | ES_READONLY | NOT WS_BORDER
+ RTEXT "Playing Url",IDC_STATIC_PLAY_URL,6,63,36,8
+ EDITTEXT IDC_PLAY_URL,46,60,157,12,ES_AUTOHSCROLL | ES_READONLY
+END
+
+IDD_PREFS_FAIL DIALOGEX 0, 0, 272, 246
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CTEXT "Unable to load the selected Winamp preference page.\n\nIf using a language pack, first check for an updated Winamp release (if not already using the current release) and then try to obtain an updated version from the language pack author.",IDC_STATIC,34,99,203,48
+END
+
+IDD_EDIT_INFO DIALOGEX 0, 0, 307, 283
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit Item Metadata"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ GROUPBOX "",1051,6,4,295,256
+ CONTROL "Artist",IDC_CHECK_ARTIST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,17,33,10
+ EDITTEXT IDC_EDIT_ARTIST,58,16,236,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Title",IDC_CHECK_TITLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,29,10
+ EDITTEXT IDC_EDIT_TITLE,58,33,236,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Album",IDC_CHECK_ALBUM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,51,35,10
+ EDITTEXT IDC_EDIT_ALBUM,58,50,236,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Comment",IDC_CHECK_COMMENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,68,42,10
+ EDITTEXT IDC_EDIT_COMMENT,58,67,236,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Track #",IDC_CHECK_TRACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,85,41,10
+ EDITTEXT IDC_EDIT_TRACK,58,84,40,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Genre",IDC_CHECK_GENRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,85,34,10
+ EDITTEXT IDC_EDIT_GENRE,148,84,62,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "BPM",IDC_CHECK_BPM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,220,85,26,10
+ EDITTEXT IDC_EDIT_BPM,250,84,44,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Year",IDC_CHECK_YEAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,102,31,10
+ EDITTEXT IDC_EDIT_YEAR,58,101,40,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Rating",IDC_CHECK_RATING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,102,34,10
+ COMBOBOX IDC_COMBO_RATING,148,101,62,64,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Disc",IDC_CHECK_DISC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,220,103,26,10
+ EDITTEXT IDC_EDIT_DISC,250,101,44,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Album Artist",IDC_CHECK_ALBUMARTIST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,119,54,10
+ EDITTEXT IDC_EDIT_ALBUMARTIST,71,118,223,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Publisher",IDC_CHECK_PUBLISHER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,136,54,10
+ EDITTEXT IDC_EDIT_PUBLISHER,71,135,223,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Composer",IDC_CHECK_COMPOSER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,153,54,10
+ EDITTEXT IDC_EDIT_COMPOSER,71,152,223,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Category",IDC_CHECK_CATEGORY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,170,54,10
+ EDITTEXT IDC_EDIT_CATEGORY,71,169,223,13,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Director",IDC_CHECK_DIRECTOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,188,54,10
+ EDITTEXT IDC_EDIT_DIRECTOR,71,186,223,14,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Producer",IDC_CHECK_PRODUCER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,206,54,10
+ EDITTEXT IDC_EDIT_PRODUCER,71,204,223,14,ES_AUTOHSCROLL | WS_DISABLED
+ GROUPBOX "Podcasts",IDC_STATIC,12,223,283,32
+ CONTROL "Is Podcast",IDC_CHECK_PODCAST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,236,49,10
+ CONTROL "Channel",IDC_CHECK_PODCAST_CHANNEL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,236,42,10
+ EDITTEXT IDC_EDIT_PODCAST_CHANNEL,129,234,160,14,ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Update file tag(s) if supported by the tagging format",1052,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,266,187,10
+ DEFPUSHBUTTON "Update",IDOK,197,264,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,251,264,50,14
+END
+
+IDD_ADDSTUFF DIALOGEX 0, 0, 186, 61
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+CAPTION "Adding media..."
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CTEXT "",1008,7,7,172,8
+ CONTROL "Progress1",1007,"msctls_progress32",WS_BORDER,7,19,172,14
+ PUSHBUTTON "Cancel",IDCANCEL,67,40,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_SPLASH, DIALOG
+ BEGIN
+ RIGHTMARGIN, 201
+ END
+
+ IDD_NEWABOUT1, DIALOG
+ BEGIN
+ VERTGUIDE, 181
+ TOPMARGIN, 1
+ END
+
+ IDD_LOADPRESET, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 164
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 152
+ END
+
+ IDD_SAVEPRESET, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 164
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 156
+ END
+
+ IDD_OPENLOC, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 178
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 61
+ END
+
+ IDD_JUMPDLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 135
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 71
+ END
+
+ IDD_JUMPFILEDLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 251
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 200
+ END
+
+ IDD_EDITENTRY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 234
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 55
+ END
+
+ IDD_HTTPGET, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 58
+ END
+
+ IDD_NEWPREFS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 382
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 251
+ END
+
+ IDD_NEWPLUG, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 246
+ END
+
+ IDD_NEWGEN, DIALOG
+ BEGIN
+ END
+
+ IDD_NEWSKIN, DIALOG
+ BEGIN
+ RIGHTMARGIN, 272
+ BOTTOMMARGIN, 245
+ END
+
+ IDD_CLASSIC_VIS, DIALOG
+ BEGIN
+ RIGHTMARGIN, 259
+ END
+
+ IDD_NEWABOUT2, DIALOG
+ BEGIN
+ RIGHTMARGIN, 300
+ TOPMARGIN, 1
+ END
+
+ IDD_NEWABOUT3, DIALOG
+ BEGIN
+ TOPMARGIN, 1
+ END
+
+ IDD_NEWABOUT4, DIALOG
+ BEGIN
+ TOPMARGIN, 1
+ END
+
+ IDD_NEWABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 307
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 225
+ END
+
+ IDD_RENAMESKIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 234
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 55
+ END
+
+ IDD_M3U_DELETE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 286
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 87
+ END
+
+ IDD_NEWSETUP, DIALOG
+ BEGIN
+ RIGHTMARGIN, 187
+ BOTTOMMARGIN, 170
+ END
+
+ IDD_FILEINFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 359
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 225
+ END
+
+ IDD_FILEINFO_METADATA, DIALOG
+ BEGIN
+ RIGHTMARGIN, 339
+ END
+
+ IDD_ARTDOWNLOADER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 294
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 255
+ END
+
+ IDD_ARTDOWNLOADER_SCROLLHOST, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_ARTDOWNLOADER_IMAGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 97
+ BOTTOMMARGIN, 121
+ END
+
+ IDD_ARTDOWNLOADER_SCROLLCHILD, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 121
+ END
+
+ IDD_AUTOTAGGING, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 55
+ END
+
+ IDD_REPLAY_GAIN_UI, DIALOG
+ BEGIN
+ END
+
+ IDD_JSAPI2_AUTHORIZATION2, DIALOG
+ BEGIN
+ VERTGUIDE, 6
+ VERTGUIDE, 180
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 80
+ END
+
+ IDD_NEWABOUT1EGG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 351
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 171
+ END
+
+ IDD_ABOUT_TRANSLATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 195
+ END
+
+ IDD_CMDLINE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 424
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 295
+ END
+
+ IDD_FILEINFO_STREAMDATA, DIALOG
+ BEGIN
+ RIGHTMARGIN, 339
+ END
+
+ IDD_EDIT_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 6
+ RIGHTMARGIN, 301
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 278
+ END
+
+ IDD_ADDSTUFF, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 54
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXT
+//
+
+TIPSTEXT TEXT "resource/tips.txt"
+
+CMDLINE TEXT "resource\\cmdline.txt"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+WINAMP_MAIN MENU
+BEGIN
+ POPUP "Main"
+ BEGIN
+ MENUITEM "About &Winamp...\tCtrl+F1", WINAMP_HELP_ABOUT
+ MENUITEM SEPARATOR
+ POPUP "&Play"
+ BEGIN
+ MENUITEM "&File... \tL", WINAMP_FILE_PLAY
+ MENUITEM "&URL...\tCtrl+L", WINAMP_FILE_LOC
+ MENUITEM "&Folder...\tShift+L", WINAMP_FILE_DIR
+ MENUITEM SEPARATOR
+ POPUP "&Bookmark"
+ BEGIN
+ MENUITEM "(no bookmarks)", ID_MAIN_PLAY_BOOKMARK_NONE, INACTIVE
+ END
+ END
+ MENUITEM "View &file info...\tAlt+3", WINAMP_EDIT_ID3
+ POPUP "&Bookmarks"
+ BEGIN
+ MENUITEM "&Edit bookmarks...\tCtrl+Alt+I", WINAMP_EDIT_BOOKMARKS
+ MENUITEM "&Add current as bookmark\tCtrl+Alt+B", WINAMP_MAKECURBOOKMARK
+ MENUITEM SEPARATOR
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "&Main Window\tAlt+W", WINAMP_MAIN_WINDOW
+ MENUITEM "Playlist &Editor\tAlt+E", WINAMP_OPTIONS_PLEDIT
+ MENUITEM "E&qualizer \tAlt+G", WINAMP_OPTIONS_EQ
+ MENUITEM "&Video\tAlt+V", WINAMP_OPTIONS_VIDEO
+ MENUITEM SEPARATOR
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Preferences... \tCtrl+P", WINAMP_OPTIONS_PREFS
+ POPUP "Skins"
+ BEGIN
+ MENUITEM "S&kin Browser...\tAlt+S", WINAMP_SELSKIN
+ MENUITEM "<< Get more skins! >>", WINAMP_GETMORESKINS
+ MENUITEM SEPARATOR
+ MENUITEM "Winamp Classic", 32767
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Time &elapsed\tCtrl+T toggles", WINAMP_OPTIONS_ELAPSED
+ MENUITEM "Time re&maining\tCtrl+T toggles", WINAMP_OPTIONS_REMAINING
+ MENUITEM SEPARATOR
+ MENUITEM "&Always On Top\tCtrl+A", WINAMP_OPTIONS_AOT
+ MENUITEM "&Double Size\tCtrl+D", WINAMP_OPTIONS_DSIZE
+ MENUITEM "&EasyMove\tCtrl+E", WINAMP_OPTIONS_EASYMOVE
+ MENUITEM SEPARATOR
+ MENUITEM "&Repeat\tR", WINAMP_FILE_REPEAT
+ MENUITEM "&Shuffle\tS", WINAMP_FILE_SHUFFLE
+ END
+ POPUP "Play&back"
+ BEGIN
+ MENUITEM "P&revious\tZ", WINAMP_BUTTON1
+ MENUITEM "&Play\tX", WINAMP_BUTTON2
+ MENUITEM "P&ause\tC", WINAMP_BUTTON3
+ MENUITEM "&Stop\tV", WINAMP_BUTTON4
+ MENUITEM "&Next \tB", WINAMP_BUTTON5
+ MENUITEM SEPARATOR
+ MENUITEM "Stop w/ fa&deout\tShift+V", WINAMP_BUTTON4_SHIFT
+ MENUITEM "Stop after &current\tCtrl+V", WINAMP_BUTTON4_CTRL
+ MENUITEM "&Back 5 seconds\tLeft", WINAMP_BUTTON1_SHIFT
+ MENUITEM "&Fwd 5 seconds\tRight", WINAMP_BUTTON5_SHIFT
+ MENUITEM "&Start of list\tCtrl+Z", WINAMP_BUTTON1_CTRL
+ MENUITEM "&End of list\tCtrl+B", WINAMP_BUTTON5_CTRL
+ MENUITEM "10 t&racks back\tNum. 1", WINAMP_JUMP10BACK
+ MENUITEM "10 &tracks fwd\tNum. 3", WINAMP_JUMP10FWD
+ MENUITEM SEPARATOR
+ MENUITEM "&Jump to time\tCtrl+J", WINAMP_JUMP
+ MENUITEM "Ju&mp to file\tJ", WINAMP_JUMPFILE
+ END
+ POPUP "&Visualization"
+ BEGIN
+ MENUITEM "Start/Stop &plug-in\tCtrl+Shift+K", WINAMP_VISPLUGIN
+ MENUITEM "&Configure plug-in... \tAlt+K", WINAMP_VISCONF
+ MENUITEM "&Select plug-in...\tCtrl+K", WINAMP_PLGSETUP
+ END
+ POPUP "&Skins"
+ BEGIN
+ MENUITEM "S&kin Browser...\tAlt+S", WINAMP_SELSKIN
+ MENUITEM "<< Get more skins! >>", WINAMP_GETMORESKINS
+ MENUITEM SEPARATOR
+ MENUITEM "Winamp Classic", 32767
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Winamp &Help\tF1", ID_HELP_HELPTOPICS
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit\tAlt+F4", WINAMP_FILE_QUIT
+ END
+ POPUP "EQpresets"
+ BEGIN
+ POPUP "Load"
+ BEGIN
+ MENUITEM "&Preset...", IDM_EQ_LOADPRE
+ MENUITEM "&Auto-load preset...", IDM_EQ_LOADMP3
+ MENUITEM "&Default", IDM_EQ_LOADDEFAULT
+ MENUITEM SEPARATOR
+ MENUITEM "From &EQF...", ID_LOAD_EQF
+ END
+ POPUP "Save"
+ BEGIN
+ MENUITEM "&Preset...", IDM_EQ_SAVEPRE
+ MENUITEM "&Auto-load preset...", IDM_EQ_SAVEMP3
+ MENUITEM "&Default", IDM_EQ_SAVEDEFAULT
+ MENUITEM SEPARATOR
+ MENUITEM "To &EQF...", ID_SAVE_EQF
+ END
+ POPUP "Delete"
+ BEGIN
+ MENUITEM "&Preset...", IDM_EQ_DELPRE
+ MENUITEM "&Auto-load preset...", IDM_EQ_DELMP3
+ END
+ END
+ POPUP "PLContextMenu"
+ BEGIN
+ POPUP "MiscOpt"
+ BEGIN
+ POPUP "File info"
+ BEGIN
+ MENUITEM "F&ile info...\tAlt+3", ID_PE_ID3
+ MENUITEM "Playlist &entry...\tCtrl+E", ID_PE_ENTRY
+ END
+ POPUP "Sort"
+ BEGIN
+ MENUITEM "Sort list by &title\tCtrl+Shift+1", ID_PE_S_TITLE
+ MENUITEM "Sort list by &filename\tCtrl+Shift+2", ID_PE_S_FILENAME
+ MENUITEM "Sort list by &path and filename\tCtrl+Shift+3", ID_PE_S_PATH
+ MENUITEM SEPARATOR
+ MENUITEM "R&everse list\tCtrl+R", ID_PE_S_REV
+ MENUITEM "&Randomize list\tCtrl+Shift+R", ID_PE_S_RANDOM
+ END
+ POPUP "Misc"
+ BEGIN
+ MENUITEM "&Generate HTML playlist\tCtrl+Alt+G", ID_PE_PRINT
+ MENUITEM SEPARATOR
+ MENUITEM "&Rebuild titles on selection\tCtrl+Alt+E", ID_PE_EXTINFO
+ END
+ END
+ POPUP "Add"
+ BEGIN
+ MENUITEM "Add &file(s)\tL", IDC_PLAYLIST_ADDMP3
+ MENUITEM "Add f&older\tShift+L", IDC_PLAYLIST_ADDDIR
+ MENUITEM "Add &URL\tCtrl+L", IDC_PLAYLIST_ADDLOC
+ END
+ POPUP "Remove"
+ BEGIN
+ MENUITEM "&Remove selected\tDelete", IDC_PLAYLIST_REMOVEMP3
+ MENUITEM "Crop &selected\tCtrl+Delete", IDC_PLAYLIST_CROP
+ MENUITEM "&Clear playlist\tCtrl+Shift+Delete", ID_PE_CLEAR
+ POPUP "Remove..."
+ BEGIN
+ MENUITEM "Remove &missing files from playlist\tAlt+Delete", ID_PE_NONEXIST
+ MENUITEM "&Physically remove selected file(s)", ID_PE_DELETEFROMDISK
+ END
+ END
+ POPUP "Select"
+ BEGIN
+ MENUITEM "Select &all\tCtrl+A", ID_PE_SELECTALL
+ MENUITEM "Select &none", ID_PE_NONE
+ MENUITEM "&Invert selection\tCtrl+I", IDC_SELECTINV
+ END
+ POPUP "Playlist"
+ BEGIN
+ MENUITEM "&Open playlist...\tCtrl+O", ID_PE_OPEN
+ MENUITEM "&Save playlist...\tCtrl+S", ID_PE_SAVEAS
+ MENUITEM "&New playlist (clear)\tCtrl+N", ID_PE_CLEAR
+ END
+ POPUP "Context"
+ BEGIN
+ MENUITEM "&Play item(s)\tEnter", IDC_PLAYLIST_PLAY
+ MENUITEM SEPARATOR
+ MENUITEM "&Remove item(s)\tDelete", IDC_PLAYLIST_REMOVEMP3
+ MENUITEM "&Crop files\tCtrl+Delete", IDC_PLAYLIST_CROP
+ MENUITEM SEPARATOR
+ MENUITEM "Edit &metadata for selection...\tShift+E", ID_PE_EDIT_SEL
+ MENUITEM "&View file info...\tAlt+3", ID_PE_ID3
+ MENUITEM "Playlist &entry\tCtrl+E", ID_PE_ENTRY
+ MENUITEM "&Bookmark item(s)\tCtrl+Alt+B", ID_PE_BOOKMARK
+ MENUITEM SEPARATOR
+ POPUP "Rate &items"
+ BEGIN
+ MENUITEM "*****", ID_PL_RATING5
+ MENUITEM "****", ID_PL_RATING4
+ MENUITEM "***", ID_PL_RATING3
+ MENUITEM "**", ID_PL_RATING2
+ MENUITEM "*", ID_PL_RATING1
+ MENUITEM "No rating", ID_PL_RATING0
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Explore item(s) &folder\tCtrl+F", ID_PE_FFOD
+ END
+ END
+ POPUP "Context menus"
+ BEGIN
+ POPUP "Song title"
+ BEGIN
+ MENUITEM "View &file info...\tAlt+3 or Dblclick", WINAMP_EDIT_ID3
+ MENUITEM "&Jump to file...\tJ", WINAMP_JUMPFILE
+ MENUITEM "Jump to &time...\tCtrl+J", WINAMP_JUMP
+ MENUITEM "&Autoscroll songname", WINAMP_TOGGLE_AUTOSCROLL
+ MENUITEM SEPARATOR
+ POPUP "&Rating"
+ BEGIN
+ MENUITEM "*****", ID_RATING5
+ MENUITEM "****", ID_RATING4
+ MENUITEM "***", ID_RATING3
+ MENUITEM "**", ID_RATING2
+ MENUITEM "*", ID_RATING1
+ MENUITEM "No rating", ID_RATING0
+ END
+ END
+ POPUP "Time display"
+ BEGIN
+ MENUITEM "Time &elapsed\tCtrl+T toggles", WINAMP_OPTIONS_ELAPSED
+ MENUITEM "Time re&maining\tCtrl+T toggles", WINAMP_OPTIONS_REMAINING
+ END
+ POPUP "Previous button"
+ BEGIN
+ MENUITEM "&Previous\tClick", WINAMP_BUTTON1
+ MENUITEM "&Start of list\tCtrl+Click", WINAMP_BUTTON1_CTRL
+ MENUITEM "&Rewind 5 seconds\tShift+Click", WINAMP_BUTTON1_SHIFT
+ END
+ POPUP "Play Button"
+ BEGIN
+ MENUITEM "&Play/restart\tClick", WINAMP_BUTTON2
+ MENUITEM "Open &URL...\tCtrl+Click", WINAMP_BUTTON2_CTRL
+ MENUITEM "Open &file...\tShift+Click", WINAMP_BUTTON2_SHIFT
+ END
+ POPUP "Pause button"
+ BEGIN
+ MENUITEM "&Pause/Unpause\tClick", WINAMP_BUTTON3
+ END
+ POPUP "Stop button"
+ BEGIN
+ MENUITEM "&Stop\tClick", WINAMP_BUTTON4
+ MENUITEM "Stop w/&fadeout\tShift+Click", WINAMP_BUTTON4_SHIFT
+ MENUITEM "Stop after &current\tCtrl+Click", WINAMP_BUTTON4_CTRL
+ END
+ POPUP "Next button"
+ BEGIN
+ MENUITEM "&Next\tClick", WINAMP_BUTTON5
+ MENUITEM "&Fastforward 5 seconds\tShift+Click", WINAMP_BUTTON5_SHIFT
+ MENUITEM "&End of list\tCtrl+Click", WINAMP_BUTTON5_CTRL
+ END
+ POPUP "Eject button"
+ BEGIN
+ MENUITEM "Open &file...\tClick", WINAMP_FILE_PLAY
+ MENUITEM "Open f&older...\tShift+Click", WINAMP_FILE_DIR
+ MENUITEM "Open &URL...\tCtrl+Click", WINAMP_FILE_LOC
+ END
+ POPUP "Seek bar"
+ BEGIN
+ MENUITEM "&Jump to time\tCtrl+J", WINAMP_JUMP
+ MENUITEM "&Rewind 5 seconds\tLeft Arrow", WINAMP_REW5S
+ MENUITEM "&Forward 5 seconds\tRight Arrow", WINAMP_FFWD5S
+ END
+ POPUP "Shuffle"
+ BEGIN
+ MENUITEM "&Shuffle\tS", WINAMP_FILE_SHUFFLE
+ END
+ POPUP "Repeat"
+ BEGIN
+ MENUITEM "&Repeat\tR", WINAMP_FILE_REPEAT
+ MENUITEM "&Manual Playlist Advance\tShift+R", WINAMP_FILE_MANUALPLADVANCE
+ END
+ POPUP "EQ button"
+ BEGIN
+ MENUITEM "Graphical E&qualizer\tAlt+G", WINAMP_OPTIONS_EQ
+ END
+ POPUP "PE button"
+ BEGIN
+ MENUITEM "Playlist &Editor\tAlt+E", WINAMP_OPTIONS_PLEDIT
+ END
+ POPUP "VideoWnd"
+ BEGIN
+ MENUITEM "&Fullscreen\tAlt+Enter", ID_VIDEOWND_ZOOMFULLSCREEN
+ MENUITEM SEPARATOR
+ MENUITEM "&Normal size\t1", ID_VIDEOWND_ZOOM100
+ MENUITEM "&Half size\t` or 3", ID_VIDEOWND_ZOOM50
+ MENUITEM "&Double size\t2", ID_VIDEOWND_ZOOM200
+ MENUITEM SEPARATOR
+ MENUITEM "Vertically &flip\tShift+F", ID_VIDEOWND_VERTICALLYFLIP
+ MENUITEM SEPARATOR
+ POPUP "&Audio track"
+ BEGIN
+ MENUITEM "Track 1", ID_VID_AUDIO0
+ END
+ POPUP "&Video track"
+ BEGIN
+ MENUITEM "Track 1", ID_VID_VIDEO0
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Video &options...", ID_VIDEOWND_VIDEOOPTIONS
+ END
+ END
+ POPUP "EQContext"
+ BEGIN
+ POPUP "enbut"
+ BEGIN
+ MENUITEM "&EQ enabled\tN", EQ_ENABLE
+ END
+ POPUP "albut"
+ BEGIN
+ MENUITEM "&EQ autoloading enabled\tA", EQ_AUTO
+ END
+ END
+ POPUP "Prefs"
+ BEGIN
+ POPUP "Skin"
+ BEGIN
+ MENUITEM "&Switch to skin", ID_PREFS_SKIN_SWITCHTOSKIN
+ MENUITEM SEPARATOR
+ MENUITEM "&Rename skin...", ID_PREFS_SKIN_RENAMESKIN
+ MENUITEM "&Delete skin...", ID_PREFS_SKIN_DELETESKIN
+ END
+ POPUP "Lang"
+ BEGIN
+ MENUITEM "&Switch to language pack", ID_LANG_SWITCHTOLANGUAGEPACK
+ MENUITEM SEPARATOR
+ MENUITEM "&Rename language pack...", ID_LANG_RENAMELANGUAGEPACK
+ MENUITEM "&Delete language pack...", ID_LANG_DELETELANGUAGEPACK
+ END
+ END
+END
+
+WINAMP5_MENUBAR MENUEX
+BEGIN
+ POPUP "File", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Play &file... \tL", 40029,MFT_STRING,MFS_ENABLED
+ MENUITEM "Play &URL...\tCtrl+L", 40185,MFT_STRING,MFS_ENABLED
+ MENUITEM "Play &folder...\tShift+L", 40187,MFT_STRING,MFS_ENABLED
+ POPUP "Play &bookmark", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&Edit bookmarks...\tCtrl+Alt+I", 40320,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Add current as bookmark\tCtrl+Alt+B", 40321,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ END
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "Open &playlist\tCtrl+O", 40202,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Save playlist\tCtrl+S", 40204,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Add media to Library...", 40344,MFT_STRING,MFS_ENABLED
+ MENUITEM "Add current playlist to Library", ID_FILE_ADDCURRENTPLAYLISTTOLIBRARY,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&View file info...\tAlt+3", 40188,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "E&xit\tAlt+F4", 40001,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "Play", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "P&revious\tZ", 40044,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Play\tX", 40045,MFT_STRING,MFS_ENABLED
+ MENUITEM "P&ause\tC", 40046,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Stop\tV", 40047,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Next \tB", 40048,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ POPUP "&Advanced Playback", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&Start of list\tCtrl+Z", 40154,MFT_STRING,MFS_ENABLED
+ MENUITEM "Stop w/ fa&deout\tShift+V", 40147,MFT_STRING,MFS_ENABLED
+ MENUITEM "Stop after &current\tCtrl+V", 40157,MFT_STRING,MFS_ENABLED
+ END
+ MENUITEM MFT_SEPARATOR
+ POPUP "&Jump to", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Ju&mp to track\tJ", 40194,MFT_STRING,MFS_ENABLED
+ MENUITEM "Jump 10 t&racks back\tNum. 1", 40197,MFT_STRING,MFS_ENABLED
+ MENUITEM "Jump 10 &tracks fwd\tNum. 3", 40195,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Jump to time\tCtrl+J", 40193,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Start of list\tCtrl+Z", 40154,MFT_STRING,MFS_ENABLED
+ MENUITEM "&End of list\tCtrl+B", 40158,MFT_STRING,MFS_ENABLED
+ END
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Back 5 seconds\tLeft", 40144,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Fwd 5 seconds\tRight", 40148,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Repeat\tR", 40022,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Shuffle\tS", 40023,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "Volume &Up\tUp", 40351,MFT_STRING,MFS_ENABLED
+ MENUITEM "Volume &Down\tDown", 40352,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "Options", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ POPUP "&Skins", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "S&kin Browser...\tAlt+S", 40219,MFT_STRING,MFS_ENABLED
+ MENUITEM "<< Get more skins! >>", 40316,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "Winamp Classic", 32767,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "&Visualization", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Start/Stop &plug-in\tCtrl+Shift+K", 40192,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Configure plug-in... \tAlt+K", 40221,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Select plug-in...\tCtrl+K", 40191,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "&Equalizer", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&EQ enabled", 40244,MFT_STRING,MFS_ENABLED
+ POPUP "&Load Preset", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&Preset...", 40172,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Auto-load preset...", 40173,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Default", 40174,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "From &EQF...", 40253,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "&Save Preset", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&Preset...", 40175,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Auto-load preset...", 40176,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Default", 40177,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "To &EQF...", 40254,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "&Delete Preset", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&Preset...", 40178,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Auto-load preset...", 40180,MFT_STRING,MFS_ENABLED
+ END
+ END
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "Time &elapsed\tCtrl+T toggles", 40037,MFT_STRING,MFS_ENABLED
+ MENUITEM "Time re&maining\tCtrl+T toggles", 40038,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Always On Top\tCtrl+A", 40019,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Double Size\tCtrl+D", 40165,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Preferences... \tCtrl+P", 40012,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "Windows", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Playlist &Editor\tAlt+E", 40040,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Video\tAlt+V", 40328,MFT_STRING,MFS_ENABLED
+ MENUITEM "Visualizations\tCtrl+Shift+K", 40192,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "Help", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Winamp Help\tF1", 40347,MFT_STRING,MFS_ENABLED
+ MENUITEM "Send &Feedback", 40464,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "About &Winamp...\tCtrl+F1", 40041,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "PE_File", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&New playlist (clear)\tCtrl+N", 40214,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Open playlist\tCtrl+O", 40202,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Add file(s)\tL", 1032,MFT_STRING,MFS_ENABLED
+ MENUITEM "Add &folder\tShift+L", 1036,MFT_STRING,MFS_ENABLED
+ MENUITEM "Add UR&L\tCtrl+L", 1039,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Save playlist\tCtrl+S", 40204,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "File &info\tAlt+3", 40188,MFT_STRING,MFS_ENABLED
+ MENUITEM "Playlist &entry\tCtrl+E", 40255,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Close playlist editor\tAlt+E", 40224,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "PE_Playlist", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Select &all\tCtrl+Alt+A", 40205,MFT_STRING,MFS_ENABLED
+ MENUITEM "Select &none", 40207,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Invert selection\tCtrl+I", 40171,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Remove selected\tDelete", 1034,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Crop selected\tCtrl+Delete", 1035,MFT_STRING,MFS_ENABLED
+ MENUITEM "C&lear playlist\tCtrl+Shift+Delete", 40214,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "Remove &missing files from playlist\tAlt+Delete", 40222,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Physically remove selected file(s)", 40223,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "Playlist pre&ferences...", 40358,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "PE_Sort", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Sort list by &title\tCtrl+Shift+1", 40209,MFT_STRING,MFS_ENABLED
+ MENUITEM "Sort list by &filename\tCtrl+Shift+2", 40210,MFT_STRING,MFS_ENABLED
+ MENUITEM "Sort list by &path and filename\tCtrl+Shift+3", 40211,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "R&everse list\tCtrl+R", 40213,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Randomize list\tCtrl+Shift+R", 40212,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "ML_File", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "&New playlist\tShift+Ins", 40359,MFT_STRING,MFS_ENABLED
+ MENUITEM "Import &current playlist", 40374,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Import playlist from file", 40360,MFT_STRING,MFS_ENABLED
+ MENUITEM "&Export playlist", 40361,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Add media to Library...", 40344,MFT_STRING,MFS_ENABLED
+ MENUITEM "Add current playlist to Library", ID_FILE_ADDCURRENTPLAYLISTTOLIBRARY,MFT_STRING,MFS_ENABLED
+ MENUITEM MFT_SEPARATOR
+ MENUITEM "&Close Media Library\tAlt+L", 40380,MFT_STRING,MFS_ENABLED
+ END
+ POPUP "ML_View", 65535,MFT_STRING,MFS_ENABLED
+ BEGIN
+ MENUITEM "Media Library &Preferences...", 40372,MFT_STRING | MFT_RIGHTJUSTIFY,MFS_ENABLED
+ END
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""wasabicfg.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+ICON_XP ICON "resource/WinampIcon.ico"
+
+IDI_FILEICON ICON "resource/icon2.ico"
+
+IDI_FILEICON2 ICON "resource/icon3.ico"
+
+IDI_FILEICON3 ICON "resource/icon13.ico"
+
+IDI_FILEICON10 ICON "resource/icon5.ico"
+
+IDI_FILEICON5 ICON "resource/icon12.ico"
+
+IDI_FILEICON6 ICON "resource/icon7.ico"
+
+IDI_FILEICON7 ICON "resource/icon8.ico"
+
+IDI_FILEICON8 ICON "resource/icon9.ico"
+
+IDI_FILEICON9 ICON "resource/icon10.ico"
+
+IDI_FILEICON4 ICON "resource/icon11.ico"
+
+IDI_FILEICON11 ICON "resource/icon6.ico"
+
+ICON_TB1 ICON "resource/icon1.ico"
+
+IDI_TBICON1 ICON "resource/TBICON1.ico"
+
+IDI_TBICON2 ICON "resource/TBICON2.ico"
+
+IDI_TBICON3 ICON "resource/TBICON3.ico"
+
+IDI_TBICON4 ICON "resource/TBICON4.ico"
+
+IDI_TBICON5 ICON "resource/TBICON5.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR_MAIN ACCELERATORS
+BEGIN
+ VK_F4, ID_PE_CLOSE, VIRTKEY, CONTROL, NOINVERT
+ VK_NUMPAD4, WINAMP_BUTTON1, VIRTKEY, NOINVERT
+ "Z", WINAMP_BUTTON1, VIRTKEY, NOINVERT
+ "Z", WINAMP_BUTTON1_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "Z", WINAMP_BUTTON1_SHIFT, VIRTKEY, SHIFT, NOINVERT
+ VK_NUMPAD5, WINAMP_BUTTON2, VIRTKEY, NOINVERT
+ "X", WINAMP_BUTTON2, VIRTKEY, NOINVERT
+ "C", WINAMP_BUTTON3, VIRTKEY, NOINVERT
+ "V", WINAMP_BUTTON4, VIRTKEY, NOINVERT
+ "V", WINAMP_BUTTON4_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "V", WINAMP_BUTTON4_SHIFT, VIRTKEY, SHIFT, NOINVERT
+ "B", WINAMP_BUTTON5, VIRTKEY, NOINVERT
+ VK_NUMPAD6, WINAMP_BUTTON5, VIRTKEY, NOINVERT
+ "B", WINAMP_BUTTON5_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "B", WINAMP_BUTTON5_SHIFT, VIRTKEY, SHIFT, NOINVERT
+ "I", WINAMP_EDIT_BOOKMARKS, VIRTKEY, CONTROL, ALT, NOINVERT
+ "3", WINAMP_EDIT_ID3, VIRTKEY, ALT, NOINVERT
+ "S", WINAMP_SELSKIN, VIRTKEY, ALT, NOINVERT
+ VK_NUMPAD9, WINAMP_FFWD5S, VIRTKEY, NOINVERT
+ VK_RIGHT, WINAMP_FFWD5S, VIRTKEY, NOINVERT
+ "L", WINAMP_FILE_DIR, VIRTKEY, SHIFT, NOINVERT
+ VK_INSERT, WINAMP_FILE_DIR, VIRTKEY, NOINVERT
+ "L", WINAMP_FILE_LOC, VIRTKEY, CONTROL, NOINVERT
+ VK_NUMPAD0, WINAMP_FILE_LOC, VIRTKEY, CONTROL, NOINVERT
+ "X", WINAMP_FILE_LOC, VIRTKEY, CONTROL, NOINVERT
+ "R", WINAMP_FILE_MANUALPLADVANCE, VIRTKEY, SHIFT, NOINVERT
+ "L", WINAMP_FILE_PLAY, VIRTKEY, NOINVERT
+ VK_NUMPAD0, WINAMP_FILE_PLAY, VIRTKEY, NOINVERT
+ "X", WINAMP_FILE_PLAY, VIRTKEY, SHIFT, NOINVERT
+ "R", WINAMP_FILE_REPEAT, VIRTKEY, NOINVERT
+ "S", WINAMP_FILE_SHUFFLE, VIRTKEY, NOINVERT
+ VK_NUMPAD1, WINAMP_JUMP10BACK, VIRTKEY, NOINVERT
+ VK_NUMPAD3, WINAMP_JUMP10FWD, VIRTKEY, NOINVERT
+ "J", WINAMP_JUMPFILE, VIRTKEY, NOINVERT
+ VK_DECIMAL, WINAMP_JUMPFILE, VIRTKEY, NOINVERT
+ "A", WINAMP_OPTIONS_AOT, VIRTKEY, CONTROL, NOINVERT
+ VK_F3, WINAMP_PE_SEARCH, VIRTKEY, NOINVERT
+ VK_F5, WINAMP_REFRESHSKIN, VIRTKEY, NOINVERT
+ VK_LEFT, WINAMP_REW5S, VIRTKEY, NOINVERT
+ VK_NUMPAD7, WINAMP_REW5S, VIRTKEY, NOINVERT
+ VK_DOWN, WINAMP_VOLUMEDOWN, VIRTKEY, NOINVERT
+ VK_NUMPAD2, WINAMP_VOLUMEDOWN, VIRTKEY, NOINVERT
+ VK_NUMPAD8, WINAMP_VOLUMEUP, VIRTKEY, NOINVERT
+ VK_UP, WINAMP_VOLUMEUP, VIRTKEY, NOINVERT
+ "E", WINAMP_OPTIONS_EASYMOVE, VIRTKEY, CONTROL, NOINVERT
+END
+
+IDR_ACCELERATOR_PL ACCELERATORS
+BEGIN
+ VK_END, ID_PE_BOTTOM, VIRTKEY, NOINVERT
+ VK_DOWN, ID_PE_SCDOWN, VIRTKEY, NOINVERT
+ VK_NEXT, ID_PE_SCROLLDOWN, VIRTKEY, NOINVERT
+ VK_PRIOR, ID_PE_SCROLLUP, VIRTKEY, NOINVERT
+ VK_UP, ID_PE_SCUP, VIRTKEY, NOINVERT
+ VK_SPACE, ID_PE_SHOWPLAYING, VIRTKEY, NOINVERT
+ VK_HOME, ID_PE_TOP, VIRTKEY, NOINVERT
+ VK_INSERT, IDC_PLAYLIST_ADDDIR, VIRTKEY, NOINVERT
+ "L", IDC_PLAYLIST_ADDMP3, VIRTKEY, NOINVERT
+ VK_NUMPAD0, IDC_PLAYLIST_ADDMP3, VIRTKEY, NOINVERT
+ VK_RETURN, IDC_PLAYLIST_PLAY, VIRTKEY, NOINVERT
+ VK_DELETE, IDC_PLAYLIST_REMOVEMP3, VIRTKEY, NOINVERT
+ VK_NUMPAD4, WINAMP_BUTTON1, VIRTKEY, NOINVERT
+ "Z", WINAMP_BUTTON1, VIRTKEY, NOINVERT
+ VK_NUMPAD5, WINAMP_BUTTON2, VIRTKEY, NOINVERT
+ "X", WINAMP_BUTTON2, VIRTKEY, NOINVERT
+ "C", WINAMP_BUTTON3, VIRTKEY, NOINVERT
+ "V", WINAMP_BUTTON4, VIRTKEY, NOINVERT
+ "B", WINAMP_BUTTON5, VIRTKEY, NOINVERT
+ VK_NUMPAD6, WINAMP_BUTTON5, VIRTKEY, NOINVERT
+ VK_NUMPAD9, WINAMP_FFWD5S, VIRTKEY, NOINVERT
+ VK_RIGHT, WINAMP_FFWD5S, VIRTKEY, NOINVERT
+ "R", WINAMP_FILE_REPEAT, VIRTKEY, NOINVERT
+ "S", WINAMP_FILE_SHUFFLE, VIRTKEY, NOINVERT
+ VK_NUMPAD1, WINAMP_JUMP10BACK, VIRTKEY, NOINVERT
+ VK_NUMPAD3, WINAMP_JUMP10FWD, VIRTKEY, NOINVERT
+ "J", WINAMP_JUMPFILE, VIRTKEY, NOINVERT
+ VK_DECIMAL, WINAMP_JUMPFILE, VIRTKEY, NOINVERT
+ VK_F3, WINAMP_PE_SEARCH, VIRTKEY, NOINVERT
+ VK_F5, WINAMP_REFRESHSKIN, VIRTKEY, NOINVERT
+ VK_LEFT, WINAMP_REW5S, VIRTKEY, NOINVERT
+ VK_NUMPAD7, WINAMP_REW5S, VIRTKEY, NOINVERT
+ VK_NUMPAD2, WINAMP_VOLUMEDOWN, VIRTKEY, NOINVERT
+ VK_NUMPAD8, WINAMP_VOLUMEUP, VIRTKEY, NOINVERT
+ "N", ID_PE_CLEAR, VIRTKEY, CONTROL, NOINVERT
+ VK_F4, ID_PE_CLOSE, VIRTKEY, CONTROL, NOINVERT
+ "E", ID_PE_ENTRY, VIRTKEY, CONTROL, NOINVERT
+ "F", ID_PE_FFOD, VIRTKEY, CONTROL, NOINVERT
+ VK_ADD, ID_PE_FONTBIGGER, VIRTKEY, CONTROL, NOINVERT
+ VK_RETURN, ID_PE_FONTRESET, VIRTKEY, CONTROL, NOINVERT
+ VK_SUBTRACT, ID_PE_FONTSMALLER, VIRTKEY, CONTROL, NOINVERT
+ "R", ID_PE_S_REV, VIRTKEY, CONTROL, NOINVERT
+ "A", ID_PE_SELECTALL, VIRTKEY, CONTROL, NOINVERT
+ "L", IDC_PLAYLIST_ADDLOC, VIRTKEY, CONTROL, NOINVERT
+ VK_NUMPAD0, IDC_PLAYLIST_ADDLOC, VIRTKEY, CONTROL, NOINVERT
+ VK_INSERT, IDC_PLAYLIST_ADDMP3, VIRTKEY, CONTROL, NOINVERT
+ VK_DELETE, IDC_PLAYLIST_CROP, VIRTKEY, CONTROL, NOINVERT
+ "I", IDC_SELECTINV, VIRTKEY, CONTROL, NOINVERT
+ "Z", WINAMP_BUTTON1_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "V", WINAMP_BUTTON4_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "B", WINAMP_BUTTON5_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "X", WINAMP_FILE_LOC, VIRTKEY, CONTROL, NOINVERT
+ "I", ID_PE_BOOKMARK, VIRTKEY, ALT, NOINVERT
+ "3", ID_PE_ID3, VIRTKEY, ALT, NOINVERT
+ VK_DOWN, ID_PE_MOVEDOWN, VIRTKEY, ALT, NOINVERT
+ VK_UP, ID_PE_MOVEUP, VIRTKEY, ALT, NOINVERT
+ VK_DELETE, ID_PE_NONEXIST, VIRTKEY, ALT, NOINVERT
+ "S", WINAMP_SELSKIN, VIRTKEY, ALT, NOINVERT
+ "E", ID_PE_EXTINFO, VIRTKEY, CONTROL, ALT, NOINVERT
+ "G", ID_PE_PRINT, VIRTKEY, CONTROL, ALT, NOINVERT
+ "A", WINAMP_OPTIONS_AOT, VIRTKEY, CONTROL, ALT, NOINVERT
+ VK_DOWN, ID_PE_SCDOWN, VIRTKEY, SHIFT, NOINVERT
+ VK_UP, ID_PE_SCUP, VIRTKEY, SHIFT, NOINVERT
+ "L", IDC_PLAYLIST_ADDDIR, VIRTKEY, SHIFT, NOINVERT
+ VK_INSERT, IDC_PLAYLIST_ADDLOC, VIRTKEY, SHIFT, NOINVERT
+ "Z", WINAMP_BUTTON1_SHIFT, VIRTKEY, SHIFT, NOINVERT
+ "V", WINAMP_BUTTON4_SHIFT, VIRTKEY, SHIFT, NOINVERT
+ "B", WINAMP_BUTTON5_SHIFT, VIRTKEY, SHIFT, NOINVERT
+ "X", WINAMP_FILE_PLAY, VIRTKEY, SHIFT, NOINVERT
+ VK_DELETE, ID_PE_CLEAR, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "2", ID_PE_S_FILENAME, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "3", ID_PE_S_PATH, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "R", ID_PE_S_RANDOM, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "1", ID_PE_S_TITLE, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "E", ID_PE_EDIT_SEL, VIRTKEY, SHIFT, NOINVERT
+END
+
+IDR_ACCELERATOR_EQ ACCELERATORS
+BEGIN
+ "A", EQ_AUTO, VIRTKEY, NOINVERT
+ "Q", EQ_DEC1, VIRTKEY, NOINVERT
+ "P", EQ_DEC10, VIRTKEY, NOINVERT
+ "W", EQ_DEC2, VIRTKEY, NOINVERT
+ "E", EQ_DEC3, VIRTKEY, NOINVERT
+ "R", EQ_DEC4, VIRTKEY, NOINVERT
+ "T", EQ_DEC5, VIRTKEY, NOINVERT
+ "Y", EQ_DEC6, VIRTKEY, NOINVERT
+ "U", EQ_DEC7, VIRTKEY, NOINVERT
+ "I", EQ_DEC8, VIRTKEY, NOINVERT
+ "O", EQ_DEC9, VIRTKEY, NOINVERT
+ VK_TAB, EQ_DECPRE, VIRTKEY, NOINVERT
+ "N", EQ_ENABLE, VIRTKEY, NOINVERT
+ "1", EQ_INC1, VIRTKEY, NOINVERT
+ "0", EQ_INC10, VIRTKEY, NOINVERT
+ "2", EQ_INC2, VIRTKEY, NOINVERT
+ "3", EQ_INC3, VIRTKEY, NOINVERT
+ "4", EQ_INC4, VIRTKEY, NOINVERT
+ "5", EQ_INC5, VIRTKEY, NOINVERT
+ "6", EQ_INC6, VIRTKEY, NOINVERT
+ "7", EQ_INC7, VIRTKEY, NOINVERT
+ "8", EQ_INC8, VIRTKEY, NOINVERT
+ "9", EQ_INC9, VIRTKEY, NOINVERT
+ VK_OEM_3, EQ_INCPRE, VIRTKEY, NOINVERT
+ VK_LEFT, EQ_PANLEFT, VIRTKEY, NOINVERT
+ VK_RIGHT, EQ_PANRIGHT, VIRTKEY, NOINVERT
+ "S", EQ_PRESETS, VIRTKEY, NOINVERT
+ VK_F4, ID_PE_CLOSE, VIRTKEY, CONTROL, NOINVERT
+ "S", IDM_EQ_LOADPRE, VIRTKEY, CONTROL, ALT, NOINVERT
+ "Z", WINAMP_BUTTON1, VIRTKEY, NOINVERT
+ "Z", WINAMP_BUTTON1_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "X", WINAMP_BUTTON2, VIRTKEY, NOINVERT
+ "C", WINAMP_BUTTON3, VIRTKEY, NOINVERT
+ "V", WINAMP_BUTTON4, VIRTKEY, NOINVERT
+ "V", WINAMP_BUTTON4_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "V", WINAMP_BUTTON4_SHIFT, VIRTKEY, SHIFT, NOINVERT
+ "B", WINAMP_BUTTON5, VIRTKEY, NOINVERT
+ "B", WINAMP_BUTTON5_CTRL, VIRTKEY, CONTROL, NOINVERT
+ "X", WINAMP_FILE_LOC, VIRTKEY, CONTROL, NOINVERT
+ "X", WINAMP_FILE_PLAY, VIRTKEY, SHIFT, NOINVERT
+ "J", WINAMP_JUMPFILE, VIRTKEY, NOINVERT
+ VK_DECIMAL, WINAMP_JUMPFILE, VIRTKEY, NOINVERT
+ "A", WINAMP_OPTIONS_AOT, VIRTKEY, CONTROL, NOINVERT
+ VK_RETURN, WINAMP_VIDEO_TOGGLE_FS, VIRTKEY, ALT, NOINVERT
+ VK_DOWN, WINAMP_VOLUMEDOWN, VIRTKEY, NOINVERT
+ VK_UP, WINAMP_VOLUMEUP, VIRTKEY, NOINVERT
+ "E", WINAMP_OPTIONS_EASYMOVE, VIRTKEY, CONTROL, NOINVERT
+END
+
+IDR_ACCELERATOR_GLOBAL ACCELERATORS
+BEGIN
+ VK_F1, ID_HELP_HELPTOPICS, VIRTKEY, NOINVERT
+ "B", WINAMP_BROWSER_ID, VIRTKEY, ALT, NOINVERT
+ VK_F4, WINAMP_FILE_QUIT, VIRTKEY, ALT, NOINVERT
+ VK_F1, WINAMP_HELP_ABOUT, VIRTKEY, CONTROL, NOINVERT
+ "J", WINAMP_JUMP, VIRTKEY, CONTROL, NOINVERT
+ "W", WINAMP_MAIN_WINDOW, VIRTKEY, ALT, NOINVERT
+ "F", WINAMP_MAINMENU, VIRTKEY, ALT, NOINVERT
+ "B", WINAMP_MAKECURBOOKMARK, VIRTKEY, CONTROL, ALT, NOINVERT
+ "M", WINAMP_MINIMIZE, VIRTKEY, ALT, NOINVERT
+ "N", WINAMP_NEW_INSTANCE, VIRTKEY, CONTROL, ALT, NOINVERT
+ VK_TAB, WINAMP_NEXT_WINDOW, VIRTKEY, CONTROL, NOINVERT
+ "D", WINAMP_OPTIONS_DSIZE, VIRTKEY, CONTROL, NOINVERT
+ "G", WINAMP_OPTIONS_EQ, VIRTKEY, ALT, NOINVERT
+ "T", WINAMP_OPTIONS_MINIBROWSER, VIRTKEY, ALT, NOINVERT
+ "E", WINAMP_OPTIONS_PLEDIT, VIRTKEY, ALT, NOINVERT
+ "P", WINAMP_OPTIONS_PREFS, VIRTKEY, CONTROL, NOINVERT
+ "T", WINAMP_OPTIONS_TOGTIME, VIRTKEY, CONTROL, NOINVERT
+ "V", WINAMP_OPTIONS_VIDEO, VIRTKEY, ALT, NOINVERT
+ "W", WINAMP_OPTIONS_WINDOWSHADE_GLOBAL, VIRTKEY, CONTROL, NOINVERT
+ "K", WINAMP_PLGSETUP, VIRTKEY, CONTROL, NOINVERT
+ "O", WINAMP_PLGSETUP, VIRTKEY, ALT, NOINVERT
+ VK_RETURN, WINAMP_VIDEO_TOGGLE_FS, VIRTKEY, ALT, NOINVERT
+ "K", WINAMP_VISCONF, VIRTKEY, ALT, NOINVERT
+ "K", WINAMP_VISPLUGIN, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "O", ID_PE_OPEN, VIRTKEY, CONTROL, NOINVERT
+ "S", ID_PE_SAVEAS, VIRTKEY, CONTROL, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_MOVEMAIN CURSOR "resource/move.cur"
+
+IDC_LRSCROLL CURSOR "resource/lrscroll.cur"
+
+IDC_DANGER CURSOR "resource/danger.cur"
+
+IDC_NORMALCURSOR CURSOR "resource/danger1.cur"
+
+IDC_UDSCROLL CURSOR "resource/cur00001.cur"
+
+IDC_RESIZE CURSOR "resource/resize.cur"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RCDATA
+//
+
+IDB_OSD RCDATA "resource\\OSD-Sprite-Controls.png"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// HTML
+//
+
+IDR_ATF_HTML HTML "resource\\atf.htm"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_P_SELECT_LANGDIR "Select Winamp Language Pack Directory"
+ IDS_P_LANG_ERR_RENAME "Error renaming language file"
+ IDS_P_LANG_ERR_RENAME_TITLE "Language File Rename Error"
+ IDS_LOCALIZATION "Localization"
+ IDS_NO_MATCHES_FOUND "No matches were found\t"
+ IDS_GRACENOTE_TOOLS_NOT_INSTALLED
+ "CDDB tools are unavailable in this release"
+ IDS_NO_MATCH_FOUND "No match found"
+ IDS_FAILED "Failed"
+ IDS_SHUFFLE_MORPH_INFO "Shuffle morph rate controls how songs within playlists are selected during shuffle playback.\n\nSlow shuffle morphing causes a slight variation of the playlist order, whereas fast\nshuffle morphing causes major variations of the playlist order."
+ IDS_SHUFFLE_MORPH_RATE "Shuffle Morph Rate"
+ IDS_ADD_FOLDER "Add Folder"
+ IDS_ADD_URL "Add URL"
+ IDS_SHOW_ALL_HISTORY "Show All History"
+ IDS_P_LNG_CHDR "This button lets you change the directory where you keep your language packages."
+ IDS_P_DISP_SPLEDPOS "Shows the playlist item position in the Windows taskbar if selected."
+ IDS_IMAGE_FILES "Image Files"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_LOCALIZED_HOMEPAGE "http://www.winamp.com"
+ IDS_AUTHOR_HOMEPAGE2 "http://www.winamp.com"
+ IDS_AUTHOR_HOMEPAGE "http://www.winamp.com"
+ 65534 "en-US"
+ 65535 "{A0099AA7-F980-45cf-818D-64EAA9F4EF4B}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_LANG_INSTALL_PROMPT "Are you sure that you want to install this Winamp Language Pack?\n\nWe recommend that you only install language packs from sources that\nyou trust. If you do not trust the source of this language pack, click No.\t"
+ IDS_LANG_INSTALL_HEADER "Winamp Language Pack Install"
+ IDS_PLEDIT_NOFILE_WSHADE "<no file>"
+ IDS_AUDIO_CD_FORMAT "Audio CD %c:"
+ IDS_CLASSIC_SKIN_NAME "Winamp Classic"
+ IDS_CLASSIC_BASE_SKIN_VERSION "Winamp base skin v%s"
+ IDS_OSD_PROGRESS_TEXT "Progress "
+ IDS_OSD_VOLUME_TEXT "Volume "
+ IDS_REFRESH_PLAYLIST_TITLES "Refresh playlist titles"
+ IDS_ATF_HAS_CHANGED "Your advanced title formatting string has been changed.\nWould you like to refresh the titles in your current playlist?"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_PREAMP "Preamp"
+ IDS_OPTIONS_MENU "Options Menu"
+ IDS_DISABLE_AOT "Disable Always-On-Top"
+ IDS_ENABLE_AOT "Enable Always-On-Top"
+ IDS_FILE_INFO_BOX "File Info Box"
+ IDS_DISABLE_DOUBLESIZE_MODE "Disable Doublesize Mode"
+ IDS_ENABLE_DOUBLESIZE_MODE "Enable Doublesize Mode"
+ IDS_VISUALIZATION_MENU "Visualization Menu"
+ IDS_SEEK_TO "Seek To"
+ IDS_VOLUME "Volume"
+ IDS_BALANCE "Balance"
+ IDS_BALANCE_CENTRE "Balance: Center"
+ IDS_BALANCE_LEFT "left"
+ IDS_BALANCE_RIGHT "right"
+ IDS_TITLE_ON_STOP "%s - %S [Stopped]"
+ IDS_TITLE_ON_PAUSE "%s - %S [Paused]"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_BURN_NULLSOFT_STR "Nullsoft Winamp Burner"
+ IDS_BURN_LIBRARY_INIT_FAILED "Unable to initialize burning library."
+ IDS_BURN_INVALID_PLAYLIST_PATH "Unable to read playlist path."
+ IDS_BURN_INVALID_TEMP_PATH "Unable to get temporary path."
+ IDS_BURN_INVALID_CONFIG_PATH "Unable to get config path."
+ IDS_BURN_INVALID_CMDLINE "Incorrect command line."
+ IDS_BURN_BAD_DRIVE_LETTER "Bad drive letter."
+ IDS_BURN_LOAD_FROM_PLAYLIST_FAIL "Unable to load files from the playlist."
+ IDS_BURN_CREATE_DIALOG_FAIL "Unable to create burner dialog."
+ IDS_BURN_UNKNOWN_ERROR "Unknown Error."
+ IDS_BURN_INIT_ERROR_REASON "Burner Initialization Error!\nReason: %s"
+ IDS_BURN_INIT_ERROR_UNKNOWN
+ "Burner Initialization Error!\nReason: Unknown error."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_CONV_SRC_EQUALS_DEST "Source file and destination file are identical"
+ IDS_CONV_DECODER_MISSING "Cannot find decoder"
+ IDS_CONV_INPUT_PLUGIN_NOT_SUPPORTING
+ "Input plug-in doesn't support transcoding"
+ IDS_CONV_DRM_DECODE_FAIL "Cannot decode DRM file"
+ IDS_CONV_ERROR_OPEN_FILE "Error opening file for decoding"
+ IDS_CONV_ERROR_OPEN_ENCODER "Cannot open encoder"
+ IDS_CONV_ERROR_OPEN_DEST "Cannot open destination file"
+ IDS_NOTPRESENT "not present"
+ IDS_ARTDELETE "Are you sure you want to delete this artwork? This action can't be undone."
+ IDS_AREYOUSURE "Are you sure?"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_PLAYLIST_LOAD_ERROR "Error loading playlist"
+ IDS_OPEN_PLAYLIST "Open Playlist"
+ IDS_ADD_PLAYLIST "Add Playlist"
+ IDS_SAVE_PLAYLIST "Save playlist"
+ IDS_PLAYLIST_FILTER_STRING
+ "M3U Playlist|*.m3u|PLS Playlist|*.pls|M3U8 (Unicode) Playlist|*.m3u8||"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_SKIN_ERR_RENAME_TITLE "Skin Rename Error"
+ IDS_P_TAGZ_ERROR_TITLE "Help"
+ IDS_P_TAGZ_NOT_INSTALLED "ATF not installed"
+ IDS_WINAMP_MENUITEM "About &Winamp...\tCtrl+F1"
+ IDS_ML_MISSING_FOR_BOOKMARKS
+ "You must have the Winamp Library installed to edit your bookmarks"
+ IDS_PLAYLIST_SUPPORT_NOT_INSTALLED
+ "Playlist support not available.\nPlease re-install Winamp."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_PLAYBACK_RG_MODE_AG_PC "Apply Gain / Prevent Clipping"
+ IDS_P_PLAYBACK_RG_MODE_N "Normalize"
+ IDS_P_PLAYBACK_RG_MODE_PC "Prevent Clipping"
+ IDS_P_24BIT_WARNING "Warning:\nSelecting 24 bit output might cause unexpected problems.\n\n*\tMany DSP plug-ins do not work with 24bit output.\n*\tMany soundcards have hardware limitations and driver limitations\n\tthat prevent 24 bit output from working fully.\n\nIt is recommended to keep this option off.\n\nReally enable 24 bit support?\n"
+ IDS_P_24BIT_WARNING_TITLE "Compatability warning"
+ IDS_P_PLDIRECTION_AUTO "Automatic, based on my locale settings"
+ IDS_P_PLDIRECTION_L2R "Force left-to-right order"
+ IDS_P_PLDIRECTION_R2L "Force right-to-left order"
+ IDS_P_SELECT_SKINDIR "Select Winamp Skin Directory"
+ IDS_P_SKIN_NO_INFO_FOUND "<no info found>"
+ IDS_P_SKIN_ERR_RENAME "Error renaming skin"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_SENDTO_STR "Send to:"
+ IDS_RATEITEM_STR "Rate items"
+ IDS_ERROR_DELETING "Error deleting %s"
+ IDS_PREFS_PLAYBACK "Playback"
+ IDS_P_CLASSIC_70FPS "70fps"
+ IDS_P_CLASSIC_35FPS "35fps"
+ IDS_P_CLASSIC_18FPS "18fps"
+ IDS_P_CLASSIC_9FPS "9fps"
+ IDS_P_PLUGIN_UNINSTALL "Permanently uninstall this plug-in?\n(This may require a restart of Winamp)"
+ IDS_P_PLUGIN_UNINSTALL_CONFIRM "Confirmation"
+ IDS_LANGCHANGE_TITLE "Note"
+ IDS_P_PLAYBACK_RG_SOURCE_TRACK "Track"
+ IDS_P_PLAYBACK_RG_SOURCE_ALBUM "Album"
+ IDS_P_PLAYBACK_RG_MODE_AG "Apply Gain"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_ML_NO_PLAYLISTS "No playlists in Media Library"
+ IDS_ML_OPEN_PLAYLIST "Open playlist from &Library"
+ IDS_ML_OPEN_VIEW_RESULTS "Open Library &view results"
+ 243 "&Close Playlist Editor\tAlt+E"
+ IDS_PE_OPEN "Open Playlist &Editor\tAlt+E"
+ IDS_ML_EXPORT_PLAYLIST "&Export playlist"
+ IDS_ML_CLOSE_ML "&Close Media Library\tAlt+L"
+ IDS_ML_OPEN_ML "Open Media &Library\tAlt+L"
+ IDS_ML_MANAGE_PLAYLISTS "&Manage Playlists..."
+ IDS_ML_SMART_VIEW_RESULTS "Media Library Smart &View results"
+ IDS_OFD_OPEN_FILES "Open file(s)"
+ IDS_OFD_ADD_FILES_TO_PLAYLIST "Add file(s) to playlist"
+ IDS_OFD_ALL_FILES "All files (*.*)"
+ IDS_STATIONINFOCAPTION "Station Info"
+ IDS_STATIONINFO_MENU "Station Info\tAlt+B"
+ IDS_WINAMP_UPDATE "Winamp Update"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_HTTP_FILE_INCOMPLETE "File incomplete"
+ IDS_HTTP_SUCCESS "Success!"
+ IDS_HTTP_CLOSE "Close"
+ IDS_CLOSE_COUNTDOWN "Close [%d]"
+ IDS_HTTP_WINAMP_UPDATE_SITE "Winamp Update Site"
+ IDS_HTTP_INIT "Initializing..."
+ IDS_HTTP_ABORT "Aborting..."
+ IDS_HTML_ERROR_WRITE "Error writing HTML file."
+ IDS_HTTP_RET_FILE "Retrieving file...\n%d bytes read"
+ IDS_HTTP_RET_FILE_PERCENT
+ "Retrieving file (%d%% done)\n%d of %d bytes read"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_HTTP_SOCKET_ERROR "Error creating socket"
+ IDS_HTTP_RESOLVE_PROXY "Resolving proxy"
+ IDS_HTTP_RESOLVE_HOST "Resolving host..."
+ IDS_HTTP_RESOLVE_PROXY_ERROR "Error resolving proxy"
+ IDS_HTTP_RESOLVE_HOST_ERROR "Error resolving host"
+ IDS_HTTP_CONNECT_PROXY "Connecting to proxy"
+ IDS_HTTP_CONNECT_HOST "Connecting to host..."
+ IDS_HTTP_CONNECT_PROXY_ERROR "Error connecting to proxy"
+ IDS_HTTP_CONNECT_HOST_ERROR "Error connecting to host"
+ IDS_HTTP_SEND_REQUEST "Sending HTTP request"
+ IDS_HTTP_READ_REQUEST "Reading HTTP response"
+ IDS_HTTP_CONNECTION_LOST "Connection to host lost"
+ IDS_HTTP_CONNECTION_CLOSED "\nConnection closed. "
+ IDS_HTTP_ERROR_OPEN_FILE "Error opening local file!"
+ IDS_HTTP_RETRIEVE_FILE_LENGTH
+ "Retrieving file (%d%% done)\n%d/%d bytes read @ %d.%02d KB/sec"
+ IDS_HTTP_RETRIEVE_FILE "Retrieving file...\n%d bytes read @ %d.%02d KB/sec"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_LANGUAGEPACKS_MENU "Language Packs"
+ IDS_ONLINESERVICE_SELDOWNLOADDIR "Set folder for all %s downloads."
+ IDS_WHATSNEW_FAIL "Can't find whatsnew.txt"
+ IDS_WINAMP_CMDLINE "Winamp Commandline"
+ IDS_SKINS_INSTALL_PROMPT
+ "Are you sure that you want to install this Winamp Skin?\n\nWe recommend that you only install skins from sources that you trust.\nIf you do not trust the source of this skin, click No."
+ IDS_SKINS_INSTALL_HEADER "Winamp Skin Install"
+ IDS_HTTP_LOAD_ERROR "Error loading wsock32.dll"
+ IDS_HTTP_INIT_SOCKET "Initializing winsock..."
+ IDS_HTTP_INIT_SOCKET_ERROR "Error initializing winsock"
+ IDS_HTTP_SOCKET_CREATE "Creating socket..."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_EQ_FILE_WRITE "Select file to write"
+ IDS_P_FILE_ALL "All Files"
+ IDS_NO_BOOKMARKS "No bookmarks found"
+ IDS_ART_SEARCH_PROGRESS "search in progress"
+ IDS_ART_SEARCH_STATUS "Status: %s, %d images found: %d downloaded, %d failed, %d downloading"
+ IDS_ART_SEARCH_NOT_FOUND_TITLE "Not Found"
+ IDS_ART_SEARCH_NOT_FOUND
+ "No cover art matching this album could be found."
+ IDS_NO_IMAGE "(no image)"
+ IDS_PLAYLISTSTRING_NEW "Playlist Files (%s)"
+ IDS_P_LANG_PACK_DELETEWLZ "Delete Language Pack?"
+ IDS_P_LANG_PACK_DELETEWLZ_PROMPT "Delete the language pack '%s'?"
+ IDS_RENAME_WLZ "Rename Language Pack"
+ IDS_P_O_VIDEO_FLIPRGB "Resolves issue where videos play upside-down when graphics drivers are old"
+ IDS_SELDOWNLOADDIR "Download folder"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_O_RECYCLE "Disabling this option will cause files to be deleted permanently instead of sent to the recycle bin. Affects 'physically remove file' command in both the playlist and media library."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_O_VIDEO_REMOVE_FS_ON_STOP
+ "This option will make the video window switch back from fullscreen when the playback stops"
+ IDS_P_O_VIDEO_AUTOOPEN "This option will make the video window open every time a video file is played"
+ IDS_P_CLASSICVIS "Classic Visualization"
+ IDS_P_IN_UNINST "This button will uninstall the selected input plug-in. This may require a restart of Winamp."
+ IDS_P_VIS_UNINST "This button will uninstall the selected visualization plug-in."
+ IDS_P_OUT_UNINST "This button will uninstall the selected output plug-in. This may require a restart of Winamp."
+ IDS_P_SKINS_DELETESKIN "Delete Skin?"
+ IDS_P_SKINS_DELETESKIN_PROMPT "Delete the skin '%s'?"
+ IDS_P_O_VIDEO_AGRESSIVENOSS
+ "This option makes Winamp try even harder to prevent the screensaver from coming on while playing video. Use with care, it might not be the best idea..."
+ IDS_P_PLUG_DISSEHVIS "Enabling this option disables structured exception handling (SEH) for visualization plug-ins, which lets plug-in developers more easily debug their plug-ins."
+ IDS_P_PLUG_DISSEHDSP "Enabling this option disables structured exception handling (SEH) for DSP plug-ins, which lets plug-in developers more easily debug their plug-ins."
+ IDS_P_PLUG_DISSEHGEN "Enabling this option disables structured exception handling (SEH) for general purpose plug-ins, which lets plug-in developers more easily debug their plug-ins."
+ IDS_P_SKINS_RN_ERR "Error renaming skin."
+ IDS_P_SKINS_RN_ERR_CAP "Skin Rename Error"
+ IDS_P_FILE_EQ "EQ Setting Files (*.EQF)"
+ IDS_P_EQ_FILE_READ "Select file to read"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_FILEASSOCIATIONS "This option lets the Agent maintain Winamp's file associations, so that if other software is installed that uses the same extensions, Winamp will keep them."
+ IDS_CONFIG_BOOKMARKSTR "Add to Winamp's &Bookmark list"
+ IDS_P_O_ONPLAY "Reads track info such as title or ID3 tag, as well as a track length estimate, on play only (rather than on view or load)."
+ IDS_P_O_SMS "This controls how quickly the playlist order changes (morphs) over time, when shuffle is on."
+ IDS_PREFS_SHUFFLE "Playlist"
+ IDS_VIDEOCAPTION "Winamp Video"
+ IDS_PREFS_VIDEO "Video"
+ IDS_P_O_VIDEO_VSYNC "This option enables video to sync with the vertical blank line for smoother display."
+ IDS_P_O_VIDEO_ADJASP "This option corrects the aspect ratio of the videos so they display at the correct size."
+ IDS_P_O_VIDEO_OVERLAYS "This option enables the use of the video card overlay feature (if available)."
+ IDS_P_O_VIDEO_UPDSIZE "This option will make the video window resize to the video dimensions"
+ IDS_P_O_VIDEO_AUTOCLOSE "Close video window as soon as playing is done"
+ IDS_P_O_VIDEO_NOSS "This option disables your current screen saver when a video is playing"
+ IDS_P_O_VIDEO_OSD "This option enables the On Screen Display interface when a video is playing in Fullscreen mode"
+ IDS_P_O_VIDEO_YV12 "This option enables the use of the YV12 type when overlay is enabled. It makes video updates faster when possible but some video cards don't support it well or correctly."
+ IDS_P_O_VIDEO_STOPCLOSE "This option will make the playback stop when the video window is closed"
+END
+
+STRINGTABLE
+BEGIN
+ 32767 "5.0v0"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_SETUP_INET1 "LAN internet connection"
+ IDS_P_SETUP_INET2 "Dialup modem internet connection"
+ IDS_P_SETUP_INET3 "No internet connection"
+ IDS_DSP_NONE "(none)"
+ IDS_CONFIG_PLAYSTR "&Play in Winamp"
+ IDS_CONFIG_ENQUEUESTR "&Enqueue in Winamp"
+ IDS_PREFS_SKIN "Skins"
+ IDS_P_O_MPA "This option controls whether Winamp automatically advances to the next track or not. You only want to enable it if you are DJing and want to be able to jump around without worrying about the playlist auto-advancing."
+ IDS_P_SK_SEL "This box lists available skins to enable."
+ IDS_P_SK_RND "When this is checked, Winamp will switch skins randomly on every new file played."
+ IDS_P_SK_CHDR "This button lets you change the directory where you keep your skins."
+ IDS_PREFS_CLASSICSKIN "Classic Skins"
+ IDS_PREFS_AG "Agent"
+ IDS_P_SETUP_VER2 "This option, when checked, allows Winamp to report anonymous usage information back to Nullsoft. It simply reports how much Winamp is being used, but not how you are using it."
+ IDS_P_A_ENABLE "This option enables the Winamp Agent, which runs at all times and lets you have enhanced functionality."
+ IDS_P_A_TRAY "This option, when the Agent is enabled, shows an icon in the notification area that lets you run Winamp, load your bookmarks/playlists, etc."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_PLFONT_CHARSET "1"
+ IDS_P_FT_RSTART "This option will make Winamp retake its filetypes when other programs steal them. It is recommended."
+ IDS_P_DISP_BIFONT "This option makes Winamp use its own (skinnable) font for displaying track titles. Disable this if you want to be able to see titles with non-English characters in them."
+ IDS_GETMORE "Update Links\tCtrl+Alt+R"
+ IDS_INST_DONETITLE "Winamp install information"
+ IDS_INST_CLOSE "Close Winamp"
+ IDS_P_DISP_PLPOS "If enabled this option makes Winamp display the current playlist position in the song scroller"
+ IDS_ART_SEARCH_FAILED "search failed"
+ IDS_INST_SENDINGIN "Sending in user information"
+ IDS_INST_FINISH "Run Winamp"
+ IDS_INST_INET1 "Always connected (LAN, DSL, Cable)"
+ IDS_INST_INET2 "Connected via dial-up (Modem)"
+ IDS_INST_INET3 "Not connected to the internet"
+ IDS_ART_SEARCH_FINISHED "finished search"
+ IDS_P_SETUP_VER "This option when enabled will have Winamp automatically detect whether a new version has been released and notify you of it."
+ IDS_P_SETUP_INTERNET "Select your internet connection method here."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_PREFS_PLUG_OUT "Output"
+ IDS_PREFS_PLUG_VIS "Visualization"
+ IDS_PREFS_PLUG_DSP "DSP/Effect"
+ IDS_PREFS_PLUG_GEN "General Purpose"
+ IDS_P_FT_CD "This option will associate Winamp with Audio CDs in explorer, so that when you insert a disc or click on the disc icon in explorer Winamp will automatically play it."
+ IDS_MBCAPTION "Winamp Minibrowser"
+ IDS_INETLOC "Open URL...\tCtrl+O"
+ IDS_PERMDELALL "Using this command will remove\nall selected files PERMANENTLY\nfrom disk. Are you SURE you want\nto do this?"
+ IDS_LANGCHANGE "Note that a restart of Winamp is required for the change of language pack to take effect. \n\nPress Ok to restart Winamp, or cancel to continue using Winamp\n(The language pack will be loaded on Winamp's next restart with cancel)."
+ IDS_SELLANGPACK "Open language pack (select Winamp.exe for English)"
+ IDS_DELETEAUTOLOAD1 "Delete auto-load preset"
+ IDS_DELETEAUTOLOAD2 "&Delete..."
+ IDS_DELETEPRE1 "Delete preset"
+ IDS_LOADAUTOLOAD "Load auto-load preset"
+ IDS_SAVEAUTOLOAD "Save auto-load preset"
+ IDS_PLFONT "Arial Unicode MS"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_TOOLTIPS "Toggle Windowshade Mode|Minimize|Close|Winamp Menu|Toggle Graphical Equalizer|Toggle Playlist Editor|Options Menu|Toggle Always-On-Top|File Info Box|Toggle Doublesize Mode|Visualization Menu|Volume Bar|Panning Bar|Seeking Bar|Toggle Shuffle|Toggle Repeat|About Winamp|Open file(s)|Previous Track|Play|Pause|Stop|Next Track|Time Display (click to toggle elapsed/remaining)|Song Title (right-click for options)"
+ IDS_P_SETUP_START2 "Removes Winamp items (added from the 'Add' button) from the Start Menu."
+ IDS_P_SETUP_LANG "This lets you change the current language pack for Winamp. The default is English."
+ IDS_P_FT_DIRCONTEXT "Checking this option makes Winamp add a 'play' and 'enqueue' option to directories in explorer."
+ IDS_P_DISP_SNAPW "This value controls at what distance (in pixels) Winamp windows snap to each other and to the viewport."
+ IDS_P_PLUG_VISDIR "This button lets you select the directory for Winamp visualization plug-ins. The default is <yourwinampdirectory>\\Plugins"
+ IDS_P_PLUG_DSPDIR "This button lets you select the directory for Winamp DSP/effect plug-ins. The default is <yourwinampdirectory>\\Plugins"
+ IDS_SELVISDIR "Select visualization plug-in directory"
+ IDS_SELDSPDIR "Select effect plug-in directory"
+ IDS_PREFS_SETUP "General Preferences"
+ IDS_PREFS_FT "File Types"
+ IDS_PREFS_TITLES "Titles"
+ IDS_PREFS_PLUG "Plug-ins"
+ IDS_PREFS_PLUG_IN "Input"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_FT_ICON2 "Selects the icon that Winamp playlist files use in Explorer."
+ IDS_P_SETUP_START "Adds Winamp items (program, documentation, and uninstall link) to the Start Menu."
+ IDS_PREFSHLP_FT_DESK "Adds Winamp as an icon to the Windows Desktop. Uses the currently selected file icon for the icon."
+ IDS_P_VIS_LIB "This is a list of installed visualization plug-ins. You can select one, and start/stop or configure it."
+ IDS_P_VIS_MOD "Once you have selected a plug-in, you can select a different module with this combo box."
+ IDS_P_PLUG_AUTO "This option makes visualization plug-ins auto-execute when you start a file."
+ IDS_P_PLUG_DIS "This option disables Winamp's built-in visualization when a visualization plug-in is running."
+ IDS_P_VIS_START "This button starts the currently selected visualization plug-in."
+ IDS_P_VIS_STOP "This button stops the currently selected visualization plug-in."
+ IDS_P_VIS_CONF "This button configures the currently selected visualization plug-in."
+ IDS_P_PLUG_PRIO "This slider adjusts the priority of any running visualization plug-ins."
+ IDS_P_DSP_LIB "Selects a DSP library to use."
+ IDS_P_DSP_MOD "Selects a module in the current DSP library."
+ IDS_P_DSP_CONF "Configures the currently selected DSP library."
+ IDS_P_GEN_LIB "Displays a list of general purpose plug-ins. Note that all are already running, you just use this box to configure them."
+ IDS_P_GEN_CONF "Configures the currently selected general purpose Winamp plug-in."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_DISP_CURSORS "This option makes Winamp use Winamp cursors for the mouse. Some people don't seem to like it, so there's this option for it."
+ IDS_P_O_ONLOAD "Reads track info such as title or ID3 tag, as well as a track length estimate, on load (rather than on play)."
+ IDS_P_O_ONDEM "Reads track info such as title or ID3 tag, as well as a track length estimate, on view (when you see it in the playlist editor)"
+ IDS_P_O_RFL "Sorts the files you add/open before adding them."
+ IDS_P_SETUP_MINST "Allow Multiple Instances loads a new copy of Winamp whenever you run it (same as using the /NEW switch on the command line). When turned off, if Winamp is already running when executed, it will be activated."
+ IDS_P_O_CONVERT1 "Converts %20 in song filenames/titles to spaces."
+ IDS_P_O_CONVERT2 "Converts underscores (the ""_"" character) in song filenames/titles to spaces."
+ IDS_P_DISP_STITLE "Scrolls the title in the Windows taskbar if selected."
+ IDS_P_DISP_PLFONT "This box controls the size of the playlist font (in pixels). The default is 10."
+ IDS_P_O_LITESTEP "This box, when enabled, allows Winamp to stay offscreen, which is good for use with LiteStep's virtual window manager."
+ IDS_P_O_AOVD "This box makes Winamp always appear on virtual desktops in LiteStep."
+ IDS_P_FT_EXTENSIONS "Extensions selected here will be registered by Winamp in Windows Explorer."
+ IDS_P_FT_ALL "Selects all extensions."
+ IDS_P_FT_NO "Selects no extensions."
+ IDS_P_FT_ENQUEUE "Makes double-clicking on a file in explorer enqueue it into Winamp's playlist instead of instant playback"
+ IDS_P_FT_ICON "Selects the icon that Winamp audio files use in Explorer."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_OUT_ABOUT "This option views the about box for the selected output plug-in."
+ IDS_P_OUT_OUTPUTS "This box lists all of the installed output plug-ins. Select the one you wish to use."
+ IDS_P_SETUP_PRIO "Adjusts the priority class of Winamp. Usually this is set to Normal, but sometimes it's nice to set it higher (or lower)."
+ IDS_P_DISP_SYSTRAY "Changes the icon that Winamp puts in the notification area."
+ IDS_P_DISP_TASKBAR "This check toggles whether Winamp is shown on the Windows Taskbar, like normal programs."
+ IDS_P_DISP_SYSTRAYICON "This check toggles whether Winamp has an icon in the notification area (near the clock)."
+ IDS_P_DISP_FREESIZE "Allows Winamp Classic skinned resizable windows to be freely sized, instead of kept at 25x29 blocks"
+ IDS_P_CLASSICUI "Classic Skin Options"
+ IDS_P_DISP_HILITE "If enabled this option lets Winamp dim its titlebar when inactive (normally enabled)"
+ IDS_P_DISP_SNAP "If enabled this option makes Winamp snap when you move it. You can temporarily toggle this option by holding down Shift while moving Winamp."
+ IDS_P_DISP_CB "If disabled this option makes Winamp hide the normally-shown ClutterBar (for some skins)."
+ IDS_P_DISP_TTIPS "If enabled this option makes Winamp show helpful (but often annoying) tooltips."
+ IDS_P_O_SPLASH "If enabled this option makes Winamp display a nice splash screen for 2 seconds on launch."
+ IDS_P_DISP_TNUMS "This option makes Winamp display the track #s before the songs in the Playlist Editor. Enabled by default."
+ IDS_P_O_SPLB "This option enables old-school single-click playlist buttons, which some people like better."
+ IDS_P_O_EQDS "This option makes the Graphical Equalizer go into doublesize mode when the main Winamp window is (otherwise, the EQ always stays single-sized)."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_BASICINFO "Basic Info"
+ IDS_DLINK_ERROR "Error updating links!"
+ IDS_ARTWORK "Artwork"
+ IDS_ADVANCED "Advanced"
+ IDS_WINAMP_UPDATE_MSG "New Winamp Available"
+ IDS_NOOUTPUT "Cannot find the selected output plug-in or a native output plug-in to fallback to for playback.\n\nGoto Preferences -> Plug-ins -> Output and select an appropriate output plug-in or re-install Winamp to restore its native plug-ins."
+ IDS_PLAYLISTSTRING "Playlist Files (*.M3U;*.PLS;*.ASX;*.WAX;*.WMX;*.WVX;*.WPL;*.B4S;*.BPL)"
+ IDS_ALLTYPES "All supported types"
+ IDS_RETRPL "Retrieving playlist..."
+ IDS_CONF_HELPSTR "Try hovering the mouse over the\nitem you want help on (a tooltip\nwill appear)!"
+ IDS_P_IN_INPUTS "This is a list of installed input plug-ins for Winamp. You can configure each one by selecting it and hitting Configure."
+ IDS_P_IN_CONF "This option configures the selected input plug-in."
+ IDS_P_IN_ABOUT "This option views the about box for the selected input plug-in."
+ IDS_P_O_DEFEXT "If no input plug-ins can claim the current file extension as their own, this extension is used by default. (we recommend: mp3)."
+ IDS_P_SETUP_PROXY "This specifies the proxy server to use for HTTP transfers.\rIf blank, no proxy is used. Otherwise, specify machine:port, i.e. proxy.noip.com:81, or user:password@machine:port, i.e. justin:rules@myproxy.com:80"
+ IDS_P_OUT_CONF "This button configures the currently selected output plug-in. Changes to the output plug-in usually take effect after restarting playback."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_ERROR "Error"
+ IDS_ERRORINIT "Error initializing"
+ IDS_EQCAPTION "Winamp Equalizer"
+ IDS_PECAPTION "Winamp Playlist Editor"
+ IDS_OPENDIR "Open Folder"
+ IDS_OPENDIRMORE "Select a folder to play:"
+ IDS_PLUGINERROR "Plug-in executed illegal operation.\nRestart of Winamp is recommended"
+ IDS_ERRORLOADINGPLUGIN "Error loading module"
+ IDS_DYNAMICLINKS "Dynamic Links"
+ IDS_PREFS_BOOK "Bookmarks"
+ IDS_DLINK_NOCONTENT "Error finding content (try hitting update)"
+ IDS_DLINK_GETTING "Retrieving Winamp dynamic links"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_EQUALIZER "Equalizer"
+ IDS_P_4FRONT_EQ "Winamp 4Front EQ"
+ IDS_P_CONSTANT_Q "Constant-Q EQ"
+ IDS_P_WA_FREQ_BANDS "Winamp frequency bands"
+ IDS_P_ISO_FREQ_BANDS "ISO Standard frequency bands"
+ IDS_P_REPLAY_GAIN "Replay Gain"
+ IDS_TRACK_GAIN_AND_ALBUM_GAIN "Track Gain: %s\nAlbum Gain: %s"
+ IDS_EQ_HZ "Hz"
+ IDS_EQ_DB "dB"
+ IDS_EQ_KHZ "KHz"
+ IDS_JPEG_FILE "JPEG File"
+ IDS_PNG_FILE "PNG File"
+ IDS_GIF_FILE "GIF File"
+ IDS_BMP_FILE "BMP File"
+ IDS_P_EQ_TYPE_CHANGE "Equalizer Type Change"
+ IDS_P_EQ_TYPE_CHANGE_MSG
+ "You will need to restart Winamp for the change of the Equalizer\ntype to be applied for use. Choose Yes to restart Winamp now."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_CUR_WLZ_INFO "Current language pack information:"
+ IDS_SEL_WLZ_INFO "Selected language pack information:"
+ IDS_WA_RESTART_FOR_WLZ_NEEDED
+ "Restart of Winamp is required for the language pack\n(%s) change to be applied"
+ IDS_DOWNLOADING "Downloading"
+ IDS_COVER "cover"
+ IDS_KBPS "kbps"
+ IDS_METADATA_ERROR "Cannot save metadata: Error writing to file or file is read-only."
+ IDS_METADATA_ERROR_TITLE "Error saving metadata"
+ IDS_CLICKHERE "Click here"
+ IDS_WINAMP_MEDIA_FILE "Winamp media file"
+ IDS_WINAMP_PLAYLIST_FILE "Winamp playlist file"
+ IDS_WINAMP_EXTENSION_INSTALLATION_FILE
+ "Winamp extension installation file"
+ IDS_WINAMP_LANGUAGE_INSTALLATION_FILE "Winamp language installation file"
+ IDS_WINAMP_FILE_INSTALL "Install"
+ IDS_WIN7TOOLBAR_TOOLTIP_PREVIOUS "Previous"
+ IDS_WIN7TOOLBAR_TOOLTIP_PLAY "Play"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_WIN7TOOLBAR_TOOLTIP_PAUSE "Pause"
+ IDS_WIN7TOOLBAR_TOOLTIP_STOP "Stop"
+ IDS_WIN7TOOLBAR_TOOLTIP_NEXT "Next"
+ IDS_SECURITY_APPLICATION_LAUNCHURL
+ "This service is trying to launch a URL in the browser."
+ IDS_SECURITY_TRANSPORT_EVENTS
+ "This service is trying to monitor playback events."
+ IDS_SECURITY_TRANSPORT_METADATA
+ "This service is trying to get information about the currently playing song."
+ IDS_SECURITY_TRANSPORT_CONTROLS
+ "This service is trying to control playback."
+ IDS_SECURITY_PLAYER_PLAYLIST
+ "This service is trying to access your active playlist."
+ IDS_SECURITY_PLAYER_METADATA
+ "This service is trying to get information about an item in your active playlist."
+ IDS_SECURITY_DOWNLOADER_EVENTS
+ "This service is trying to monitor media downloading events."
+ IDS_SECURITY_DOWNLOADER_DOWNLOADMEDIA
+ "This service is trying to download media to your computer."
+ IDS_SECURITY_SECURITY_AUTH "This service is trying to steal yer secretz."
+ IDS_SECURITY_BOOKMARKS_AUTH
+ "This service is trying to access your bookmarks."
+ IDS_SECURITY_SKIN_AUTH "This service is trying to access your skin settings."
+ IDS_SECURITY_MEDIACORE_METADATAHOOK
+ "This service is trying to provide metadata to Winamp."
+ IDS_SECURITY_MEDIACORE_METADATA
+ "This service is trying to access information about media on your computer."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_SECURITY_MEDIACORE_EXTENSIONS
+ "This service is trying to access information about media supported by Winamp."
+ IDS_LANG_DIR_MOVE_MESSAGE
+ "Since you are changing the language pack directory, would you like to\nmove the contents of the langauge pack directory to the new location?\n\nChoosing 'Yes' will move all of the directory contents from:\n\n%s\nto\n%s"
+ IDS_SKIN_DIR_MOVE_MESSAGE
+ "Since you are changing the skins directory, would you like to\nmove the contents of the skins directory to the new location?\n\nChoosing 'Yes' will move all of the directory contents from:\n\n%s\nto\n%s"
+ IDS_DIR_MOVE_ERROR "You have specified a drive root as the new location which is not allowed. The location change will now be aborted.\n\nPlease select a different location which is not a drive root."
+ IDS_LANG_DIR_MOVE "Language Pack Directory Change"
+ IDS_SKIN_DIR_MOVE "Skins Directory Change"
+ IDS_NOML_SAVE_RATING "Do you want to save the rating to file?\nNote: You will not be prompted again."
+ IDS_NOML_SAVE_RATING_TITLE "Media Library Not Detected"
+ IDS_RELEASED "Released: %s"
+ IDS_EQ_TOOLTIPS "EQ on/off|EQ auto|Open presets"
+ IDS_VID_TOOLTIPS "Fullscreen|Normal Size|Double Size|Internet TV|Options"
+ IDS_PL_TOOLTIPS "Add Files to Playlist|Remove Files from Playlist|Select Files in Playlist|Misc Actions|Manage Playlist|Scroll Up|Scroll Down|Adjust Horizontal Size"
+ IDS_P_FT_EXTENSIONS_WIN8
+ "Extensions listed here are able to be registered to Winamp via the 'Set Default Programs' Control Panel in Windows."
+ IDS_ARTWORK_DETAILS "%s: %dx%d, origin: %s, type: %s"
+ IDS_ORIGIN_NONE "none"
+ IDS_ORIGIN_EMBEDDED "embedded"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_ORIGIN_ALBUM_MATCH "album name match"
+ IDS_ORIGIN_NFO "nfo file"
+ IDS_ORIGIN_COVER_MATCH "cover.* match"
+ IDS_ORIGIN_FOLDER_MATCH "folder.* match"
+ IDS_ORIGIN_FRONT_MATCH "front.* match"
+ IDS_ORIGIN_ARTWORK_MATCH "artwork.* match"
+ IDS_SKINS_INSTALL_ERROR "There was an error whilst installing the skin. Error code: %s\r\n\r\nFrom: %s\r\nTo: %s"
+ IDS_LANG_INSTALL_ERROR "There was an error whilst installing the language pack. Error code: %s\r\n\r\nFrom: %s\r\nTo: %s"
+ IDS_PREFS_SAFE_MODE "Winamp Preferences [SAFE MODE]"
+ IDS_START_SAFE_MODE "Winamp Starting In Safe Mode"
+ IDS_FAILED_SAFE_MODE "Winamp Unable To Start In Safe Mode"
+ IDS_FAILED_SAFE_MODE_MSG
+ "Winamp is already running and 'safe mode' cannot be properly started. Ensure all instances of Winamp have been closed before trying again."
+ IDS_SAFE_MODE_ALL "Winamp will now be run in 'safe mode' which prevents the loading of\n3rd party plug-ins including all detected Visualisation, DSP and\nMedia Library plug-ins as well as Language Packs."
+ IDS_SAFE_MODE_NORMAL "Winamp will now be run in 'safe mode' which prevents the loading of\n3rd party plug-ins including all detected Visualisation and DSP plug-ins\nas well as Language Packs."
+ IDS_RESTART_NORMAL "Restart In\nFull Mode"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_PLUG_SAFEMODE "Restart Winamp in Full or Safe Mode based on the current mode Winamp was started."
+ IDS_RESTART_SAFE "Are you sure you want to restart Winamp in the selected mode?"
+ IDS_RESTART "Restart Winamp?"
+ IDS_NO_MODERN_SKIN_SUPPORT
+ "You are attempting to use a Modern skin (""%s"") but have not installed the Modern skin support plug-in required to load these skins.\n\nYou will need to re-run the Winamp installer and ensure you select Modern skin support to be able to use this skin."
+ IDS_SKIN_LOAD_ERROR "Winamp Skin Loading Error"
+ IDS_AUDIO_CD "Audio CD %c: [%s]"
+ IDS_EMPTY "Empty"
+ IDS_BYTES "bytes"
+ IDS_KIB "KiB"
+ IDS_MIB "MiB"
+ IDS_GIB "GiB"
+ IDS_TIB "TiB"
+ IDS_KB "KB"
+ IDS_MB "MB"
+ IDS_GB "GB"
+ IDS_TB "TB"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_SHUFFLE_ON "Shuffle: On"
+ IDS_SHUFFLE_OFF "Shuffle: Off"
+ IDS_REPEAT_OFF "Repeat: Off"
+ IDS_REPEAT_PL "Repeat: Playlist"
+ IDS_REPEAT_TRACK "Repeat: Track"
+ IDS_MAN_ADV_ON "Manual Advance: On"
+ IDS_MAN_ADV_OFF "Manual Advance: Off"
+ IDS_DEF_PROG_LOAD_ERROR "Unable to open the 'Set Default Programs' window. You will need to manually go to the Control Panel and enter 'Set Default Programs' into the search bar to easily find it."
+ IDS_RESET_URLS "Are you sure you want to reset the saved URL history?\nNote: This cannot be undone after choosing 'Yes'."
+ IDS_RESET_URLS_TITLE "Reset URL History"
+ IDS_P_DISP_BIFONT_ALT "This option makes Winamp use an alternative style for the un-skinned font for displaying track titles which may make it easier to see the track titles when 'Double size' is enabled."
+ IDS_P_FILE_ASSOC "Winamp File Association"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_FILE_ASSOC_FAILURE
+ "Unable to apply the requested file association changes.\n\nIf you selected 'No' or cancelled the UAC prompt (if one was shown), re-select the 'File Types' preference page and make any changes needed again ensuring you select 'Yes' or enter the correct Administrator details required to allow this action to be completed."
+ IDS_P_NO_MOUSEWHEEL "Enabling this option will prevent the mouse wheel from changing the current volume which can still be done via the keyboard or directly clicking and then moving the volume slider."
+ IDS_P_PLUG_SAFEMODEALWAYS
+ "Enable this to always run Winamp in Safe Mode without the 'nag' screen and the risk from issues that can arise by using 3rd party plug-ins."
+ IDS_NOT_LOADED "NOT LOADED"
+ IDS_NO_RATING "No rating"
+ IDS_X_ITEM_SELECTED "%i item selected."
+ IDS_X_ITEMS_SELECTED "%i items selected."
+ IDS_UPDATING_FILES "Updating files..."
+ IDS_UPDATING_X "Updating %s..."
+ IDS_ERROR_UPDATING_FILE "Error updating file: %s\n"
+ IDS_INFO_UPDATING_ERROR "Info updating error"
+ IDS_P_O_VIDEO_AUTO_FS_ON_START
+ "This option will make the video window automatically switch to fullscreen when playback is started."
+ IDS_P_O_VIDEO_ENABLE "This option allows you to enable or disable Winamp's video support. This requires a restart for the change to be applied."
+END
+
+STRINGTABLE
+BEGIN
+ IDS_P_VIDEO_CHANGE "Enable / Disable Video Support"
+ IDS_P_VIDEO_CHANGE_MSG "You will need to restart Winamp for this change to be applied.\n\nChoose Yes to restart Winamp now."
+ IDS_P_O_VIDEO_HIDE_PREFS
+ "This option allows you to permanently hide this preference page when video support is disabled. To restore access to this preference page set no_video=1 in your winamp.ini file."
+ IDS_STREAMINFO "Stream Info"
+ IDS_P_SK_PROMPT "When this option is checked, you will receive a prompt when installing new skins. If unchecked, always ensure you are installing skins from a safe source."
+ IDS_PREFS_ARTWORK "Artwork"
+ IDS_UNKNOWN_MIME "unknown"
+ IDS_RC_CHANNEL_TITLE "Join RC Channel"
+ IDS_RC_CHANNEL_MESSAGE "Are you interested in participating in our next round of release candidate (RC) upgrades?"
+END
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Winamp/WinampAttributes.cpp b/Src/Winamp/WinampAttributes.cpp
new file mode 100644
index 00000000..2ce27277
--- /dev/null
+++ b/Src/Winamp/WinampAttributes.cpp
@@ -0,0 +1,66 @@
+#include "main.h"
+#include "api.h"
+#include "WinampAttributes.h"
+#include "InternetConfigGroup.h"
+#include "VideoConfigGroup.h"
+#include "PlaybackConfigGroup.h"
+#include "EQConfigGroup.h"
+#include "DeveloperConfigGroup.h"
+#include "AccessibilityConfigGroup.h"
+#include "../config/config.h"
+extern Config config;
+
+/* --- Video --- */
+VideoConfigGroup videoConfigGroup;
+_bool config_video_overlays(true);
+_bool config_video_yv12(true);
+_bool config_video_vsync2(true);
+_bool config_video_ddraw(true);
+_bool config_video_gdiplus(false);
+_mutable_bool config_video_autoopen(true);
+_mutable_bool config_video_autoclose(true);
+_mutable_bool config_video_auto_fs(false);
+
+/* --- Internet --- */
+InternetConfigGroup internetConfigGroup;
+_bool config_proxy80(false);
+
+/* --- Playback --- */
+PlaybackConfigGroup playbackConfigGroup;
+_unsigned config_audio_bits(16);
+_bool config_audio_mono(false);
+_bool config_audio_surround(true);
+_bool config_audio_dither(true);
+_bool config_replaygain(false);
+_unsigned config_replaygain_mode(RG_MODE_GAIN_NOCLIP);
+_unsigned config_replaygain_source(RG_SOURCE_TRACK);
+_bool config_replaygain_preferred_only(false);
+_float config_replaygain_non_rg_gain(-6);
+_float config_replaygain_preamp(0);
+_int config_playback_thread_priority(THREAD_PRIORITY_HIGHEST);
+
+/* --- EQ --- */
+EQConfigGroup eqConfigGroup;
+_int config_eq_frequencies(EQ_FREQUENCIES_WINAMP);
+_int config_eq_type(EQ_TYPE_4FRONT);
+_bool config_eq_limiter(true);
+
+/* --- Developer --- */
+DeveloperConfigGroup developerConfigGroup;
+
+
+/* --- Accessibility --- */
+AccessibilityConfigGroup accessibilityConfigGroup;
+_bool config_accessibility_modalbeep(false);
+_bool config_accessibility_modalflash(true);
+
+void RegisterConfigGroups()
+{
+ config.RegisterGroup(&internetConfigGroup);
+ config.RegisterGroup(&videoConfigGroup);
+ config.RegisterGroup(&playbackConfigGroup);
+ config.RegisterGroup(&eqConfigGroup);
+ config.RegisterGroup(&developerConfigGroup);
+ config.RegisterGroup(&accessibilityConfigGroup);
+}
+
diff --git a/Src/Winamp/WinampAttributes.h b/Src/Winamp/WinampAttributes.h
new file mode 100644
index 00000000..5e31cb2d
--- /dev/null
+++ b/Src/Winamp/WinampAttributes.h
@@ -0,0 +1,49 @@
+#ifndef NULLSOFT_WINAMP_WINAMPATTRIBUTES_H
+#define NULLSOFT_WINAMP_WINAMPATTRIBUTES_H
+
+#include "attributes.h"
+
+// internet
+extern _bool config_proxy80;
+
+// video
+extern _bool config_video_overlays;
+extern _bool config_video_yv12;
+extern _bool config_video_vsync2;
+extern _bool config_video_ddraw;
+extern _bool config_video_gdiplus;
+extern _mutable_bool config_video_autoopen;
+extern _mutable_bool config_video_autoclose;
+extern _mutable_bool config_video_auto_fs;
+
+// audio
+extern _unsigned config_audio_bits;
+extern _bool config_audio_mono;
+extern _bool config_audio_surround;
+extern _bool config_audio_dither;
+
+// playback
+extern _int config_playback_thread_priority;
+
+// EQ
+enum { EQ_FREQUENCIES_WINAMP = 0, EQ_FREQUENCIES_ISO = 1, };
+extern _int config_eq_frequencies;
+enum { EQ_TYPE_4FRONT = 0, EQ_TYPE_CONSTANT_Q = 1, };
+extern _int config_eq_type;
+extern _bool config_eq_limiter;
+
+// replay gain
+extern _bool config_replaygain;
+enum { RG_MODE_GAIN=0, RG_MODE_GAIN_NOCLIP=1, RG_MODE_NORMALIZE=2, RG_MODE_NOCLIP=3};
+extern _unsigned config_replaygain_mode;
+enum { RG_SOURCE_TRACK=0, RG_SOURCE_ALBUM=1};
+extern _unsigned config_replaygain_source;
+extern _bool config_replaygain_preferred_only;
+extern _float config_replaygain_non_rg_gain;
+extern _float config_replaygain_preamp;
+
+// accessibility
+extern _bool config_accessibility_modalbeep;
+extern _bool config_accessibility_modalflash;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/WinampPlaylist.cpp b/Src/Winamp/WinampPlaylist.cpp
new file mode 100644
index 00000000..fa93c618
--- /dev/null
+++ b/Src/Winamp/WinampPlaylist.cpp
@@ -0,0 +1,228 @@
+#include "main.h"
+#include "WinampPlaylist.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+#include "api.h"
+
+WinampDirectoryLoad::WinampDirectoryLoad( bool _forceRecurse, char *_exts ) : forceRecurse( _forceRecurse ), exts( _exts ), needsFree( false ), listStart( 0 )
+{
+ listStart = PlayList_getlength();
+ if ( !exts )
+ {
+ exts = in_getextlist();
+ needsFree = false;
+ }
+}
+
+WinampDirectoryLoad::~WinampDirectoryLoad()
+{
+ if ( config_rofiob & 1 )
+ PlayList_sort( 2, listStart );
+
+ if ( needsFree )
+ GlobalFree( (HGLOBAL)exts );
+}
+
+WinampPlaylist::WinampPlaylist( const wchar_t *_base, bool _loadDirectories ) : base( _base ), terminateOnEnd( false ), loadDirectories( _loadDirectories )
+{}
+
+bool WhitelistOK( wchar_t *url )
+{
+ bool validurl = false;
+ wchar_t *p = url;
+ // Whitelist the url...
+ if ( *p == L'a' ) p++; // get passed the ad-fullscreen blob.
+ if ( *p )
+ {
+ wchar_t *whitelist;
+ whitelist = wcsstr( p, L"http://www.winamp.com/" );
+ if ( whitelist && whitelist == p )
+ {
+ validurl = true;
+ }
+
+ if ( validurl == false ) // Check for javscript command
+ {
+ whitelist = wcsstr( p, L"javascript:onCommand(" );
+ if ( whitelist && whitelist == p )
+ {
+ wchar_t *semi = wcsstr( whitelist, L";" );
+ if ( semi )
+ {
+ semi++;
+ if ( *semi )
+ *semi = 0;
+ }
+
+ validurl = true;
+ }
+
+ }
+ }
+
+ return validurl;
+}
+
+WinampPlaylist::~WinampPlaylist()
+{
+ //if ( terminateOnEnd )
+ //{
+ //}
+}
+
+void WinampPlaylist::OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMs, ifc_plentryinfo *info)
+{
+ BOOL hidden = false;
+ int playcount = 0;
+ unsigned long starttime = 0, endtime = 0;
+ wchar_t fcurtain[FILENAME_SIZE] = L"";
+ wchar_t fileExt[ 10 ] = L"";
+ //wchar_t fbrowser[FILENAME_SIZE] = L"";
+
+ if (LoadPlaylist(filename, 1, 0) == 0) //(playlistManager->Load(filename, this) == PLAYLISTMANAGER_SUCCESS) // if it's another playlist file, load recursively
+ return ;
+
+ // check for trailing backslash
+ /*
+ if (filename[lstrlenW(filename)] == '\\')
+ {
+ WinampDirectoryLoad dir(true);
+ playlistManager->LoadDirectory(filename, this, &dir);
+ return;
+ }
+ */
+
+ // see if it's a directory
+ if ( loadDirectories && !PathIsURLW( filename ) && !PathIsNetworkPathW( filename ) )
+ {
+ HANDLE h;
+ WIN32_FIND_DATAW d;
+
+ h = FindFirstFileW( filename, &d );
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ FindClose( h );
+ if ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+ WinampDirectoryLoad dir( true );
+ playlistManager->LoadDirectory( filename, this, &dir );
+ return;
+ }
+ }
+ }
+
+ if (info)
+ {
+ const wchar_t *ext = 0;
+ ext = info->GetExtendedInfo(L"Repeat");
+ if (ext) playcount = _wtoi(ext);
+
+ ext = info->GetExtendedInfo(L"Start");
+ if (ext) starttime = _wtoi(ext);
+
+ ext = info->GetExtendedInfo(L"End");
+ if (ext) endtime = _wtoi(ext);
+
+ ext = info->GetExtendedInfo(L"Hidden");
+ if (ext)
+ hidden = _wtoi(ext);
+ else
+ {
+ ext = info->GetExtendedInfo(L"Context");
+ if (ext)
+ {
+ if (!lstrcmpiW(ext, L"radio"))
+ {
+ hidden = true;
+ terminateOnEnd = true;
+ }
+ }
+ }
+
+ ext = info->GetExtendedInfo(L"Curtain");
+ if (ext)
+ {
+ StringCchCopyW(fcurtain, FILENAME_SIZE, ext);
+ if (!WhitelistOK(fcurtain))
+ fcurtain[0] = 0;
+ }
+
+ ext = info->GetExtendedInfo( L"ext" );
+ if ( ext )
+ {
+ StringCchCopyW( fileExt, 10, ext );
+ }
+ /*
+ ext = info->GetExtendedInfo(L"Browser");
+ if (ext)
+ {
+ StringCchCopyW(fbrowser, FILENAME_SIZE, ext);
+ if (!WhitelistOK(fbrowser))
+ fbrowser[0] = 0;
+ }
+ */
+ }
+
+ if ( lengthInMs != -1 )
+ lengthInMs /= 1000;
+
+ if ( !hidden )
+ {
+ PlayList_append_withinfo_curtain( filename, title, lengthInMs, fcurtain[ 0 ] ? AutoChar( fcurtain ) : 0, fileExt, 0 );
+ }
+ else
+ {
+ PlayList_append_withinfo_hidden( filename, title, lengthInMs, fcurtain[ 0 ] ? AutoChar( fcurtain ) : 0/*, fbrowser[0] ? AutoChar(fbrowser) : 0*/ );
+ }
+
+ PlayList_SetLastItem_RepeatCount(playcount);
+ PlayList_SetLastItem_Range(starttime, endtime);
+}
+
+const wchar_t *WinampPlaylist::GetBasePath()
+{
+ return base;
+}
+
+bool WinampDirectoryLoad::ShouldRecurse(const wchar_t *path)
+{
+ if (config_rofiob&1)
+ PlayList_sort(2, listStart);
+
+ listStart = PlayList_getlength();
+
+ if (forceRecurse)
+ return true;
+ else
+ return (config_rofiob&2) ? false : true;
+}
+
+bool WinampDirectoryLoad::ShouldLoad(const wchar_t *filename)
+{
+ if (!exts)
+ return true;
+ const wchar_t *ext = extensionW(filename);
+ char *a = exts;
+ while (a && *a)
+ {
+ if (!_wcsicmp(AutoWide(a), ext))
+ return true;
+ a += lstrlenA(a) + 1;
+ }
+ return false;
+
+}
+
+#define CBCLASS WinampPlaylist
+START_DISPATCH;
+VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
+CB(IFC_PLAYLISTLOADERCALLBACK_GETBASEPATH, GetBasePath)
+END_DISPATCH;
+
+#undef CBCLASS
+#define CBCLASS WinampDirectoryLoad
+START_DISPATCH;
+CB(IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDRECURSE, ShouldRecurse)
+CB(IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDLOAD, ShouldLoad)
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Winamp/WinampPlaylist.h b/Src/Winamp/WinampPlaylist.h
new file mode 100644
index 00000000..aedb6720
--- /dev/null
+++ b/Src/Winamp/WinampPlaylist.h
@@ -0,0 +1,43 @@
+#ifndef NULLSOFT_WINAMP_WINAMP_PLAYLIST_H
+#define NULLSOFT_WINAMP_WINAMP_PLAYLIST_H
+
+// this class is for the main playlist editor
+#include "../playlist/ifc_playlistloadercallback.h"
+#include "../playlist/ifc_playlistdirectorycallback.h"
+
+class WinampPlaylist : public ifc_playlistloadercallback
+{
+public:
+ WinampPlaylist( const wchar_t *_base = 0, bool _loadDirectories = false );
+ ~WinampPlaylist();
+
+ void OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info );
+ const wchar_t *GetBasePath();
+
+protected:
+ RECVS_DISPATCH;
+
+ const wchar_t *base;
+ bool terminateOnEnd;
+ bool loadDirectories;
+};
+
+class WinampDirectoryLoad : public ifc_playlistdirectorycallback
+{
+public:
+ WinampDirectoryLoad( bool _forceRecurse, char *exts = 0 );
+ ~WinampDirectoryLoad();
+
+ bool ShouldRecurse( const wchar_t *path );
+ bool ShouldLoad( const wchar_t *filename );
+
+ bool forceRecurse;
+ char *exts;
+ bool needsFree;
+ int listStart;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/XMLString.cpp b/Src/Winamp/XMLString.cpp
new file mode 100644
index 00000000..232605b6
--- /dev/null
+++ b/Src/Winamp/XMLString.cpp
@@ -0,0 +1,51 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "XMLString.h"
+
+XMLString::XMLString()
+{
+ data[0]=0;
+}
+
+void XMLString::Reset()
+{
+ data[0]=0;
+}
+
+const wchar_t *XMLString::GetString()
+{
+ return data;
+}
+
+void XMLString::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ data[0]=0;
+}
+
+
+void XMLString::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str)
+{
+ StringCchCatW(data, XMLSTRING_SIZE, str);
+}
+
+
+void XMLString::ManualSet(const wchar_t *string)
+{
+StringCchCatW(data, XMLSTRING_SIZE, string);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS XMLString
+START_DISPATCH;
+VCB(ONSTARTELEMENT, StartTag)
+VCB(ONCHARDATA, TextHandler)
+END_DISPATCH;
diff --git a/Src/Winamp/XMLString.h b/Src/Winamp/XMLString.h
new file mode 100644
index 00000000..df33ca34
--- /dev/null
+++ b/Src/Winamp/XMLString.h
@@ -0,0 +1,29 @@
+#ifndef NULLSOFT_WINAMP_XMLSTRING_H
+#define NULLSOFT_WINAMP_XMLSTRING_H
+
+
+#include "../xml/ifc_xmlreadercallback.h"
+/*
+this one is an xml callback that just saves the last encountered string
+*/
+
+#define XMLSTRING_SIZE MAX_URL
+class XMLString : public ifc_xmlreadercallback
+{
+public:
+ XMLString();
+ void Reset();
+ const wchar_t *GetString();
+ void ManualSet(const wchar_t *string);
+private:
+ /* XML callbacks */
+ void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+ void EndTag(const wchar_t *xmlpath, const wchar_t *xmltag);
+ void TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
+
+ wchar_t data[XMLSTRING_SIZE]; // for now, we'll make it dynamic later
+
+ RECVS_DISPATCH;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/api.h b/Src/Winamp/api.h
new file mode 100644
index 00000000..5b5c3453
--- /dev/null
+++ b/Src/Winamp/api.h
@@ -0,0 +1,72 @@
+#ifndef __WASABI_API_H
+#define __WASABI_API_H
+
+#include "wasabicfg.h"
+#include "ServiceManager.h"
+#include "SysCallbacks.h"
+#include "MemoryManager.h"
+#include "URLManager.h"
+#include "PaletteManager.h"
+#include "GammaManagerAPI.h"
+
+#define WASABI_API_SVC serviceManager
+#define WASABI_API_SYSCB sysCallbacks
+#define WASABI_API_VIDEOPREFERENCES videoPreferences
+#define WASABI_API_MEMMGR memoryManager
+extern PaletteManager *paletteManager;
+#define WASABI_API_PALETTE paletteManager
+extern GammaManagerAPI *gammaManager;
+#define WASABI_API_COLORTHEMES gammaManager
+
+#include "../tagz/api_tagz.h"
+extern api_tagz *tagz;
+#define WINAMP5_API_TAGZ tagz
+
+#include "feeds.h"
+extern VideoTextFeed *videoTextFeed;
+extern PlaylistTextFeed *playlistTextFeed;
+
+#include "application.h"
+#define WASABI_API_APP application
+
+#include "Metadata.h"
+#define WASABI_API_METADATA metadata
+
+#include "../nu/threadpool/ThreadPool.h"
+extern ThreadPool *threadPool;
+#define WASABI_API_THREADPOOL threadPool
+
+#include "stats.h"
+#define AGAVE_API_STATS (&stats)
+
+/* Services we need from W5S services */
+#include "../playlist/api_playlistmanager.h"
+extern api_playlistmanager *playlistManager;
+#define AGAVE_API_PLAYLISTMANAGER playlistManager
+
+#include "../playlist/api_playlists.h"
+extern api_playlists *playlistsManager;
+#define AGAVE_API_PLAYLISTS playlistsManager
+
+#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
+
+extern URLManager *urlmanagerApi;
+#define AGAVE_API_URLMANAGER urlmanagerApi
+
+#include "./winampApi.h"
+extern WinampApi *winampApi;
+#define WASABI_API_WINAMP winampApi
+
+#include "../jpeg/amg.h"
+extern api_amgsucks *amgSucks;
+#define AGAVE_API_AMGSUCKS amgSucks
+
+#include "../Agave/AlbumArt/api_albumart.h"
+extern api_albumart *albumArtApi;
+#define AGAVE_API_ALBUMART albumArtApi
+
+/* Services we need to watch for */
+#include <api/skin/api_skin.h>
+#define WASABI_API_SKIN skinApi
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/api_audiostream.h b/Src/Winamp/api_audiostream.h
new file mode 100644
index 00000000..f965e506
--- /dev/null
+++ b/Src/Winamp/api_audiostream.h
@@ -0,0 +1,7 @@
+#include "../Agave/DecodeFile/ifc_audiostream.h"
+#ifndef NULLSOFT_TYPEDEF_API_AUDIOSTREAM_H
+#define NULLSOFT_TYPEDEF_API_AUDIOSTREAM_H
+
+typedef ifc_audiostream api_audiostream;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/api_decodefile.h b/Src/Winamp/api_decodefile.h
new file mode 100644
index 00000000..553d3231
--- /dev/null
+++ b/Src/Winamp/api_decodefile.h
@@ -0,0 +1,2 @@
+#include "../Agave/DecodeFile/api_decodefile.h"
+#include "api_audiostream.h" \ No newline at end of file
diff --git a/Src/Winamp/api_inflate.h b/Src/Winamp/api_inflate.h
new file mode 100644
index 00000000..8012f877
--- /dev/null
+++ b/Src/Winamp/api_inflate.h
@@ -0,0 +1,96 @@
+#ifndef NULLSOFT_WINAMP_API_INFLATE_H
+#define NULLSOFT_WINAMP_API_INFLATE_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/types.h>
+
+/* TODO: this should be renamed api_zlib */
+class NOVTABLE api_inflate : public Dispatchable
+{
+protected:
+ api_inflate() {}
+ ~api_inflate() {}
+public:
+ int inflateReset(void *strm);
+ int inflateInit_(void *strm,const char *version, int stream_size);
+ int inflateInit2_(void *strm, int windowBits, const char *version, int stream_size);
+ int inflate(void *strm, int flush);
+ int inflateEnd(void *strm);
+ unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len);
+
+ int deflateReset(void *strm);
+ int deflateInit2_(void *strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size);
+ int deflate(void *strm, int flush);
+ int deflateEnd(void *strm);
+public:
+ DISPATCH_CODES
+ {
+ API_INFLATE_INFLATERESET = 10,
+ API_INFLATE_INFLATEINIT = 20,
+ API_INFLATE_INFLATEINIT2 = 21,
+ API_INFLATE_INFLATE = 30,
+ API_INFLATE_INFLATEEND = 40,
+ API_INFLATE_CRC32 = 50,
+
+ API_INFLATE_DEFLATERESET = 60,
+ API_INFLATE_DEFLATEINIT2 = 70,
+ API_INFLATE_DEFLATE = 80,
+ API_INFLATE_DEFLATEEND = 90,
+ };
+};
+
+inline int api_inflate::inflateReset(void *strm)
+{
+ return _call(API_INFLATE_INFLATERESET, (int)-4, strm);
+}
+
+inline int api_inflate::inflateInit_(void *strm, const char *version, int stream_size)
+{
+ return _call(API_INFLATE_INFLATEINIT, (int)-4, strm, version, stream_size);
+}
+
+inline int api_inflate::inflateInit2_(void *strm, int windowBits, const char *version, int stream_size)
+{
+ return _call(API_INFLATE_INFLATEINIT2, (int)-4, strm, windowBits, version, stream_size);
+}
+
+inline int api_inflate::inflate(void *strm, int flush)
+{
+ return _call(API_INFLATE_INFLATE, (int)-4, strm, flush);
+}
+
+inline int api_inflate::inflateEnd(void *strm)
+{
+ return _call(API_INFLATE_INFLATEEND, (int)-2, strm);
+}
+
+inline unsigned long api_inflate::crc32(unsigned long crc, const unsigned char *buf, unsigned int len)
+{
+ return _call(API_INFLATE_CRC32, (unsigned long)0, crc, buf, len);
+}
+
+inline int api_inflate::deflateReset(void *strm)
+{
+ return _call(API_INFLATE_DEFLATERESET, (unsigned long)-4, strm);
+}
+
+inline int api_inflate::deflateInit2_(void *strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)
+{
+ return _call(API_INFLATE_DEFLATEINIT2, (int)-4, strm, level, method, windowBits, memLevel, strategy, version, stream_size);
+}
+
+inline int api_inflate::deflateEnd(void *strm)
+{
+ return _call(API_INFLATE_DEFLATEEND, (int)-2, strm);
+}
+
+inline int api_inflate::deflate(void *strm, int flush)
+{
+ return _call(API_INFLATE_DEFLATE, (int)-4, strm, flush);
+}
+
+ // {8A4C0BAA-83D0-440e-BB59-A5C70A92EFFF}
+static const GUID inflateGUID =
+{ 0x8a4c0baa, 0x83d0, 0x440e, { 0xbb, 0x59, 0xa5, 0xc7, 0xa, 0x92, 0xef, 0xff } };
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/api_random.h b/Src/Winamp/api_random.h
new file mode 100644
index 00000000..a3aa8b36
--- /dev/null
+++ b/Src/Winamp/api_random.h
@@ -0,0 +1 @@
+#include "../Agave/Random/api_random.h"
diff --git a/Src/Winamp/api_stats.h b/Src/Winamp/api_stats.h
new file mode 100644
index 00000000..02e2a71c
--- /dev/null
+++ b/Src/Winamp/api_stats.h
@@ -0,0 +1,74 @@
+#ifndef NULLSOFT_API_STATS_H
+#define NULLSOFT_API_STATS_H
+
+#include <bfc/dispatch.h>
+/* super secret user spying code goes here */
+
+class api_stats : public Dispatchable
+{
+ public:
+ enum
+ {
+ LAUNCHES, // st1
+ TIME_RUNNING, // st2
+ TIME_VISIBLE,// st3
+ TIME_PLAYING,// st4
+ TIME_MB,// st5
+ TIME_VISIBLE_PLAYING, // st6
+ TIME_MB_PLAYING, // st7
+ FILES_PLAYED, // st8
+ CDS_PLAYED, // st9
+ STREAMS_PLAYED, // st10
+ VIDEOS_PLAYED, // st11
+ LIBRARY_SIZE, // st12
+ REGVER, // st13
+ PLEDIT_LENGTH, // st14
+ PLAYLIST_COUNT, // st15
+ PODCAST_COUNT, // st16
+ PMP_TRANSFER_COUNT, // st17
+ REPLAYGAIN_COUNT, // st18
+ TRANSCODE_COUNT, // st19
+ TRANSCODE_FORMAT, // st20
+ RIP_COUNT, // st21
+ RIP_FORMAT, // st22
+ AVI_AUDIO_FORMAT, // st23
+ AVI_VIDEO_FOURCC, // st24
+ BOOKMARK_COUNT, // st25
+ PLG_COUNT, // st26
+ NUM_STATS,
+ };
+protected:
+ api_stats() {}
+ ~api_stats() {}
+public:
+ void SetStat(int stat, int value);
+ void IncrementStat(int stat);
+ void SetString(const char *key, const wchar_t *value);
+ enum
+ {
+ SETSTAT = 0,
+ INCREMENTSTAT = 1,
+ SETSTRING = 2,
+ };
+};
+
+inline void api_stats::SetStat(int stat, int value)
+{
+ _voidcall(SETSTAT, stat, value);
+}
+
+inline void api_stats::IncrementStat(int stat)
+{
+ _voidcall(INCREMENTSTAT, stat);
+}
+
+inline void api_stats::SetString(const char *key, const wchar_t *value)
+{
+ _voidcall(SETSTRING, key, value);
+}
+
+// {E23D9470-A095-4f02-97A1-88A8859DE0C2}
+static const GUID AnonymousStatsGUID =
+{ 0xe23d9470, 0xa095, 0x4f02, { 0x97, 0xa1, 0x88, 0xa8, 0x85, 0x9d, 0xe0, 0xc2 } };
+
+#endif // !NULLSOFT_API_STATS_H \ No newline at end of file
diff --git a/Src/Winamp/api_urlmanager.h b/Src/Winamp/api_urlmanager.h
new file mode 100644
index 00000000..4d964f6e
--- /dev/null
+++ b/Src/Winamp/api_urlmanager.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/guid.h>
+
+class api_urlmanager : public Dispatchable
+{
+protected:
+ api_urlmanager(){}
+ ~api_urlmanager(){}
+public:
+ const wchar_t *GetURL(const wchar_t *urlid);
+
+ enum
+ {
+ API_URLMANAGER_GETURL=0,
+ };
+};
+
+inline const wchar_t *api_urlmanager::GetURL(const wchar_t *urlid)
+{
+ return _call(API_URLMANAGER_GETURL, (const wchar_t *)0, urlid);
+}
+
+// {B5E9E32E-4C4A-49d6-804F-8858B396F27E}
+static const GUID urlManagerGUID =
+{ 0xb5e9e32e, 0x4c4a, 0x49d6, { 0x80, 0x4f, 0x88, 0x58, 0xb3, 0x96, 0xf2, 0x7e } };
diff --git a/Src/Winamp/api_videopreferences.cpp b/Src/Winamp/api_videopreferences.cpp
new file mode 100644
index 00000000..1ab836c9
--- /dev/null
+++ b/Src/Winamp/api_videopreferences.cpp
@@ -0,0 +1,2 @@
+#include "main.h"
+#include "api_videopreferences.h" \ No newline at end of file
diff --git a/Src/Winamp/api_videopreferences.h b/Src/Winamp/api_videopreferences.h
new file mode 100644
index 00000000..f14764d9
--- /dev/null
+++ b/Src/Winamp/api_videopreferences.h
@@ -0,0 +1,28 @@
+#ifndef __WASABI_API_VIDEOPREFERENCES_H
+#define __WASABI_API_VIDEOPREFERENCES_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/types.h>
+class NOVTABLE api_videopreferences : public Dispatchable
+{
+public:
+ DISPATCH_CODES
+ {
+ API_VIDEOPREFERENCES_IS_OUTPUT_YV12=10,
+ };
+
+ int IsOutputYV12();
+};
+
+inline int api_videopreferences::IsOutputYV12()
+{
+ return _call(API_VIDEOPREFERENCES_IS_OUTPUT_YV12, (int)0);
+}
+
+
+// {9DE9DBEE-1466-4da4-939D-2EFDDEA14DA7}
+static const GUID videoPreferencesGUID =
+{ 0x9de9dbee, 0x1466, 0x4da4, { 0x93, 0x9d, 0x2e, 0xfd, 0xde, 0xa1, 0x4d, 0xa7 } };
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/api_winamp.h b/Src/Winamp/api_winamp.h
new file mode 100644
index 00000000..637f4fab
--- /dev/null
+++ b/Src/Winamp/api_winamp.h
@@ -0,0 +1,57 @@
+#ifndef NULLSOFT_WINAMP_API_WINAMP_HEADER
+#define NULLSOFT_WINAMP_API_WINAMP_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {5968E566-805E-442f-B6A0-916F9CD4E8A8}
+static const GUID winampApiGuid =
+{ 0x5968e566, 0x805e, 0x442f, { 0xb6, 0xa0, 0x91, 0x6f, 0x9c, 0xd4, 0xe8, 0xa8 } };
+
+
+class __declspec(novtable) api_winamp : public Dispatchable
+{
+protected:
+ api_winamp() {}
+ ~api_winamp() {}
+
+public:
+ HWND GetMainWindow(void);
+ HWND GetDlgParent(void);
+ HRESULT OpenUrl(HWND hwnd, const wchar_t *url);
+ int GetRegVer();
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETMAINWINDOW = 10,
+ API_GETDLGPARENT = 20,
+ API_OPENURL = 30,
+ API_GETREGVER = 40,
+ };
+};
+
+inline HWND api_winamp::GetMainWindow(void)
+{
+ return _call(API_GETMAINWINDOW, (HWND)NULL);
+}
+
+inline HWND api_winamp::GetDlgParent(void)
+{
+ return _call(API_GETDLGPARENT, (HWND)NULL);
+}
+
+inline HRESULT api_winamp::OpenUrl(HWND hwnd, const wchar_t *url)
+{
+ return _call(API_OPENURL, (HRESULT)E_NOTIMPL, hwnd, url);
+}
+
+inline int api_winamp::GetRegVer()
+{
+ return _call(API_GETREGVER, (int)0);
+}
+
+#endif // NULLSOFT_WINAMP_API_WINAMP_HEADER \ No newline at end of file
diff --git a/Src/Winamp/application.cpp b/Src/Winamp/application.cpp
new file mode 100644
index 00000000..b7b6ca34
--- /dev/null
+++ b/Src/Winamp/application.cpp
@@ -0,0 +1,941 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename: application.cpp
+ ** Project: Winamp 5
+ ** Description: Winamp's implementation of Wasabi's Application API.
+ ** Also includes the main message loop.
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "application.h"
+#include "../nu/AutoWide.h"
+#include "api.h"
+#include "../nu/ns_wc.h"
+
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+
+static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL;
+static ATOM DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL = 0;
+
+static BOOL DirectMouseWheel_RegisterMessage()
+{
+ WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL");
+ if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
+ return FALSE;
+
+ if (NULL != application)
+ application->DirectMouseWheel_InitBlackList();
+
+ return TRUE;
+}
+
+BOOL
+IsDirectMouseWheelMessage(const UINT uMsg)
+{
+ if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
+ {
+ if (FALSE == DirectMouseWheel_RegisterMessage())
+ return FALSE;
+ }
+
+ return (WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg);
+}
+
+BOOL
+DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable)
+{
+ if (FALSE != enable)
+ {
+ if (0 == DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)
+ {
+ DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL = GlobalAddAtomW(L"DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL");
+ if (0 == DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)
+ return FALSE;
+ }
+
+ if (0 == SetPropW(hwnd, (const wchar_t*)MAKEINTATOM(DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL), (HANDLE)1))
+ return FALSE;
+ }
+ else
+ {
+ if (0 != DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)
+ RemovePropW(hwnd, (const wchar_t*)MAKEINTATOM(DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL));
+ }
+
+ return TRUE;
+}
+
+BOOL
+DirectMouseWheel_IsConvertToMouseWheelEnabled(HWND hwnd)
+{
+ return(0 != DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL &&
+ NULL != GetPropW(hwnd, (const wchar_t*)MAKEINTATOM(DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)));
+}
+
+Application::Application()
+ : shuttingdown(0), activeDialog(NULL), machineID(GUID_NULL), userID(GUID_NULL), sessionID(GUID_NULL),
+ threadStorageIndex(TLS_OUT_OF_INDEXES), messageHook(NULL), disableMessageHook(false)
+{
+ tlsIndex = TlsAlloc();
+}
+
+Application::~Application()
+{
+ if (NULL != messageHook)
+ {
+ UnhookWindowsHookEx(messageHook);
+ messageHook = NULL;
+ }
+}
+
+const wchar_t *Application::main_getAppName()
+{
+ return WIDEN(APP_NAME);
+}
+
+const wchar_t *Application::main_getVersionString()
+{
+ return WIDEN(APP_NAME) L" " WIDEN(APP_VERSION_STRING);
+}
+
+const wchar_t *Application::main_getVersionNumString()
+{
+ return WIDEN(APP_VERSION);
+}
+
+unsigned int Application::main_getBuildNumber()
+{
+ return BUILD_NUMBER;
+}
+
+// a guid for our app : {4BE592C7-6937-426a-A388-ACF0EBC88E93}
+static const GUID WinampGUID =
+ {
+ 0x4be592c7, 0x6937, 0x426a, { 0xa3, 0x88, 0xac, 0xf0, 0xeb, 0xc8, 0x8e, 0x93 }
+ };
+
+GUID Application::main_getGUID()
+{
+ return WinampGUID;
+}
+
+HANDLE Application::main_getMainThreadHandle()
+{
+ if (hMainThread == 0)
+ return (HANDLE)0;
+ HANDLE h = (HANDLE)0;
+ DuplicateHandle(GetCurrentProcess(), hMainThread, GetCurrentProcess(), &h, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ return h;
+}
+
+HINSTANCE Application::main_gethInstance()
+{
+ return hMainInstance;
+}
+
+const wchar_t *Application::main_getCommandLine()
+{
+ return GetCommandLineW();
+}
+
+void Application::main_shutdown(int deferred)
+{
+
+ int x = static_cast<int>(SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_IS_EXIT_ENABLED));
+
+ if (!x)
+ return;
+
+ shuttingdown = 1;
+
+ SendMessageW(hMainWindow, WM_CLOSE, 0, 0);
+}
+
+void Application::main_cancelShutdown()
+{
+ shuttingdown = 0;
+}
+
+int Application::main_isShuttingDown()
+{
+ return shuttingdown;
+}
+
+const wchar_t *Application::path_getAppPath()
+{
+ return PROGDIR;
+}
+
+const wchar_t *Application::path_getUserSettingsPath()
+{
+ return CONFIGDIR;
+}
+
+const wchar_t *Application::path_getSkinSettingsPath()
+{
+ return SKINDIR;
+}
+
+int Application::app_getInitCount()
+{
+ return 1;
+}
+
+void Application::app_addMessageProcessor(api_messageprocessor *processor)
+{
+ messageProcessors.push_back(processor);
+}
+
+void Application::app_removeMessageProcessor(api_messageprocessor *processor)
+{
+ //messageProcessors.eraseAll(processor);
+ auto it = messageProcessors.begin();
+ while (it != messageProcessors.end())
+ {
+ if (*it != processor)
+ {
+ it++;
+ continue;
+ }
+
+ it = messageProcessors.erase(it);
+ }
+}
+
+void Application::app_addModelessDialog(HWND hwnd)
+{
+ OutputDebugStringA( "[Error] 'app_addModelessDialog' removed! Use 'ActiveDialog_Register' instead!\r\n" );
+}
+
+void Application::app_removeModelessDialog(HWND hwnd)
+{
+ OutputDebugStringA( "[Error] 'app_removeModelessDialog' removed!Use 'ActiveDialog_Unregister' instead!\r\n" );
+}
+
+void Application::app_addAccelerators(HWND hwnd, HACCEL *phAccel, INT cAccel, UINT translateMode)
+{
+ AccelMap::iterator accelIterator;
+ ACCELNODE *pList;
+
+ if (accelerators.size() > 0)
+ {
+ accelIterator = accelerators.end();
+ do
+ {
+ accelIterator--;
+ if (!IsWindow(accelIterator->first))
+ {
+ //app_removeAccelerators(accelIterator->first);
+ ACCELNODE* pList, * pNode;
+ pList = accelIterator->second;
+ while (pList)
+ {
+ pNode = pList;
+ pList = (pList->pNext) ? pList->pNext : NULL;
+ free(pNode);
+ }
+ accelIterator = accelerators.erase(accelIterator);
+ }
+ } while (accelIterator != accelerators.begin() && accelIterator != accelerators.end());
+ }
+
+ if (!IsWindow(hwnd) || !phAccel || cAccel <= 0) return;
+
+ accelIterator = accelerators.find(hwnd);
+ if(accelIterator != accelerators.end())
+ pList = accelIterator->second;
+ else
+ {
+ pList = (ACCELNODE*)calloc(1, sizeof(ACCELNODE));
+ if(pList)
+ {
+ accelerators.insert({hwnd, pList});
+ }
+ }
+ if (!pList) return;
+ while (pList->pNext) pList = pList->pNext;
+
+ while(cAccel--)
+ {
+ if (*phAccel)
+ {
+ ACCELNODE *pNode;
+ if (pList->hAccel)
+ {
+ pNode = (ACCELNODE*)calloc(1, sizeof(ACCELNODE));
+ pNode->pNext = NULL;
+ pList->pNext = pNode;
+ pList = pNode;
+ }
+ else pNode = pList;
+
+ pNode->hAccel = *phAccel;
+ pNode->translateMode = translateMode;
+
+ }
+ phAccel++;
+ }
+}
+
+void Application::app_removeAccelerators(HWND hwnd)
+{
+ AccelMap::iterator iter = accelerators.find(hwnd);
+ if(iter == accelerators.end())
+ return;
+
+ ACCELNODE *pList, *pNode;
+ pList = iter->second;
+ while(pList)
+ {
+ pNode = pList;
+ pList = (pList->pNext) ? pList->pNext : NULL;
+ free(pNode);
+ }
+ accelerators.erase(hwnd);
+}
+
+int Application::app_getAccelerators(HWND hwnd, HACCEL *phAccel, INT cchAccelMax, BOOL bGlobal)
+{
+
+ if (!hwnd || 0 == accelerators.size()) return 0;
+ if ((!phAccel && cchAccelMax) || (phAccel && !cchAccelMax)) return 0;
+
+ AccelMap::iterator accelIterator = accelerators.end();
+ INT count = 0;
+
+ do
+ {
+ accelIterator--;
+ for (ACCELNODE *pNode = accelIterator->second; NULL != pNode; pNode = pNode->pNext)
+ {
+ if (accelIterator->first == hwnd ||
+ (bGlobal && (TRANSLATE_MODE_GLOBAL == pNode->translateMode ||
+ (TRANSLATE_MODE_CHILD == pNode->translateMode && IsChild(accelIterator->first, hwnd)))))
+ {
+ if (phAccel && cchAccelMax)
+ {
+ *phAccel = pNode->hAccel;
+ phAccel++;
+ cchAccelMax--;
+ }
+ count++;
+ }
+ }
+ }
+ while (accelIterator != accelerators.begin() && (!phAccel || cchAccelMax));
+
+ return count;
+}
+
+void Application::app_registerGlobalWindow(HWND hwnd)
+{
+ for (std::vector<HWND>::const_iterator e = globalWindows.begin(); e != globalWindows.end(); e++)
+ {
+ if (*e == hwnd) return;
+ }
+ globalWindows.push_back(hwnd);
+}
+
+void Application::app_unregisterGlobalWindow(HWND hwnd)
+{
+ for (std::vector<HWND>::iterator e = globalWindows.begin(); e != globalWindows.end(); e++)
+ {
+ if (*e == hwnd)
+ {
+ globalWindows.erase(e);
+ return;
+ }
+ }
+
+}
+
+bool Application::FilterMessage(MSG *msg) // returns 1 if you should Dispatch the message, will handle TranslateMessage for you
+{
+ if (msg->hwnd != NULL && msg->hwnd != hMainWindow && msg->hwnd != hEQWindow // && msg.hwnd != hMBWindow
+ && msg->hwnd != hPLWindow && msg->hwnd != hVideoWindow)
+ {
+ HWND hWndParent = NULL;
+ HWND temphwnd = msg->hwnd;
+ if (GetClassLong(temphwnd, GCW_ATOM) == (INT)32770)
+ hWndParent = temphwnd;
+
+ /*while (*/temphwnd = GetParent(temphwnd)/*)*/ ;
+ {
+ if (GetClassLong(temphwnd, GCW_ATOM) == (INT)32770)
+ hWndParent = temphwnd;
+ }
+
+ if (NULL != hWndParent)
+ {
+ BOOL processed;
+
+ disableMessageHook = true;
+ processed = IsDialogMessageW(hWndParent, msg);
+ disableMessageHook = false;
+
+ if (FALSE != processed)
+ return true;
+ }
+
+ //if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN ||
+ // msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
+ //{
+ //if (IsChild(hMBWindow,msg.hwnd) && TranslateAccelerator(hMBWindow,hAccel[3],&msg)) continue;
+ TranslateMessage(msg);
+ //}
+ }
+ return false;
+}
+bool Application::isGlobalWindow(HWND hwnd)
+{
+ for (std::vector<HWND>::const_iterator e = globalWindows.begin(); e != globalWindows.end(); e++)
+ {
+ if (*e == hwnd || IsChild(*e, hwnd)) return true;
+ }
+ return false;
+}
+
+bool Application::app_translateAccelerators(MSG *msg)
+{
+ if (accelerators.size() > 0)
+ {
+ AccelMap::iterator accelIterator = accelerators.end();
+ do
+ {
+ accelIterator--;
+ for (ACCELNODE *pNode = accelIterator->second; NULL != pNode; pNode = pNode->pNext)
+ {
+ if (((TRANSLATE_MODE_GLOBAL == pNode->translateMode && isGlobalWindow(msg->hwnd)) ||
+ accelIterator->first == msg->hwnd ||
+ (TRANSLATE_MODE_CHILD == pNode->translateMode && IsChild(accelIterator->first, msg->hwnd))) &&
+ TranslateAcceleratorW(accelIterator->first, pNode->hAccel, msg))
+ {
+ return true;
+ }
+ }
+ }
+ while (accelIterator != accelerators.begin());
+ }
+ return false;
+}
+
+bool
+Application::DirectMouseWheel_RegisterSkipClass(ATOM klass)
+{
+ size_t index;
+
+ if (klass < 0xC000)
+ return false;
+
+ index = directMouseWheelBlackList.size();
+ while(index--)
+ {
+ if (directMouseWheelBlackList[index] == klass)
+ return false;
+ }
+
+ directMouseWheelBlackList.push_back(klass);
+
+ return true;
+}
+
+bool
+Application::DirectMouseWheel_UnregisterSkipClass(ATOM klass)
+{
+ size_t index;
+
+ if (klass < 0xC000)
+ return false;
+
+ index = directMouseWheelBlackList.size();
+ while(index--)
+ {
+ if (directMouseWheelBlackList[index] == klass)
+ {
+ directMouseWheelBlackList.erase(directMouseWheelBlackList.begin() + index);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Application::DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable)
+{
+ return (0 != ::DirectMouseWheel_EnableConvertToMouseWheel(hwnd, enable));
+}
+
+void
+Application::DirectMouseWheel_InitBlackList()
+{
+ size_t index;
+ WNDCLASSW klassInfo;
+ ATOM klassAtom;
+
+ const static LPCWSTR defaultBlackListNames[] =
+ {
+ L"msctls_trackbar32",
+ L"msctls_updown32",
+ L"SysHeader32",
+ };
+
+ const static ATOM defaultBlackListAtoms[] =
+ {
+ 0xC017, // button
+ 0xC018, // edit
+ 0xC019, // static
+ 0xC01C, // combobox
+ };
+
+ for (index = 0; index < ARRAYSIZE(defaultBlackListAtoms); index++)
+ {
+ directMouseWheelBlackList.push_back(defaultBlackListAtoms[index]);
+ }
+
+ for (index = 0; index < ARRAYSIZE(defaultBlackListNames); index++)
+ {
+ klassAtom = (ATOM)GetClassInfoW(NULL, defaultBlackListNames[index], &klassInfo);
+ if (0 != klassAtom)
+ directMouseWheelBlackList.push_back(klassAtom);
+ }
+}
+
+bool
+Application::DirectMouseWheel_ProccessMessage(MSG *msg)
+{
+ HWND targetWindow;
+ ATOM targetAtom;
+ DWORD targetProcessId;
+ POINT mousePoint;
+ size_t index, listSize;
+
+ if (msg->message != WM_MOUSEWHEEL)
+ return false;
+
+ if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
+ {
+ if (FALSE == DirectMouseWheel_RegisterMessage())
+ return false;
+ }
+
+ POINTSTOPOINT(mousePoint, msg->lParam);
+ targetWindow = WindowFromPoint(mousePoint);
+
+ if (NULL == targetWindow || targetWindow == msg->hwnd)
+ return false;
+
+ GetWindowThreadProcessId(targetWindow, &targetProcessId);
+ if (targetProcessId != GetCurrentProcessId())
+ return false;
+
+ if (FALSE == IsWindowEnabled(targetWindow))
+ return false;
+
+ listSize = directMouseWheelBlackList.size();
+ index = 0;
+
+ while(index != listSize)
+ {
+ targetAtom = (ATOM)GetClassLongPtrW(targetWindow, GCW_ATOM);
+ for(index = 0; index < listSize; index++)
+ {
+ if (targetAtom == directMouseWheelBlackList[index])
+ {
+ targetWindow = GetAncestor(targetWindow, GA_PARENT);
+ if (NULL == targetWindow || targetWindow == msg->hwnd)
+ return false;
+ break;
+ }
+ }
+ }
+
+ if (FALSE != DirectMouseWheel_IsConvertToMouseWheelEnabled(targetWindow))
+ {
+ SendMessageW(targetWindow, WM_MOUSEWHEEL, msg->wParam, msg->lParam);
+ return true;
+ }
+ else if (0 != SendMessageW(targetWindow, WINAMP_WM_DIRECT_MOUSE_WHEEL, msg->wParam, msg->lParam))
+ return true;
+
+ return false;
+}
+
+HWND ActiveChildWindowFromPoint( HWND hwnd, POINTS cursor_s, const int *controls, size_t controlsCount )
+{
+ POINT pt;
+ RECT controlRect;
+ HWND controlWindow;
+
+ POINTSTOPOINT( pt, cursor_s );
+
+ while ( controlsCount-- )
+ {
+ controlWindow = GetDlgItem( hwnd, controls[ controlsCount ] );
+
+ if ( controlWindow != NULL && GetClientRect( controlWindow, &controlRect ) != FALSE )
+ {
+ MapWindowPoints( controlWindow, HWND_DESKTOP, (POINT *) &controlRect, 2 );
+
+ if ( PtInRect( &controlRect, pt ) != FALSE )
+ {
+ unsigned long windowStyle = (unsigned long) GetWindowLongPtrW( controlWindow, GWL_STYLE );
+
+ if ( ( ( WS_VISIBLE | WS_DISABLED ) & windowStyle ) == WS_VISIBLE )
+ return controlWindow;
+
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+BOOL DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen)
+{
+ if (FALSE != ::IsDirectMouseWheelMessage(uMsg))
+ {
+ HWND targetWindow = ::ActiveChildWindowFromPoint(hwnd, MAKEPOINTS(lParam), controls, controlslen);
+ if (NULL != targetWindow)
+ {
+ SendMessageW(targetWindow, WM_MOUSEWHEEL, wParam, lParam);
+ SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (long)TRUE);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOL Application::DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen)
+{
+ return ::DirectMouseWheel_ProcessDialogMessage(hwnd, uMsg, wParam, lParam, controls, controlslen);
+}
+
+void Application::ActiveDialog_Register(HWND hwnd)
+{
+ activeDialog = hwnd;
+}
+
+void Application::ActiveDialog_Unregister(HWND hwnd)
+{
+ if (hwnd == activeDialog)
+ activeDialog = NULL;
+}
+
+HWND Application::ActiveDialog_Get()
+{
+ return activeDialog;
+}
+
+/* Plugins can register a 'Message Processor' to tap into the main message loop
+ for some purposes (Dialog message handling, ActiveX/ATL/COM, wxWidgets)
+ this is the only way to make sure all messages are processed correctly
+ @see api_application::app_addMessageProcessor() and api_messageprocessor.h
+ */
+
+bool Application::ProcessMessageLight( MSG *msg )
+{
+ /* messageProcessors is the list of registered Message Processors */
+ for ( api_messageprocessor *processor : messageProcessors )
+ {
+ disableMessageHook = true;
+
+ if ( processor->ProcessMessage( msg ) ) // it'll return true if it wants to eat the message
+ {
+ disableMessageHook = false;
+
+ return true;
+ }
+ }
+
+ disableMessageHook = false;
+
+ if ( false != DirectMouseWheel_ProccessMessage( msg ) )
+ return true;
+
+ return false;
+}
+
+bool Application::ProcessMessage( MSG *msg )
+{
+ if ( ProcessMessageLight( msg ) != false )
+ return true;
+
+ if ( ( msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN ) && app_translateAccelerators( msg ) )
+ return true;
+
+
+ if ( activeDialog != NULL )
+ {
+ disableMessageHook = true;
+
+ if ( IsDialogMessageW( activeDialog, msg ) != FALSE )
+ {
+ disableMessageHook = false;
+
+ return true;
+ }
+ }
+
+ disableMessageHook = false;
+
+ return false;
+}
+
+intptr_t Application::app_messageLoopStep()
+{
+ MSG msg;
+
+ if (PeekMessageW(&msg, NULL, 0, 0, TRUE))
+ {
+ if (msg.message == WM_QUIT)
+ {
+ PostQuitMessage((int)msg.wParam);
+ return msg.wParam ; // abandoned due to WM_QUIT
+ }
+
+ if (!ProcessMessage(&msg) && !FilterMessage(&msg))
+ DispatchMessageW(&msg);
+
+ if (WM_NCDESTROY == msg.message)
+ DirectMouseWheel_EnableConvertToMouseWheel(msg.hwnd, FALSE);
+
+ return msg.wParam;
+ }
+
+ return 0;
+}
+
+LRESULT CALLBACK Application::MessageHookProc( INT code, WPARAM wParam, LPARAM lParam )
+{
+ if ( application == NULL || application->messageHook == NULL )
+ {
+ return FALSE;
+ }
+
+ if ( application->disableMessageHook == false )
+ {
+ switch ( code )
+ {
+ case MSGF_DIALOGBOX:
+ case MSGF_MESSAGEBOX:
+ if ( false != application->ProcessMessageLight( (MSG *) lParam ) )
+ return 1;
+ break;
+ }
+ }
+ else
+ application->disableMessageHook = false;
+
+ return CallNextHookEx( application->messageHook, code, wParam, lParam );
+}
+
+WPARAM Application::MessageLoop()
+{
+ if ( messageHook == NULL )
+ messageHook = SetWindowsHookEx( WH_MSGFILTER, MessageHookProc, NULL, GetCurrentThreadId() );
+
+ for ( ;;)
+ {
+ DWORD dwStatus = MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE );
+
+ if ( dwStatus == WAIT_OBJECT_0 )
+ {
+ MSG msg;
+ while ( PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE ) )
+ {
+ if ( msg.message == WM_QUIT )
+ return msg.wParam;
+
+ if ( !ProcessMessage( &msg ) && !FilterMessage( &msg ) )
+ DispatchMessageW( &msg );
+ }
+ }
+ }
+}
+
+WPARAM WinampMessageLoop()
+{
+ return WASABI_API_APP->MessageLoop();
+}
+
+const wchar_t *Application::path_getWorkingPath()
+{
+ return config_cwd;
+}
+
+void Application::path_setWorkingPath(const wchar_t *newPath)
+{
+ StringCchCopyW(config_cwd, MAX_PATH, newPath);
+}
+
+/*
+int Application::GetMachineID(GUID *id)
+{
+ // TODO: stuff this in the registry
+ if (machineID == GUID_NULL)
+ {
+ if (!GetPrivateProfileStruct(app_name, "mid", (LPVOID)&machineID, sizeof(machineID), INI_FILE) || machineID == GUID_NULL)
+ {
+ UuidCreate(&machineID);
+ WritePrivateProfileStruct(app_name, "mid", (LPVOID)&machineID, sizeof(machineID), INI_FILE);
+ }
+ }
+
+ *id = machineID;
+ return API_APPLICATION_SUCCESS;
+}
+*/
+int Application::GetUserID(GUID *id)
+{
+ if (userID == GUID_NULL)
+ {
+ config_uid_ft = (char)GetPrivateProfileIntW(L"Winamp", L"uid_ft", 0, INI_FILE);
+
+ wchar_t uid_str[512] = {0};
+ if (!GetPrivateProfileStructA(app_name, "uid", (LPVOID)&userID, sizeof(userID), INI_FILEA) || userID == GUID_NULL)
+ {
+ // attempt to restore the client uid after an uninstall, lost config file, etc
+ readwrite_client_uid(0, uid_str);
+ if (uid_str[0])
+ {
+ WritePrivateProfileStringW(AutoWide(app_name), L"uid", uid_str, INI_FILE);
+ }
+
+ if (!GetPrivateProfileStructA(app_name, "uid", (LPVOID)&userID, sizeof(userID), INI_FILEA) || userID == GUID_NULL)
+ {
+ UuidCreate(&userID);
+ WritePrivateProfileStructA(app_name, "uid", (LPVOID)&userID, sizeof(userID), INI_FILEA);
+ GetPrivateProfileStringW(AutoWide(app_name), L"uid", L"", uid_str, ARRAYSIZE(uid_str), INI_FILE);
+ readwrite_client_uid(1, uid_str);
+ // if done then no need to re-do it at a later point
+ config_uid_ft = 1;
+ }
+ }
+
+ // and just to make sure, if this is like a new run then we'll need to force into the registry
+ if (!config_uid_ft)
+ {
+ config_uid_ft = 1;
+ GetPrivateProfileStringW(AutoWide(app_name), L"uid", L"", uid_str, ARRAYSIZE(uid_str), INI_FILE);
+ readwrite_client_uid(1, uid_str);
+ }
+ }
+
+ *id = userID;
+
+ return API_APPLICATION_SUCCESS;
+}
+
+int Application::GetSessionID(GUID *id)
+{
+ if (sessionID == GUID_NULL)
+ UuidCreate(&sessionID);
+
+ *id = sessionID;
+ return API_APPLICATION_SUCCESS;
+}
+
+size_t Application::AllocateThreadStorage()
+{
+ return (size_t)InterlockedIncrement(&threadStorageIndex);
+}
+
+void *Application::GetThreadStorage(size_t index)
+{
+ std::vector<void*> *ptrlist = (std::vector<void*> *)TlsGetValue(tlsIndex);
+ if (!ptrlist)
+ return 0;
+
+ if ((index+1) > ptrlist->size())
+ return 0;
+
+ return ptrlist->at(index);
+}
+
+void Application::SetThreadStorage(size_t index, void *value)
+{
+ std::vector<void*> *ptrlist = (std::vector<void*> *)TlsGetValue(tlsIndex);
+ if (!ptrlist)
+ {
+ ptrlist = new std::vector<void*>;
+ TlsSetValue(tlsIndex, ptrlist);
+ }
+ size_t ptrlist_size = ptrlist->size();
+ if ((index+1) > ptrlist_size)
+ {
+ ptrlist->reserve(index+1);
+ for (size_t i=ptrlist_size;i<=index;i++)
+ {
+ ptrlist->push_back(0);
+ }
+ }
+ ptrlist->at(index) = value;
+}
+
+const wchar_t *Application::getATFString()
+{
+ return config_titlefmt;
+}
+
+int Application::getScaleX(int x)
+{
+ return ScaleX(x);
+}
+
+int Application::getScaleY(int y)
+{
+ return ScaleY(y);
+}
+
+#define CBCLASS Application
+START_DISPATCH;
+CB(API_APPLICATION_MAIN_GETAPPNAME, main_getAppName)
+CB(API_APPLICATION_MAIN_GETVERSIONSTRING, main_getVersionString)
+CB(API_APPLICATION_MAIN_GETVERSIONSTRING2, main_getVersionNumString)
+CB(API_APPLICATION_MAIN_GETBUILDNUMBER, main_getBuildNumber)
+CB(API_APPLICATION_MAIN_GETGUID, main_getGUID)
+CB(API_APPLICATION_MAIN_GETMAINTHREADHANDLE, main_getMainThreadHandle)
+CB(API_APPLICATION_MAIN_GETHINSTANCE, main_gethInstance)
+CB(API_APPLICATION_MAIN_GETCOMMANDLINE, main_getCommandLine)
+VCB(API_APPLICATION_MAIN_SHUTDOWN, main_shutdown)
+VCB(API_APPLICATION_MAIN_CANCELSHUTDOWN, main_cancelShutdown)
+CB(API_APPLICATION_MAIN_ISSHUTTINGDOWN, main_isShuttingDown)
+CB(API_APPLICATION_PATH_GETAPPPATH, path_getAppPath)
+CB(API_APPLICATION_PATH_GETUSERSETTINGSPATH, path_getUserSettingsPath)
+CB(API_APPLICATION_PATH_GETSKINSETTINGSPATH, path_getSkinSettingsPath)
+CB(API_APPLICATION_APP_GETINITCOUNT, app_getInitCount)
+CB(API_APPLICATION_APP_MESSAGELOOPSTEP, app_messageLoopStep)
+VCB(API_APPLICATION_APP_ADDMESSAGEPROCESSOR, app_addMessageProcessor)
+VCB(API_APPLICATION_APP_REMOVEMESSAGEPROCESSOR, app_removeMessageProcessor)
+VCB(API_APPLICATION_APP_ADDMODELESSDIALOG, app_addModelessDialog)
+VCB(API_APPLICATION_APP_REMOVEMODELESSDIALOG, app_removeModelessDialog)
+VCB(API_APPLICATION_APP_ADDACCELERATORS, app_addAccelerators)
+VCB(API_APPLICATION_APP_REMOVEACCELERATORS, app_removeAccelerators)
+CB(API_APPLICATION_APP_TRANSLATEACCELERATORS, app_translateAccelerators);
+CB(API_APPLICATION_APP_GETACCELERATORS, app_getAccelerators);
+VCB(API_APPLICATION_APP_REGISTERGLOBALWINDOW, app_registerGlobalWindow);
+VCB(API_APPLICATION_APP_UNREGISTERGLOBALWINDOW, app_unregisterGlobalWindow);
+CB(API_APPLICATION_PATH_GETWORKINGPATH, path_getWorkingPath);
+VCB(API_APPLICATION_PATH_SETWORKINGPATH, path_setWorkingPath);
+CB(API_APPLICATION_DIRECTMOUSEWHEEL_REGISTERSKIPCLASS, DirectMouseWheel_RegisterSkipClass);
+CB(API_APPLICATION_DIRECTMOUSEWHEEL_UNREGISTERSKIPCLASS, DirectMouseWheel_UnregisterSkipClass);
+CB(API_APPLICATION_DIRECTMOUSEWHEEL_ENABLECONVERTTOMOUSEWHEEL, DirectMouseWheel_EnableConvertToMouseWheel);
+CB(API_APPLICATION_DIRECTMOUSEWHEEL_PROCESSDIALOGMESSAGE, DirectMouseWheel_ProcessDialogMessage);
+VCB(API_APPLICATION_ACTIVEDIALOG_REGISTER, ActiveDialog_Register);
+VCB(API_APPLICATION_ACTIVEDIALOG_UNREGISTER, ActiveDialog_Unregister);
+CB(API_APPLICATION_ACTIVEDIALOG_GET, ActiveDialog_Get);
+/*
+CB(API_APPLICATION_GETMACHINEID, GetMachineID);
+*/
+CB(API_APPLICATION_GETUSERID, GetUserID);
+CB(API_APPLICATION_GETSESSIONID, GetSessionID);
+CB(API_APPLICATION_ALLOCATETHREADSTORAGE, AllocateThreadStorage);
+CB(API_APPLICATION_GETTHREADSTORAGE, GetThreadStorage);
+VCB(API_APPLICATION_SETTHREADSTORAGE, SetThreadStorage);
+CB(API_APPLICATION_GETATFSTRING, getATFString);
+CB(API_APPLICATION_GETSCALEX, getScaleX);
+CB(API_APPLICATION_GETSCALEY, getScaleY);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/application.h b/Src/Winamp/application.h
new file mode 100644
index 00000000..77c07a69
--- /dev/null
+++ b/Src/Winamp/application.h
@@ -0,0 +1,127 @@
+#ifndef NULLSOFT_WINAMP_APPLICATION_H
+#define NULLSOFT_WINAMP_APPLICATION_H
+
+#include <api/application/api_application.h>
+#include <vector>
+#include <map>
+
+class Application : public api_application
+{
+public:
+ static const char *getServiceName() { return "Application API"; }
+ static const GUID getServiceGuid() { return applicationApiServiceGuid; }
+public:
+ Application();
+ ~Application();
+
+ const wchar_t *main_getAppName();
+ const wchar_t *main_getVersionString();
+ const wchar_t *main_getVersionNumString();
+ unsigned int main_getBuildNumber();
+ GUID main_getGUID();
+ HANDLE main_getMainThreadHandle();
+ HINSTANCE main_gethInstance();
+ const wchar_t *main_getCommandLine();
+ void main_shutdown(int deferred = TRUE);
+ void main_cancelShutdown();
+ int main_isShuttingDown();
+ const wchar_t *path_getAppPath();
+ const wchar_t *path_getUserSettingsPath();
+ // added for 5.58+ so gen_ff can fill @SKINSPATH@ in scripts correctly
+ const wchar_t *path_getSkinSettingsPath();
+ int app_getInitCount();
+ intptr_t app_messageLoopStep();
+ void app_addMessageProcessor(api_messageprocessor *processor);
+ void app_removeMessageProcessor(api_messageprocessor *processor);
+
+ void app_addModelessDialog(HWND hwnd);
+ void app_removeModelessDialog(HWND hwnd);
+ // added for 5.34
+ const wchar_t *path_getWorkingPath();
+ void path_setWorkingPath(const wchar_t *newPath);
+ // added for 5.35
+ /*
+ int GetMachineID(GUID *id);
+ */
+ int GetUserID(GUID *id);
+
+ int GetSessionID(GUID *id);
+
+ WPARAM MessageLoop();
+
+ // added for 5.53
+ bool app_translateAccelerators(MSG *msg);
+ void app_addAccelerators(HWND hwnd, HACCEL *phAccel, INT cAccel, UINT translateMode);
+ void app_removeAccelerators(HWND hwnd);
+ int app_getAccelerators(HWND hwnd, HACCEL *phAccel, INT cchAccelMax, BOOL bGlobal);
+
+ // added for 5.54
+ void app_registerGlobalWindow(HWND hwnd);
+ void app_unregisterGlobalWindow(HWND hwnd);
+ bool isGlobalWindow(HWND hwnd);
+
+ /* 5.54 + */
+ size_t AllocateThreadStorage(); // returns an index, -1 for error
+ void *GetThreadStorage(size_t index);
+ void SetThreadStorage(size_t index, void *value);
+
+ /* 5.58 + */
+ bool DirectMouseWheel_RegisterSkipClass(ATOM klass);
+ bool DirectMouseWheel_UnregisterSkipClass(ATOM klass);
+ bool DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable);
+ /* 5.64 + */
+ BOOL DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen);
+
+ /* 5.61 + */
+ void ActiveDialog_Register(HWND hwnd);
+ void ActiveDialog_Unregister(HWND hwnd);
+ HWND ActiveDialog_Get();
+
+ /* 5.64 + */
+ const wchar_t *getATFString(); // returns the current ATF formatting string
+
+ /* 5.66 + */
+ // used for dpi scaling so we're consistent in usage throughout the UI, etc
+ int getScaleX(int x);
+ int getScaleY(int y);
+private:
+ RECVS_DISPATCH;
+ bool ProcessMessageLight(MSG *msg);
+ bool ProcessMessage(MSG *msg);
+ bool FilterMessage(MSG *msg);
+ bool DirectMouseWheel_ProccessMessage(MSG *msg);
+ void DirectMouseWheel_InitBlackList();
+ friend static BOOL DirectMouseWheel_RegisterMessage();
+ static LRESULT CALLBACK MessageHookProc(INT code, WPARAM wParam, LPARAM lParam);
+
+private:
+ typedef struct __ACCELNODE
+ {
+ HACCEL hAccel;
+ UINT translateMode;
+ __ACCELNODE *pNext;
+ } ACCELNODE;
+
+ typedef std::map<HWND, ACCELNODE*> AccelMap;
+
+private:
+ int shuttingdown;
+ std::vector<api_messageprocessor*> messageProcessors;
+ HWND activeDialog;
+
+ AccelMap accelerators;
+ std::vector<HWND> globalWindows;
+ std::vector<ATOM> directMouseWheelBlackList;
+
+ GUID machineID, userID, sessionID;
+
+ DWORD tlsIndex;
+ LONG threadStorageIndex;
+
+ HHOOK messageHook;
+ bool disableMessageHook;
+};
+
+extern Application *application;
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/asx.cpp b/Src/Winamp/asx.cpp
new file mode 100644
index 00000000..70ef4d17
--- /dev/null
+++ b/Src/Winamp/asx.cpp
@@ -0,0 +1,63 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "asx.h"
+#include "../jnetlib/api_httpget.h"
+#include "../nu/AutoChar.h"
+#include "WinampPlaylist.h"
+#include "../nu/AutoWide.h"
+#include "api.h"
+
+#if 0 // keep around for reference
+void ASXLoader::LoadFile(const char *filename)
+{
+ HANDLE file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
+
+ if (file == INVALID_HANDLE_VALUE)
+ return ;
+
+ char data[1024];
+ DWORD bytesRead;
+
+ // check for ASXv2
+ if (ReadFile(file, data, 11, &bytesRead, NULL) && bytesRead)
+ {
+ if (bytesRead == 11 && !_strnicmp((char *)data, "[Reference]", 11))
+ {
+ loadasxv2fn(filename, 1); // can pass 0 since loadasxfn() already took care of this
+ CloseHandle(file);
+ return ;
+ }
+ }
+ else
+ {
+ CloseHandle(file);
+ return ;
+ }
+ if (!parser)
+ {
+ CloseHandle(file);
+ return ;
+ }
+
+ GayASX_to_XML_converter(parser, data, bytesRead); // read the small amount we read when sniffing for asxv2
+
+ while (true)
+ {
+
+ if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
+ GayASX_to_XML_converter(parser, data, bytesRead);
+ else
+ break;
+ }
+
+ CloseHandle(file);
+ parser->xmlreader_feed(0, 0);
+}
+#endif
+
diff --git a/Src/Winamp/asx.h b/Src/Winamp/asx.h
new file mode 100644
index 00000000..85251690
--- /dev/null
+++ b/Src/Winamp/asx.h
@@ -0,0 +1,4 @@
+#ifndef NULLSOFT_WINAMP_ASX_H
+#define NULLSOFT_WINAMP_ASX_H
+
+#endif
diff --git a/Src/Winamp/attributes.h b/Src/Winamp/attributes.h
new file mode 100644
index 00000000..419f8aab
--- /dev/null
+++ b/Src/Winamp/attributes.h
@@ -0,0 +1,94 @@
+#ifndef NULLSOFT_WINAMP_ATTRIBUTES_H
+#define NULLSOFT_WINAMP_ATTRIBUTES_H
+
+#include "../Agave/Config/ifc_configitem.h"
+
+class _bool_base : public ifc_configitem
+{
+public:
+ _bool_base();
+ bool GetBool();
+ void SetBool(bool boolValue);
+ intptr_t GetInt();
+ void SetInt(intptr_t intValue);
+ operator intptr_t();
+ intptr_t operator =(intptr_t intValue);
+ bool operator =(bool boolValue);
+ operator bool();
+ operator UINT(); // for CheckDlgButton
+ bool operator !();
+protected:
+ bool value;
+};
+
+class _bool : public _bool_base
+{
+public:
+ _bool(bool defaultValue);
+protected:
+ RECVS_DISPATCH;
+};
+
+/* _mutable_bool allows the config item to be changed via users of api_config */
+class _mutable_bool : public _bool_base
+{
+public:
+ _mutable_bool(bool defaultValue);
+protected:
+ RECVS_DISPATCH;
+};
+
+class _unsigned : public ifc_configitem
+{
+public:
+ _unsigned();
+ _unsigned(uintptr_t defaultValue);
+
+ uintptr_t GetUnsigned() { return value; }
+ uintptr_t operator =(uintptr_t uintValue);
+ operator uintptr_t() { return value; }
+
+protected:
+ RECVS_DISPATCH;
+private:
+ uintptr_t value;
+};
+
+class _int : public ifc_configitem
+{
+public:
+ _int();
+ _int(intptr_t defaultValue);
+
+ intptr_t GetInt() { return value; }
+ float GetFloat() { return (float)value; }
+ intptr_t operator =(intptr_t uintValue);
+ operator intptr_t() { return value; }
+
+protected:
+ RECVS_DISPATCH;
+private:
+ intptr_t value;
+};
+
+class _float : public ifc_configitem
+{
+public:
+ _float();
+ _float(float defaultValue);
+
+ intptr_t GetInt() { return (intptr_t)value; }
+ intptr_t operator =(intptr_t uintValue);
+ operator intptr_t() { return static_cast<intptr_t>(value); }
+
+ float GetFloat() { return value; }
+ float operator =(float uintValue);
+ operator float () { return value; }
+
+protected:
+ RECVS_DISPATCH;
+private:
+ float value;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/b4s.cpp b/Src/Winamp/b4s.cpp
new file mode 100644
index 00000000..5d529333
--- /dev/null
+++ b/Src/Winamp/b4s.cpp
@@ -0,0 +1,8 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
diff --git a/Src/Winamp/b4s.h b/Src/Winamp/b4s.h
new file mode 100644
index 00000000..642dca8a
--- /dev/null
+++ b/Src/Winamp/b4s.h
@@ -0,0 +1,6 @@
+#ifndef NULLSOFT_WINAMP_B4S_H
+#define NULLSOFT_WINAMP_B4S_H
+
+
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/benskiQ/Biquad.cpp b/Src/Winamp/benskiQ/Biquad.cpp
new file mode 100644
index 00000000..5fa030bd
--- /dev/null
+++ b/Src/Winamp/benskiQ/Biquad.cpp
@@ -0,0 +1,204 @@
+#include "Biquad.h"
+#include <assert.h>
+#include <math.h>
+
+Biquad::Biquad()
+ : sampleRate(44100)
+ , _f0(1000)
+{
+ _z_eq_b[0] = 1;
+ _z_eq_b[1] = 0;
+ _z_eq_b[2] = 0;
+ _z_eq_a[0] = 1;
+ _z_eq_a[1] = 0;
+ _z_eq_a[2] = 0;
+
+ clear_buffers();
+
+ _s_eq_a[0] = 1;
+ _s_eq_a[1] = 2;
+ _s_eq_a[2] = 1;
+
+ _s_eq_b[0] = _s_eq_a[0];
+ _s_eq_b[1] = _s_eq_a[1];
+ _s_eq_b[2] = _s_eq_a[2];
+}
+
+
+#define M_PI 3.14159265358979323846
+// warp to the z-plane
+void Biquad::transform_s_to_z()
+{
+ // s to z bilinear transform
+ const double inv_k = tan(_f0 * M_PI / sampleRate);
+ const double k = 1 / inv_k;
+ const double kk = k*k;
+
+ const double b1k = _s_eq_b[1] * k;
+ const double b2kk = _s_eq_b[2] * kk;
+ const double b2kk_plus_b0 = b2kk + _s_eq_b[0];
+ const double b0z = b2kk_plus_b0 + b1k;
+ const double b2z = b2kk_plus_b0 - b1k;
+ const double b1z = 2 * (_s_eq_b[0] - b2kk);
+
+ const double a1k = _s_eq_a[1] * k;
+ const double a2kk = _s_eq_a[2] * kk;
+ const double a2kk_plus_a0 = a2kk + _s_eq_a[0];
+ const double a0z = a2kk_plus_a0 + a1k;
+ const double a2z = a2kk_plus_a0 - a1k;
+ const double a1z = 2 * (_s_eq_a[0] - a2kk);
+
+ // IIR coefficients
+ const double mult = 1 / a0z;
+
+ _z_eq_b[0] = float(b0z * mult);
+ _z_eq_b[1] = float(b1z * mult);
+ _z_eq_b[2] = float(b2z * mult);
+
+ _z_eq_a[0] = 1;
+ _z_eq_a[1] = float(a1z * mult);
+ _z_eq_a[2] = float(a2z * mult);
+}
+
+void Biquad::process_block(float *dest_ptr, const float *src_ptr, long nbr_spl)
+{
+ assert(nbr_spl >= 0);
+
+ if (nbr_spl == 0)
+ {
+ return;
+ }
+
+// If we're not on a pair boudary, we process a single sample.
+ if (_mem_pos != 0)
+ {
+ *dest_ptr++ = (float)process_sample(*src_ptr++);
+ nbr_spl--;
+ }
+
+ if (nbr_spl == 0)
+ {
+ return;
+ }
+
+ long half_nbr_spl = nbr_spl >> 1;
+ long index = 0;
+ if (half_nbr_spl > 0)
+ {
+ double mem_x[2];
+ double mem_y[2];
+ mem_x[0] = xn[0];
+ mem_x[1] = xn[1];
+ mem_y[0] = yn[0];
+ mem_y[1] = yn[1];
+
+ do
+ {
+
+ float x = src_ptr[index];
+ mem_y[1] = _z_eq_b[0] * x
+ + (_z_eq_b[1] * mem_x[0]
+ + _z_eq_b[2] * mem_x[1])
+ - (_z_eq_a[1] * mem_y[0]
+ + _z_eq_a[2] * mem_y[1]);
+
+ mem_x[1] = x;
+ dest_ptr[index] = (float)mem_y[1];
+
+ x = src_ptr[index + 1];
+ mem_y[0] = _z_eq_b[0] * x
+ + (_z_eq_b[1] * mem_x[1]
+ + _z_eq_b[2] * mem_x[0])
+ - (_z_eq_a[1] * mem_y[1]
+ + _z_eq_a[2] * mem_y[0]);
+
+ mem_x[0] = x;
+ dest_ptr[index + 1] = (float)mem_y[0];
+ index += 2;
+
+ -- half_nbr_spl;
+ }
+ while (half_nbr_spl > 0);
+
+ xn[0] = mem_x[0];
+ xn[1] = mem_x[1];
+ yn[0] = mem_y[0];
+ yn[1] = mem_y[1];
+ }
+
+// If number of samples was odd, there is one more to process.
+ if ((nbr_spl & 1) > 0)
+ {
+ dest_ptr[index] = (float)process_sample(src_ptr[index]);
+ }
+}
+
+void Biquad::clear_buffers()
+{
+ xn[0] = 0;
+ xn[1] = 0;
+ yn[0] = 0;
+ yn[1] = 0;
+ _mem_pos = 0;
+}
+
+double Biquad::process_sample(double x)
+{
+ const int alt_pos = 1 - _mem_pos;
+ const double y = _z_eq_b[0] * x
+ + (_z_eq_b[1] * xn[_mem_pos]
+ + _z_eq_b[2] * xn[alt_pos])
+ - (_z_eq_a[1] * yn[_mem_pos]
+ + _z_eq_a[2] * yn[alt_pos]);
+
+ xn[alt_pos] = x;
+ yn[alt_pos] = y;
+ _mem_pos = alt_pos;
+
+ return (y);
+}
+
+void Biquad::copy_filter(const Biquad &other)
+{
+ _z_eq_b[0] = other._z_eq_b[0];
+ _z_eq_b[1] = other._z_eq_b[1];
+ _z_eq_b[2] = other._z_eq_b[2];
+ _z_eq_a[1] = other._z_eq_a[1];
+ _z_eq_a[2] = other._z_eq_a[2];
+
+ sampleRate = other.sampleRate;
+ _f0 = other._f0;
+ set_s_eq(other._s_eq_b, other._s_eq_a);
+}
+
+void Biquad::SetSampleRate(double fs)
+{
+ assert(fs > 0);
+
+ sampleRate = fs;
+ transform_s_to_z();
+}
+
+void Biquad::set_freq(double f0)
+{
+ assert(f0 > 0);
+
+ _f0 = f0;
+}
+
+void Biquad::set_s_eq(const double b[3], const double a[3])
+{
+ assert(a != 0);
+ assert(a[2] != 0);
+ assert(b != 0);
+
+ _s_eq_b[0] = float(b[0]);
+ _s_eq_b[1] = float(b[1]);
+ _s_eq_b[2] = float(b[2]);
+
+ _s_eq_a[0] = float(a[0]);
+ _s_eq_a[1] = float(a[1]);
+ _s_eq_a[2] = float(a[2]);
+}
+
+
diff --git a/Src/Winamp/benskiQ/Biquad.h b/Src/Winamp/benskiQ/Biquad.h
new file mode 100644
index 00000000..ad7ab3a5
--- /dev/null
+++ b/Src/Winamp/benskiQ/Biquad.h
@@ -0,0 +1,29 @@
+#pragma once
+
+class Biquad
+{
+public:
+ Biquad();
+ void copy_filter(const Biquad &other);
+ void SetSampleRate(double fs);
+ void set_freq(double f0);
+ void set_s_eq(const double b[3], const double a[3]);
+ void transform_s_to_z();
+
+ void process_block(float *dest_ptr, const float *src_ptr, long nbr_spl);
+ void clear_buffers();
+
+private:
+ double _s_eq_b[3]; // Coefs for numerator (zeros)
+ double _s_eq_a[3]; // Coefs for denominator (poles)
+ double _z_eq_b[3]; // Direct coefficients, order z^(-n)
+ double _z_eq_a[3]; // Recursive coefficients, order z^(-n)
+ double sampleRate; // Hz, > 0
+ double _f0; // Hz, > 0, _f0 % (_sample_freq/2) != 0
+ double xn[2]; // Input memory, order z^(-n)
+ double yn[2]; // Output memory, order z^(-n)
+ int _mem_pos; // 0 or 1
+
+ inline double process_sample(double x);
+};
+
diff --git a/Src/Winamp/benskiQ/EqBand.cpp b/Src/Winamp/benskiQ/EqBand.cpp
new file mode 100644
index 00000000..ea9d4037
--- /dev/null
+++ b/Src/Winamp/benskiQ/EqBand.cpp
@@ -0,0 +1,81 @@
+#include "EqBand.h"
+#include <assert.h>
+#include <math.h>
+
+EqBand::EqBand() : sampleRate(44100), centerFrequency(1000), gain(1), _q(0.5), nch(0), channels(0), bypass(true)
+{
+}
+
+void EqBand::set_num_channels(int num_channels)
+{
+ if (nch < num_channels)
+ {
+ nch = num_channels;
+ delete[]channels;
+ channels = new Biquad[nch];
+ clear_buffers();
+ set_parameters(centerFrequency, gain, _q);
+ }
+}
+
+void EqBand::SetSampleRate(double sample_freq)
+{
+ if (sample_freq != sampleRate)
+ {
+ sampleRate = sample_freq;
+ for (int chn = 0; chn < nch; ++chn)
+ {
+ channels[chn].SetSampleRate(sampleRate);
+ }
+ clear_buffers();
+ set_parameters(centerFrequency, gain, _q);
+ }
+}
+
+void EqBand::set_parameters(double freq, double newGain, double q)
+{
+ centerFrequency = freq;
+ gain = newGain;
+ _q = q;
+
+ if (nch > 0)
+ {
+ Biquad & ref_filter = channels[0];
+
+ ref_filter.set_freq(centerFrequency);
+
+ double a[3] = { 1, 1/_q, 1 };
+ double b[3] = {1, gain / _q, 1};
+ ref_filter.set_s_eq(b, a);
+
+ ref_filter.transform_s_to_z();
+
+ for (int chn = 1; chn < nch; ++chn)
+ channels[chn].copy_filter(ref_filter);
+ }
+
+ bypass = (fabs(gain - 1.0) < 0.02); // About 1/4 dB
+}
+
+void EqBand::process(float ** const out, float ** in, long nbr_spl, int nbr_chn)
+{
+ assert(nbr_chn >= 0);
+ assert(nbr_chn <= nch);
+
+ if (!bypass)
+ {
+ for (int chn = 0; chn < nbr_chn; ++chn)
+ {
+ channels[chn].process_block(out[chn], in[chn], nbr_spl);
+ }
+ }
+}
+
+void EqBand::clear_buffers()
+{
+ for (int chn = 0; chn < nch; ++chn)
+ {
+ channels[chn].clear_buffers();
+ }
+}
+
diff --git a/Src/Winamp/benskiQ/EqBand.h b/Src/Winamp/benskiQ/EqBand.h
new file mode 100644
index 00000000..53f1c9ce
--- /dev/null
+++ b/Src/Winamp/benskiQ/EqBand.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "Biquad.h"
+
+class EqBand
+{
+public:
+ EqBand();
+ void set_num_channels(int num_channels);
+ void SetSampleRate(double sample_freq);
+ void set_parameters(double freq, double gain, double q);
+ void process(float ** const out, float ** in, long nbr_spl, int nbr_chn);
+
+private:
+ double sampleRate, centerFrequency, gain;
+ double _q;
+ int nch;
+ Biquad *channels;
+ bool bypass;
+
+ void clear_buffers();
+};
+
diff --git a/Src/Winamp/benskiQ/benskiQ.cpp b/Src/Winamp/benskiQ/benskiQ.cpp
new file mode 100644
index 00000000..aeaddf0e
--- /dev/null
+++ b/Src/Winamp/benskiQ/benskiQ.cpp
@@ -0,0 +1,231 @@
+#include "main.h"
+
+#include "EqBand.h"
+#include "WinampAttributes.h"
+
+#include <math.h>
+
+extern int filter_srate, filter_enabled, filter_top, filter_top2;
+extern float preamp_val;
+
+static int filter_nch=0;
+static bool init=false;
+static EqBand benskiQ[10];
+//#define BENSKIQ_Q 0.70710678118654752440084436210485
+#define BENSKIQ_Q 1.41
+static double benskiQ_freqs_iso[10]={31.5, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000}; // ISO standard equalizer frequency table
+static double benskiQ_freqs[10]={ 70, 180, 320, 600, 1000, 3000, 6000, 12000, 14000, 16000 }; // winamp style frequency table
+
+static CRITICAL_SECTION benskiQ_cs;
+void benskiQ_init()
+{
+ InitializeCriticalSection(&benskiQ_cs);
+ for (int x=0;x<10;x++)
+ {
+ benskiQ[x].set_parameters((config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?benskiQ_freqs[x]:benskiQ_freqs_iso[x], 1.0, BENSKIQ_Q);
+ }
+}
+
+
+static __inline double VALTODB(int v)
+{
+ v -= 31;
+ if (v < -31) v = -31;
+ if (v > 32) v = 32;
+
+ if (v > 0) return -12.0*(v / 32.0);
+ else if (v < 0)
+ {
+ return -12.0*(v / 31.0);
+ }
+ return 0.0f;
+}
+
+static __inline double VALTOGAIN(int v)
+{
+ return pow(10.0, VALTODB(v)/20.0);
+}
+
+void benskiQ_eq_set(char data[10])
+{
+ if (!init)
+ {
+ init=true; benskiQ_init();
+ }
+ EnterCriticalSection(&benskiQ_cs);
+ for (int x = 0; x < 10; x ++)
+ {
+ benskiQ[x].set_parameters((config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?benskiQ_freqs[x]:benskiQ_freqs_iso[x], VALTOGAIN(data[x]), BENSKIQ_Q);
+ }
+ LeaveCriticalSection(&benskiQ_cs);
+}
+
+static void FillFloat(float **floatBuf, void *samples, size_t bps, size_t numSamples, size_t numChannels, float preamp)
+{
+ switch (bps)
+ {
+ case 8:
+ {
+ preamp /= 256.0f;
+ unsigned __int8 *samples8 = (unsigned __int8 *)samples;
+ for (size_t c=0;c<numChannels;c++)
+ for (size_t x = 0; x != numSamples; x ++)
+ {
+ floatBuf[c][x] = (float)(samples8[c+numChannels*x]-128) * preamp;
+ }
+ }
+ break;
+ case 16:
+ {
+ preamp/=32768.0f;
+ short *samples16 = (short *)samples;
+ for (size_t c=0;c<numChannels;c++)
+ for (size_t x = 0; x != numSamples; x ++)
+ {
+ floatBuf[c][x] = (float)samples16[c+numChannels*x] * preamp;
+ }
+ }
+ break;
+ case 24:
+ {
+ preamp/=2147483648.0f;
+ unsigned __int8 *samples8 = (unsigned __int8 *)samples;
+
+ long temp;
+
+ for (size_t x = 0; x != numSamples; x ++)
+ for (size_t c=0;c<numChannels;c++)
+ {
+ temp = (((long)samples8[0]) << 8);
+ temp = temp | (((long)samples8[1]) << 16);
+ temp = temp | (((long)samples8[2]) << 24);
+ floatBuf[c][x] = (float)temp * preamp;
+ samples8+=3;
+ }
+ }
+ break;
+ case 32:
+ {
+ preamp /= 2147483648.0f;
+ int32_t *samples32 = (int32_t *)samples;
+ for (size_t x = 0; x != numSamples; x ++)
+ for (size_t c=0;c<numChannels;c++)
+ {
+ floatBuf[c][x] = (float)samples32[c+x*numChannels] * preamp;
+ }
+ }
+ break;
+ }
+}
+
+static void FillSamples(void *samples, float **floatBuf, size_t bps, size_t numSamples, size_t numChannels)
+{
+ switch (bps)
+ {
+ case 16:
+ for (size_t i=0;i<numChannels;i++)
+ Float32_To_Int16_Clip((char *)samples+i*(bps/8), (signed int)numChannels, floatBuf[i], 1, (unsigned int) numSamples);
+ break;
+ case 24:
+ for (size_t i=0;i<numChannels;i++)
+ Float32_To_Int24_Clip((char *)samples+i*(bps/8), (signed int)numChannels, floatBuf[i], 1, (unsigned int) numSamples);
+ break;
+
+ }
+}
+
+static int last_nch=0, last_numsamples=0;
+static float **last_sample=0;
+void DeleteSample(float **big, int nch)
+{
+ for (int i=0;i<nch;i++)
+ delete big[i];
+ delete[]big;
+}
+
+float **MakeSample(int numsamples, int nch)
+{
+ if (last_nch < nch || last_numsamples < numsamples)
+ {
+ DeleteSample(last_sample, last_nch);
+ last_nch=max(nch, last_nch);
+ last_numsamples=max(numsamples, last_numsamples);
+ last_sample = new float*[last_nch];
+ for (int i=0;i<last_nch;i++)
+ last_sample [i]=new float[last_numsamples];
+ }
+ return last_sample;
+}
+
+void benskiQ_reset(int srate, int nch)
+{
+ for (int i=0;i<10;i++)
+ {
+ benskiQ[i].SetSampleRate(srate);
+ benskiQ[i].set_num_channels(nch);
+ }
+
+ int x;
+ if (config_eq_frequencies == EQ_FREQUENCIES_WINAMP)
+ for (x = 0; x < 10 && benskiQ_freqs[x]*2 <= srate; x++);
+ else
+ for (x = 0; x < 10 && benskiQ_freqs_iso[x]*2 <= srate; x++);
+ filter_top = min(x, filter_top2);
+ filter_srate=srate;
+ filter_nch=nch;
+}
+
+static float NonReplayGainAdjust()
+{
+ if (!(in_mod->UsesOutputPlug&IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool())
+ return pow(10.0f, (float)config_replaygain_non_rg_gain/20.0f);
+ else
+ return 1.0f;
+}
+
+static float ReplayGainPreamp()
+{
+ if (!(in_mod->UsesOutputPlug&IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool())
+ return pow(10.0f, (float)config_replaygain_preamp/20.0f);
+ else
+ return 1.0f;
+}
+
+int benskiQ_eq_dosamples(short *samples, int numsamples, int bps, int nch, int srate)
+{
+ if (filter_enabled && in_mod && !(in_mod->UsesOutputPlug&IN_MODULE_FLAG_EQ) && bps != 32)
+ {
+ if (srate !=filter_srate || nch != filter_nch)
+ benskiQ_reset(srate, nch);
+
+ if (!init)
+ {
+ init=true; benskiQ_init();
+ }
+ float **in = MakeSample(numsamples, nch);
+
+ FillFloat(in, samples, bps, numsamples, nch, preamp_val*NonReplayGainAdjust()*ReplayGainPreamp());
+ EnterCriticalSection(&benskiQ_cs);
+ for (int x = 0; x < filter_top; x ++)
+ {
+ benskiQ[x].process(in, in, numsamples, nch);
+ }
+ LeaveCriticalSection(&benskiQ_cs);
+ FillSamples(samples, in, bps, numsamples, nch);
+ }
+ else if (!(in_mod->UsesOutputPlug&IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool() && (config_replaygain_non_rg_gain.GetFloat() != 0) && bps != 32)
+ {
+ float **in = MakeSample(numsamples, nch);
+ FillFloat(in, samples, bps, numsamples, nch, NonReplayGainAdjust()*ReplayGainPreamp());
+ FillSamples(samples, in, bps, numsamples, nch);
+ }
+ else if (!(in_mod->UsesOutputPlug&IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool() && (config_replaygain_preamp.GetFloat() != 0) && bps != 32)
+ {
+ float **in = MakeSample(numsamples, nch);
+ FillFloat(in, samples, bps, numsamples, nch, ReplayGainPreamp());
+ FillSamples(samples, in, bps, numsamples, nch);
+ }
+ else
+ filter_srate = 0;
+ return dsp_dosamples(samples, numsamples, bps, nch, srate);
+}
diff --git a/Src/Winamp/bm.cpp b/Src/Winamp/bm.cpp
new file mode 100644
index 00000000..24127018
--- /dev/null
+++ b/Src/Winamp/bm.cpp
@@ -0,0 +1,129 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "../Plugins/Library/ml_bookmarks/bookmark.h"
+#include <malloc.h>
+#include "api.h"
+#include "../nu/AutoCharFn.h"
+#include "../nu/AutoChar.h"
+#include <strsafe.h>
+
+void Bookmark_additem(wchar_t *fn, wchar_t *ft)
+{
+ if ((!fn || fn && !*fn) || (!ft || ft && !*ft)) return;
+
+ BookmarkWriter bookmarks;
+ bookmarks.Open(BOOKMARKFILE);
+ bookmarks.Write(AutoCharFn(fn), AutoCharFn(ft));
+ bookmarks.Close();
+
+ bookmarks.Open(BOOKMARKFILE8);
+ bookmarks.Write(AutoChar(fn, CP_UTF8), AutoChar(ft, CP_UTF8));
+ bookmarks.Close();
+
+ size_t bufSize = wcslen(fn)+wcslen(ft)+3;
+ wchar_t *buf=(wchar_t*)_malloca(bufSize*sizeof(wchar_t)), *buf2pass = buf;
+ if (buf)
+ {
+ StringCchCopyExW(buf, bufSize, fn, &buf, &bufSize, 0);
+ buf++; bufSize--;
+ StringCchCopyW(buf, bufSize, ft);
+ SendMessageW(hMainWindow,WM_WA_IPC,(WPARAM)buf2pass,IPC_ADDBOOKMARKW);
+ AGAVE_API_STATS->IncrementStat(api_stats::BOOKMARK_COUNT);
+ _freea(buf);
+ }
+}
+
+void Bookmark_AddCommandline(wchar_t *lpszCmdParam)
+{
+ wchar_t *p = lpszCmdParam;
+ if (p)
+ {
+ if (*p == L'\"') { p++; p[lstrlenW(p) - 1] = 0; }
+ Bookmark_additem(p, PlayList_gettitle(p, 1));
+ }
+}
+
+void WriteEscaped(FILE *fp, const char *str)
+{
+ // TODO: for speed optimization,
+ // we should wait until we hit a special character
+ // and write out everything else so before it,
+ // like how ASX loader does it
+ while (str && *str)
+ {
+ switch(*str)
+ {
+ case '&':
+ fputs("&amp;", fp);
+ break;
+ case '>':
+ fputs("&gt;", fp);
+ break;
+ case '<':
+ fputs("&lt;", fp);
+ break;
+ case '\'':
+ fputs("&apos;", fp);
+ break;
+ case '\"':
+ fputs("&quot;", fp);
+ break;
+ default:
+ fputc(*str, fp);
+ break;
+ }
+ // write out the whole character
+ char *next = CharNextA(str);
+ while (++str != next)
+ fputc(*str, fp);
+ }
+}
+
+void Bookmark_WriteAsXML(const wchar_t *filename, int max)
+{
+ FILE *destFp=_wfopen(filename,L"wb");
+ FILE *fp=_wfopen(BOOKMARKFILE8,L"rt");
+
+ if (fp && destFp)
+ {
+ //fprintf(destFp, "<?xml version=\"1.0\" encoding=\"windows-%u\"?>", GetACP());
+ fprintf(destFp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ fputs("<bookmarks>\n", destFp);
+ int x=0;
+ for (;;)
+ {
+ char ft[4096] = {0}, fn[4096] = {0};
+ fgets(fn,4096,fp);
+ if (feof(fp)) break;
+ fgets(ft,4096,fp);
+ if (feof(fp)) break;
+ if (ft[0] && fn[0])
+ {
+ if (fn[strlen(fn)-1]=='\n') fn[strlen(fn)-1]=0;
+ if (ft[strlen(ft)-1]=='\n') ft[strlen(ft)-1]=0;
+ if (ft[0] && fn[0])
+ {
+ fputs("<bookmark file=\"", destFp);
+ WriteEscaped(destFp, fn);
+ fputs("\" title=\"", destFp);
+ WriteEscaped(destFp, ft);
+ fputs("\"/>\n", destFp);
+ x++;
+ }
+ }
+ if (x == max)
+ break;
+ }
+ fputs("</bookmarks>", destFp);
+ }
+ if (fp)
+ fclose(fp);
+ if (destFp)
+ fclose(destFp);
+} \ No newline at end of file
diff --git a/Src/Winamp/bookmark.cpp b/Src/Winamp/bookmark.cpp
new file mode 100644
index 00000000..d0541819
--- /dev/null
+++ b/Src/Winamp/bookmark.cpp
@@ -0,0 +1,25 @@
+#include "main.h"
+#include "api.h"
+#include <stdio.h>
+
+void Bookmark_additem(char *fn, char *ft)
+{
+ FILE *fp;
+
+ fp=fopen(BOOKMARKFILE,"a+t");
+ if (fp)
+ {
+ char *buf=(char*)malloc(lstrlen(fn)+lstrlen(ft)+3);
+ fprintf(fp,"%s\n%s\n",fn,ft);
+ fclose(fp);
+ if (buf)
+ {
+ lstrcpy(buf,fn);
+ lstrcpy(buf+lstrlen(buf)+1,ft);
+ SendMessage(hMainWindow,WM_WA_IPC,(WPARAM)buf,IPC_ADDBOOKMARK);
+ free(buf);
+ AGAVE_API_STATS->IncrementStat(api_stats::BOOKMARK_COUNT);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/buildType.h b/Src/Winamp/buildType.h
new file mode 100644
index 00000000..119903d4
--- /dev/null
+++ b/Src/Winamp/buildType.h
@@ -0,0 +1,13 @@
+#pragma once
+/* This file will be generated by the build process automatically
+ You can modify this file to have sane values for local developer builds */
+
+#define APP_VERSION "5.9.2"
+#define APP_VERSION_STRING "5.9.2 Build 10042"
+#define APP_VERSION_NUM 0x00005092
+#define BUILD_NUMBER 10042
+#define WINAMP_FILEVER 5,9,2,10042
+#define WINAMP_PRODUCTVER 5,9,2,10042
+#define STR_WINAMP_FILEVER "5,9,2,10042"
+#define STR_WINAMP_PRODUCTVER "5,9,2,10042"
+#define SPECIAL_BUILD_NAME L"Winamp"
diff --git a/Src/Winamp/burn.cpp b/Src/Winamp/burn.cpp
new file mode 100644
index 00000000..d1a6cc8d
--- /dev/null
+++ b/Src/Winamp/burn.cpp
@@ -0,0 +1,220 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "resource.h"
+#include <windows.h>
+#include <strsafe.h>
+#include <time.h>
+#include <math.h>
+
+#include "./api.h"
+#include "./wa_ipc.h"
+#include "../nu/ns_wc.h"
+#include "../nu/AutoWide.h"
+#include "../Agave/Language/api_language.h"
+#include <api/service/waservicefactory.h>
+#ifdef BURN_SUPPORT
+#include "../primo/obj_primo.h"
+#include "../burnlib/burnlib.h"
+
+#endif
+
+static void code(long* v, long* k)
+{
+ unsigned long y = v[0], z = v[1], sum = 0, delta = 0x9e3779b9, n = 32 ; /* key schedule constant*/
+ while (n-- > 0)
+ { /* basic cycle start */
+ sum += delta;
+ y += ((z << 4) + k[0]) ^ (z + sum) ^ ((z >> 5) + k[1]);
+ z += ((y << 4) + k[2]) ^ (y + sum) ^ ((y >> 5) + k[3]); /* end cycle */
+ }
+ v[0] = y; v[1] = z;
+}
+
+int getRegVer(HWND waWnd)
+{
+ int *x = (int*)malloc(32);
+ long s[3];
+ long ss[2] = {(long)GetTickCount64(), (long)((int)x + (int)s)};
+ long tealike_key[4] = { 31337, 0xf00d, 0xdead, 0xbeef};
+ free(x);
+ s[0] = ss[0];
+ s[1] = ss[1];
+ s[2] = 0;
+
+ SendMessageW(waWnd, WM_WA_IPC, (WPARAM)s, IPC_GETREGISTEREDVERSION);
+ code(ss, tealike_key);
+ return (memcmp(s, ss, 8)) ? 0 : s[2];
+}
+
+#ifdef BURN_SUPPORT
+int burn_start(burnCDStruct *param)
+{
+ char buf[MAX_PATH] = "\"";
+ STARTUPINFO si = {sizeof(si), };
+ PROCESS_INFORMATION pi;
+ GetModuleFileName(NULL, buf + 1, sizeof(buf) - 1);
+ StringCchCat(buf, MAX_PATH, "\"");
+ StringCchPrintf(buf + lstrlen(buf), MAX_PATH - lstrlen(buf), " /BURN=%c,\"%s\",%d", param->cdletter, param->playlist_file, param->callback_hwnd);
+ return (CreateProcess(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) ? pi.dwProcessId : 0;
+}
+extern "C"
+{
+ typedef int (*BurnFunction)(const wchar_t*, HWND, DWORD, DWORD, DWORD , const wchar_t*);
+}
+
+#define BURNER_OK 0x0000
+#define BURNER_FAILED 0x0001
+#define BURNER_PRIMOFAILED 0x0FF0
+#define BURNER_BADPLAYLISTPATH 0x0FF1
+#define BURNER_BADTEMPPATH 0x0FF2
+#define BURNER_BADCONFIGPATH 0x0FF3
+#define BURNER_BADCOMMANDLINE 0x0FF4
+#define BURNER_BADDRIVELETTER 0x0FF5
+#define BURNER_EMPTYPLAYLIST 0x0FF6
+#define BURNER_DIALOGFAILED 0x0FF7
+
+void ReportError(HWND ownerWnd, int errorCode)
+{
+ wchar_t description[128] = {0};
+
+ switch (errorCode)
+ {
+ case BURNER_OK: return ;
+ case BURNER_PRIMOFAILED: getStringW(IDS_BURN_LIBRARY_INIT_FAILED,description,128); break;
+ case BURNER_BADPLAYLISTPATH: getStringW(IDS_BURN_INVALID_PLAYLIST_PATH,description,128); break;
+ case BURNER_BADTEMPPATH: getStringW(IDS_BURN_INVALID_TEMP_PATH,description,128); break;
+ case BURNER_BADCONFIGPATH: getStringW(IDS_BURN_INVALID_CONFIG_PATH,description,128); break;
+ case BURNER_BADCOMMANDLINE: getStringW(IDS_BURN_INVALID_CMDLINE,description,128); break;
+ case BURNER_BADDRIVELETTER: getStringW(IDS_BURN_BAD_DRIVE_LETTER,description,128); break;
+ case BURNER_EMPTYPLAYLIST: getStringW(IDS_BURN_LOAD_FROM_PLAYLIST_FAIL,description,128); break;
+ case BURNER_DIALOGFAILED: getStringW(IDS_BURN_CREATE_DIALOG_FAIL,description,128); break;
+ default: getStringW(IDS_BURN_UNKNOWN_ERROR,description,128); break;
+ }
+
+ wchar_t message[1024] = {0};
+ if (S_OK != StringCchPrintfW(message, 1024, getStringW(IDS_BURN_INIT_ERROR_REASON,NULL,0), description))
+ {
+ StringCchCopyW(message, 1024, getStringW(IDS_BURN_INIT_ERROR_UNKNOWN,NULL,0));
+ }
+ MessageBoxW(ownerWnd, message, getStringW(IDS_BURN_NULLSOFT_STR,NULL,0), MB_OK | MB_ICONSTOP);
+}
+
+unsigned int burn_doBurn(char *cmdline, HWND winampWnd, HINSTANCE winampInstance)
+{
+// PrimoSDK::Trace(FALSE);
+
+#ifdef _DEBUG
+ MessageBox(NULL, "Starting burner", "Debug", MB_OK);
+#endif
+
+ HWND callbackWnd = 0;
+ DWORD speed = 0;
+ DWORD cdrom = 0;
+ DWORD flags = PRIMOSDK_CLOSEDISC;
+ DWORD errorCode = BURNER_OK;
+ wchar_t tmppath[4*MAX_PATH] = {0};
+ wchar_t in_wm[MAX_PATH] = {0};
+ wchar_t playlist[4096] = {0};
+
+ // get temp path
+ if (BURNER_OK == errorCode && !GetTempPathW(MAX_PATH, tmppath)) errorCode = BURNER_BADTEMPPATH;
+
+ if (BURNER_OK == errorCode) //// parse parameters
+ {
+ if (lstrlenA(cmdline) < 1) errorCode = BURNER_BADCOMMANDLINE;
+
+ if (BURNER_OK == errorCode)
+ {
+ // drive letter
+ CharUpperBuff(cmdline, 1);
+ cdrom = cmdline[0];
+ for (int i = 0; i < 2; i++) cmdline = CharNext(cmdline);
+ if (cdrom < 'A' || cdrom > 'Z') errorCode = BURNER_BADDRIVELETTER;
+ }
+
+ if (BURNER_OK == errorCode)
+ {
+ // callback window
+ char *current = cmdline + lstrlenA(cmdline);
+ while (current != cmdline && *current != ',') current = CharPrevA(cmdline, current);
+ callbackWnd = (current != cmdline) ? (HWND)atoi(CharNext(current)) : NULL;
+
+ // playlist path
+ size_t cchLen = current - cmdline;
+ if (cchLen == 0) errorCode = BURNER_BADPLAYLISTPATH;
+
+ if (BURNER_OK == errorCode)
+ {
+ if (!MultiByteToWideCharSZ(CP_ACP, 0, cmdline, current - cmdline, playlist, 4096)) errorCode = BURNER_BADPLAYLISTPATH;
+ else playlist[cchLen] = 0x0000;
+ }
+ }
+
+ if (BURNER_OK == errorCode)
+ {
+ speed = GetPrivateProfileIntW(L"gen_ml_config", L"cdburnspeed", PRIMOSDK_MIN, ML_INI_FILE);
+ DWORD maxspeed = GetPrivateProfileIntW(L"gen_ml_config", L"cdburnmaxspeed", PRIMOSDK_MIN, ML_INI_FILE);
+ if (!getRegVer(winampWnd)) speed = PRIMOSDK_MIN;
+ if (!speed) speed = maxspeed;
+ if (!speed) speed = PRIMOSDK_MIN;
+
+ flags |= (GetPrivateProfileIntW(L"gen_ml_config", L"cdburntestmode", 0, ML_INI_FILE)) ? PRIMOSDK_TEST : PRIMOSDK_WRITE;
+ flags |= (GetPrivateProfileIntW(L"gen_ml_config", L"cdburnproof", 0, ML_INI_FILE)) ? PRIMOSDK_BURNPROOF : 0;
+ }
+ }
+
+ if (BURNER_OK != errorCode)
+ {
+ if (playlist[0] != 0x0000) DeleteFileW(playlist);
+ ReportError(callbackWnd, errorCode);
+ return errorCode;
+ }
+
+ // try in_wm version first
+ PathCombineW(in_wm, PLUGINDIR, L"in_wm.dll");
+ BurnFunction burnFunc = NULL;
+ HMODULE lib = LoadLibraryW(in_wm);
+ if (lib)
+ {
+ burnFunc = (BurnFunction)GetProcAddress(lib, "burn_doBurn");
+ if (burnFunc)
+ {
+ errorCode = burnFunc(playlist, callbackWnd, cdrom, speed, flags, tmppath);
+ }
+ }
+ if (lib) FreeLibrary(lib);
+ lib = NULL;
+
+ if (!burnFunc)
+ {
+ InitializeBurningLibrary(WASABI_API_SVC, hMainInstance, winampWnd);
+ BurnerPlaylist burnPL;
+ burnPL.Load(playlist);
+ if (!burnPL.GetCount()) errorCode = BURNER_EMPTYPLAYLIST;
+ else
+ {
+ obj_primo *primo=0;
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(obj_primo::getServiceGuid());
+ if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface());
+ if (!primo)
+ errorCode = BURNER_PRIMOFAILED;
+ else
+ {
+ BurnPlaylistUI burnDlg;
+ errorCode = burnDlg.Burn(primo, cdrom, speed, flags, &burnPL, tmppath, callbackWnd);
+ sf->releaseInterface(primo);
+ }
+ }
+ }
+
+ DeleteFileW(playlist);
+ if (BURNER_OK != errorCode) ReportError(callbackWnd, errorCode);
+ return errorCode;
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/burn.h b/Src/Winamp/burn.h
new file mode 100644
index 00000000..a4d5dbb0
--- /dev/null
+++ b/Src/Winamp/burn.h
@@ -0,0 +1,16 @@
+#define BURNCALLBACK_DIALOGOPEN (WM_USER + 0x500)
+#define BURNCOMMAND (WM_USER + 32)
+#define BURN_SETERRORPARENT (WM_USER+111)
+ #define BURNCOMMAND_GETSTATUS 1
+ #define BURNCOMMAND_GETPERCENT 2
+ #define BURNCOMMAND_CANCEL 666
+
+#define BURNTICK 0x123
+#define CANCELTICK 0x124
+
+
+#define STATUS_BURNING_DONE 7
+#define STATUS_BURNING_COMPLETE 100
+#define STATUS_START_BURNING 5
+#define STATUS_ERROR 999
+#define STATUS_BURNING 6 \ No newline at end of file
diff --git a/Src/Winamp/classic_vis.cpp b/Src/Winamp/classic_vis.cpp
new file mode 100644
index 00000000..bb2a943d
--- /dev/null
+++ b/Src/Winamp/classic_vis.cpp
@@ -0,0 +1,342 @@
+#include "main.h"
+#include "SABuffer.h"
+#include <math.h>
+#include "WinampAttributes.h"
+#include "fft.h"
+extern int _srate;
+#ifdef _M_IX86
+__inline static int lrint(float flt)
+{
+ int intgr;
+
+ _asm
+ {
+ fld flt
+ fistp intgr
+ }
+
+ return intgr;
+}
+#else
+__inline static int lrint(float flt)
+{
+ return (int)flt;
+}
+#endif
+
+
+// quantizes to 23 bits - use appropriately
+inline static float fastmin(float x, const float b)
+{
+ x = b - x;
+ x += (float)fabs(x);
+ x *= 0.5f;
+ x = b - x;
+ return x;
+}
+#define FASTMIN(x,b) { x = b - x; x += (float)fabs(x); x *= 0.5f; x = b - x; }
+inline static float fastclip(float x, const float a, const float b)
+{
+ float x1 = (float)fabs(x-a);
+ float x2 = (float)fabs(x-b);
+ x = x1 + (a+b);
+ x -= x2;
+ x *= 0.5f;
+ return (x);
+}
+
+
+void makeOscData(char *tempdata, char *data_buf, int little_block, int channels, int bits)
+{
+ float dd = little_block/75.0f;
+ int x,c;
+ int stride=bits/8; // number of bytes between samples
+
+ // we're calculating using only the most significant byte,
+ // because we only end up with 6 bit data anyway
+ // if you want full resolution, check out CVS tag BETA_2005_1122_182830, file: vis.c
+ char *ptr, *sbuf = data_buf;
+ for (x = 0; x < 75; x ++)
+ {
+ float val=0;
+ int index =(int)((float)x * dd); // calculate the nearest sample for this point, interpolation is too expensive for this use
+ ptr=&sbuf[index*stride*channels+stride-1]; // find first sample, and offset for little endian
+ for (c=0;c<channels;c++)
+ {
+ val += (float)*ptr / 8.0f; // we want our final value to be -32 to 32
+ ptr+=stride; // jump to the next sample (channels are interleaved)
+ }
+ tempdata[x] = (char)lrint(val / (float)channels); // average the channels
+ }
+}
+
+
+
+inline double fast_exp2(const double val)
+{
+ int e;
+ double ret;
+
+ if (val >= 0)
+ {
+ e = int (val);
+ ret = val - (e - 1);
+ ((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
+ }
+ else
+ {
+ e = int (val + 1023);
+ ret = val - (e - 1024);
+ ((*(1 + (int *) &ret)) &= ~(2047 << 20)) += e << 20;
+ }
+ return (ret);
+}
+
+// ~6 clocks on Pentium M vs. ~24 for single precision sqrtf
+#if !defined(_WIN64)
+static inline float squareroot_sse_11bits(float x)
+{
+ float z;
+ _asm
+ {
+ rsqrtss xmm0, x
+ rcpss xmm0, xmm0
+ movss z, xmm0 // z ~= sqrt(x) to 0.038%
+ }
+ return z;
+}
+
+static inline int floor_int(double x)
+{
+ int i;
+ static const float round_toward_m_i = -0.5f;
+ __asm
+ {
+ fld x
+ fadd st, st(0)
+ fadd round_toward_m_i
+ fistp i
+ sar i, 1
+ }
+
+ return (i);
+}
+#endif
+/*
+static inline float hermite(float x, float y0, float y1, float y2, float y3)
+{
+ // 4-point, 3rd-order Hermite (x-form)
+ float c0 = y1;
+ float c1 = 0.5f * (y2 - y0);
+ float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3;
+ float c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0);
+
+ return ((c3 * x + c2) * x + c1) * x + c0;
+}
+*/
+
+/*
+static const float c_half = 0.5f;
+__declspec(naked) static float hermite(float frac_pos, const float* pntr)
+{
+ __asm
+ {
+ push ecx;
+ mov ecx, dword ptr[esp + 12]; //////////////////////////////////////////////////////////////////////////////////////////////////
+ add ecx, 0x04; // ST(0) ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7)
+ fld dword ptr [ecx+4]; // x1
+ fsub dword ptr [ecx-4]; // x1-xm1
+ fld dword ptr [ecx]; // x0 x1-xm1
+ fsub dword ptr [ecx+4]; // v x1-xm1
+ fld dword ptr [ecx+8]; // x2 v x1-xm1
+ fsub dword ptr [ecx]; // x2-x0 v x1-xm1
+ fxch st(2); // x1-m1 v x2-x0
+ fmul c_half; // c v x2-x0
+ fxch st(2); // x2-x0 v c
+ fmul c_half; // 0.5*(x2-x0) v c
+ fxch st(2); // c v 0.5*(x2-x0)
+ fst st(3); // c v 0.5*(x2-x0) c
+ fadd st(0), st(1); // w v 0.5*(x2-x0) c
+ fxch st(2); // 0.5*(x2-x0) v w c
+ faddp st(1), st(0); // v+.5(x2-x0) w c
+ fadd st(0), st(1); // a w c
+ fadd st(1), st(0); // a b_neg c
+ fmul dword ptr [esp+8]; // a*frac b_neg c
+ fsubrp st(1), st(0); // a*f-b c
+ fmul dword ptr [esp+8]; // (a*f-b)*f c
+ faddp st(1), st(0); // res-x0/f
+ fmul dword ptr [esp+8]; // res-x0
+ fadd dword ptr [ecx]; // res
+ pop ecx;
+ ret;
+ }
+}
+*/
+inline float hermite(float x, float y0, float y1, float y2, float y3)
+{
+ // 4-point, 3rd-order Hermite (x-form)
+ float c0 = y1;
+ float c1 = 0.5f * (y2 - y0);
+ float c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0);
+ float c2 = y0 - y1 + c1 - c3;
+
+ return ((c3 * x + c2) * x + c1) * x + c0;
+}
+
+static inline float fpow2(const float y)
+{
+ union
+ {
+ float f;
+ int i;
+ } c;
+
+ int integer = lrint(floor(y));
+ /* cut: because we guarantee y>=0
+ if(y < 0)
+ integer = integer-1;
+ */
+
+ float frac = y - (float)integer;
+
+ c.i = (integer+127) << 23;
+ c.f *= 0.33977f*frac*frac + (1.0f-0.33977f)*frac + 1.0f;
+
+ return c.f;
+}
+
+//#define SAPOW(x) (powf(2.f, (float)(x)/12.f))
+#define SAPOW(x) (fpow2((float)(x)/12.f))
+//#define WARP(x) ((powf(1.1f, (float)(x)/12.f) - 1.) * bla)
+#define WARP(x) ((SAPOW(x) - 1.f) * bla)
+void makeSpecData(unsigned char *tempdata, float *wavetrum)
+{
+ //WARP(75);
+ float bla = (255.f/SAPOW(75.f));
+ fft_9(wavetrum);
+
+ float spec_scale=0.5;
+ if (config_replaygain)
+ { // benski> i'm sure there's some math identity we can use to optimize this.
+ spec_scale/=pow(10.0f, config_replaygain_non_rg_gain.GetFloat() / 20.0f);
+ }
+
+ for (int i=0;i<256;i++)
+ {
+ //int lookup=2*i;
+ float sinT = wavetrum[2*i];
+ float cosT = wavetrum[2*i+1];
+ wavetrum[i] = sqrt(sinT*sinT+cosT*cosT)*spec_scale;
+ }
+
+ float next = WARP(0)+1 ;
+ for (int x = 0; x < 75; x ++)
+ {
+ //float prev = 1.+(pow(2.,(float)x/12.) -1.) * bla;
+ float binF = next;
+ next = WARP(x+1) +1;
+
+ float thisValue = 0;
+ int bin = lrint(floor(binF));
+ int end = lrint(floor(next));
+ end = min(end, 255);
+ float mult = ((float)(bin+1))-binF;
+ bool herm=true;
+ do
+ {
+ if (bin == end)
+ {
+ mult = (next-binF);
+ herm=true;
+ }
+
+ if (herm)
+ {
+ float C=0, D=0;
+ if (bin<255)
+ {
+ C=wavetrum[bin+1];
+ if (bin<254)
+ D=wavetrum[bin+2];
+ }
+
+ //float samples[4] = { wavetrum[lookupA], wavetrum[lookupB], wavetrum[lookupC], wavetrum[lookupD] };
+ //thisValue += hermite(binF-bin, samples) * mult;
+ thisValue += hermite(binF-bin, wavetrum[bin-1], wavetrum[bin], C, D) * mult;
+ }
+ else
+ {
+ thisValue += wavetrum[bin];
+ }
+
+ herm=false;
+ bin++;
+ binF=(float)bin;
+ }
+ while (bin <= end);
+
+ tempdata[x]=lrint(fastmin(thisValue, 255.f));
+ }
+
+}
+
+////////////////////////////////
+
+SABuffer saBuffer;
+
+void sa_addpcmdata(void *_data_buf, int numChannels, int numBits, int ts)
+{
+ char *data_buf = reinterpret_cast<char *>(_data_buf);
+ char tempdata[75*2] = {0};
+ __declspec(align(16)) float wavetrum[512];
+ //extern int sa_curmode;
+ int vis_Csa=sa_override ? 3 : sa_curmode;
+
+ switch (vis_Csa)
+ {
+ case 4:
+ tempdata[0] = 0;
+ tempdata[1] = 0;
+ sa_add(tempdata,ts,4);
+ return;
+ case 2:
+ makeOscData(tempdata,data_buf,576,numChannels, numBits);
+ sa_add(tempdata,ts,2);
+ return ;
+ case 3:
+ makeOscData(tempdata+75,data_buf,576,numChannels, numBits);
+ // fall through!
+ case 1:
+ calcVuData((unsigned char*)tempdata, data_buf, numChannels, numBits);
+ vu_add(tempdata, ts);
+ break;
+ }
+ bool done=false;
+ size_t samples=576;
+ while (samples)
+ {
+ unsigned int copied = saBuffer.AddToBuffer(data_buf, numChannels, numBits, ts, (unsigned int) samples);
+ samples-=copied;
+ data_buf+=(copied*(numBits/8)*numChannels);
+ if (saBuffer.Full())
+ {
+ saBuffer.WindowToFFTBuffer(wavetrum);
+ if (!done)
+ {
+ if (vis_Csa == 3)
+ {
+ makeSpecData((unsigned char*)tempdata, wavetrum);
+ sa_add(tempdata, ts, 0x80000003);
+ }
+ else if (vis_Csa == 1)
+ {
+ makeSpecData((unsigned char*)tempdata, wavetrum);
+ sa_add(tempdata, ts, 1);
+ }
+ }
+ //done=true;
+ saBuffer.CopyHalf();
+ ts+=MulDiv(SABUFFER_WINDOW_INCREMENT,1000,_srate);
+ }
+ }
+}
diff --git a/Src/Winamp/cmdline.cpp b/Src/Winamp/cmdline.cpp
new file mode 100644
index 00000000..8cb71cfb
--- /dev/null
+++ b/Src/Winamp/cmdline.cpp
@@ -0,0 +1,1120 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author:
+** Created:
+**/
+
+#include "main.h"
+#include "resource.h"
+#include "strutil.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+#include "../nu/ns_wc.h"
+#include "api.h"
+#include "main.hpp"
+#include "MergePlaylist.h"
+
+static HWND find_otherwinamp_fast()
+{
+ wchar_t buf[MAX_PATH] = {0};
+ StringCchPrintfW(buf, MAX_PATH, L"%s_%x_CLASS", szAppName, APP_VERSION_NUM);
+ HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, FALSE, buf);
+ if (waitEvent)
+ {
+ HWND lhwnd = 0;
+ CloseHandle(waitEvent);
+ while (NULL != (lhwnd = FindWindowExW(NULL, lhwnd, szAppName, NULL)))
+ {
+ if (lhwnd != hMainWindow)
+ return lhwnd;
+ }
+ }
+ return NULL;
+}
+
+wchar_t *EatSpaces(wchar_t *cmdLine)
+{
+ while (cmdLine && *cmdLine && *cmdLine == L' ')
+ cmdLine = CharNextW(cmdLine);
+
+ return cmdLine;
+}
+
+static const wchar_t *EatSpaces(const wchar_t *cmdLine)
+{
+ while (cmdLine && *cmdLine && *cmdLine == L' ')
+ cmdLine = CharNextW(cmdLine);
+
+ return cmdLine;
+}
+
+wchar_t *FindNextCommand(wchar_t *cmdLine)
+{
+ int inQuotes = 0;
+ while (cmdLine && *cmdLine)
+ {
+ if (*cmdLine == L' ' && !inQuotes) // if we see a space (and we're not in quotes) then we're done
+ {
+ // we purposefully don't eat any extra space characters here
+ // that way we can null terminate the results of this function and get a clean string
+ break;
+ }
+ else if (*cmdLine == L'\"') // check for quotes
+ {
+ inQuotes = !inQuotes; // toggles quotes mode
+ }
+ cmdLine = CharNextW(cmdLine); // iterate the string
+ }
+ return cmdLine;
+}
+
+void GetParameter(const wchar_t *commandLine, wchar_t *yourBuffer, size_t yourBufferSize)
+{
+ int inQuotes = 0;
+
+ commandLine = EatSpaces(commandLine);
+
+ for(;;)
+ {
+ if (yourBufferSize == 1 // buffer is out
+ || *commandLine == 0 // out of stuff to copy
+ || (*commandLine == L' ' && !inQuotes)) // or we found a space
+ {
+ *yourBuffer = 0;
+ break;
+ }
+ else if (*commandLine == L'\"') // don't copy quotes
+ {
+ inQuotes = !inQuotes; // but do toggle the quote flag (so we can ignore spaces)
+ }
+ else // safe character to copy
+ {
+ *yourBuffer++ = *commandLine;
+ yourBufferSize--;
+ }
+ commandLine++;
+ }
+}
+
+bool IsCommand(const wchar_t *cmdline, const wchar_t *str, size_t size)
+{
+ if (!_wcsnicmp(cmdline, str, size) && (!cmdline[size] || cmdline[size] == L' '))
+ return true;
+ else
+ return false;
+}
+
+static void createPlayListDBFileName(wchar_t *filename)
+{
+ int x = 32;
+ for (;;)
+ {
+ GetTempFileNameW(M3UDIR, L"plf", GetTickCount() + x*5000, filename);
+ if (lstrlenW(filename) > 4)
+ {
+ PathRemoveExtensionW(filename);
+ PathAddExtensionW(filename, L".m3u8");
+ }
+ HANDLE h = CreateFileW(filename, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, 0, 0);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(h);
+ break;
+ }
+ if (++x > 4096)
+ {
+ break;
+ }
+ }
+}
+
+#if 0
+#ifdef BETA
+void ParseParametersExpired(wchar_t *lpszCmdParam)
+{
+ lpszCmdParam = EatSpaces(lpszCmdParam);
+ if (IsCommand(lpszCmdParam, L"/UNREG", 6))
+ {
+ char ext_list[8192] = {0};
+ char *a = ext_list;
+ void _r_s(char *name, char *data, int mlen);
+ CoInitialize(0);
+ setup_config();
+ Wasabi_Load();
+ w5s_init();
+
+ ext_list[0] = 0;
+ _r_s("config_extlist", ext_list, sizeof(ext_list));
+ while (a && *a)
+ {
+ char *p = strstr(a, ":");
+ if (p) *p++ = 0;
+ config_register(a, 0);
+ a = p;
+ }
+
+ wchar_t playlistExtensions[1024] = {0};
+ playlistManager->GetExtensionList(playlistExtensions, 1024);
+ wchar_t *p = playlistExtensions;
+ while (p && *p)
+ {
+ config_register(AutoChar(p), 0);
+ p += lstrlenW(p) + 1;
+ }
+
+ a = "wsz\0wpz\0wal\0wlz\0";
+ while (a && *a)
+ {
+ config_register(a, 0);
+ a += lstrlen(a) + 1;
+ }
+ config_regcdplayer(0);
+ if (config_isdircontext()) config_removedircontext();
+ config_registermediaplayer(0);
+ w5s_deinit(NULL);
+ Wasabi_Unload();
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
+ RemoveRegistrar();
+ ExitProcess(0);
+ }
+}
+#endif
+#endif
+
+void* LoadResource(HINSTANCE hinst, HINSTANCE owner, LPCTSTR lpType, LPCTSTR lpName, DWORD* size)
+{
+ HINSTANCE hmod = hinst;
+ HRSRC rsrc = FindResource(hmod, lpName, lpType);
+ if(!rsrc)
+ {
+ hmod = owner;
+ rsrc = FindResource(hmod, lpName, lpType);
+ }
+ if(rsrc)
+ {
+ HGLOBAL resourceHandle = LoadResource(hmod, rsrc);
+ if(size){*size = SizeofResource(hmod, rsrc);}
+ return LockResource(resourceHandle);
+ }
+ return 0;
+}
+
+static LRESULT WINAPI cmdLineProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ HICON hIcon = LoadIconW(hMainInstance, MAKEINTRESOURCE(ICON_XP));
+ SetClassLongPtrW(hwndDlg, GCLP_HICON, (LONG_PTR)hIcon);
+
+ char *b = NULL, *p = 0, *op = 0;
+ DWORD size = 0;
+ HGLOBAL hResource = LoadResource(hMainInstance, hMainInstance, TEXT("TEXT"), TEXT("CMDLINE"), &size);
+ p = (char*)hResource;
+ if (p && (op = strstr(p, "!!End"))) // if there's "!!End" in the resource, than copy everything before it
+ {
+ b = (char*)GlobalAlloc(GPTR, op-p+1);
+ memcpy(b, p, op-p);
+ b[op-p] = 0;
+ } else {
+ b = (char*)GlobalAlloc(GPTR, size+1);
+ if (b && p)
+ {
+ memcpy(b, p, size);
+ b[size] = 0;
+ }
+ }
+
+ SetDlgItemTextA(hwndDlg, IDC_CMDLINE, (b ? b : p)); // send it to the text control to display
+ if (b) GlobalFree(b);
+ SetFocus(GetDlgItem(hwndDlg, IDC_CMDLINE));
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+wchar_t *ParseParameters(wchar_t *lpszCmdParam, int *bAdd, int *bBookmark, int *bHandle, int *nCmdShow, int *bCommand, int *bCmdParam, int *bAllowCompat)
+{
+ for (;;)
+ {
+ lpszCmdParam = EatSpaces(lpszCmdParam);
+ if (IsCommand(lpszCmdParam, L"-embedding", 10))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 10);
+ }
+ else if (IsCommand(lpszCmdParam, L"/ALLOW_COMPAT_MODE", 18))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 18);
+ *bAllowCompat = 1;
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/SAFE=", 6))
+ {
+ wchar_t p[1024] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ GetParameter(lpszCmdParam, p, 1024);
+ int mode = _wtoi(p);
+
+ g_safeMode = (1 + (mode == 2));
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/SAFEALWAYS", 11))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 11);
+ g_safeMode = 3;
+ }
+ else if (IsCommand(lpszCmdParam, L"/?", 2))
+ {
+ DialogBoxW(hMainInstance, MAKEINTRESOURCEW(IDD_CMDLINE), 0, (DLGPROC)cmdLineProc);
+ ExitProcess(0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/NEW", 4))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 4);
+ bNoHwndOther = 1;
+ }
+ else if (IsCommand(lpszCmdParam, L"/HANDLE", 7))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 7);
+ *bHandle = 1;
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/REG=", 5))
+ {
+ wchar_t p[1024] = {0};
+ wchar_t *pItr = p;
+ lpszCmdParam = SkipXW(lpszCmdParam, 5);
+ GetParameter(lpszCmdParam, p, 1024);
+
+ is_install = 1;
+ while (pItr && *pItr)
+ {
+ // changed 5.64 - cope with upper + lowercase
+ // if the commands are done that way as well
+ switch (*pItr)
+ {
+ case L'A': case L'a': is_install |= 2; break; //2=audiotype
+ case L'V': case L'v': is_install |= 4; break; //4=videotype
+ case L'C': case L'c': is_install |= 8; break; //8=cd
+ case L'N': case L'n': is_install |= 16; break; //16=set needreg=1
+ case L'D': case L'd': is_install |= 32; break; //32=dircontextmenus
+ case L'L': case L'l': is_install |= 64; break; //64=playlisttype
+ case L'S': case L's': is_install |= 128; break; //128=setupwizard
+ }
+ pItr = CharNextW(pItr);
+ }
+ }
+ else if (IsCommand(lpszCmdParam, L"/NOREG", 6))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ g_noreg = 1;
+ }
+ else if (IsCommand(lpszCmdParam, L"/UNREG", 6))
+ {
+ wchar_t ext_list[16384] = {0};
+ wchar_t *a = ext_list;
+ void _r_sW(const char *name, wchar_t *data, int mlen);
+ CoInitialize(0);
+ setup_config();
+ Wasabi_Load();
+ w5s_init();
+
+ _r_sW("config_extlist", ext_list, ARRAYSIZE(ext_list));
+ while (a && *a)
+ {
+ wchar_t *p = wcsstr(a, L":");
+ if (p) *p++ = 0;
+ config_register(a, 0);
+ a = p;
+ }
+
+ wchar_t playlistExtensions[1024] = {0};
+ playlistManager->GetExtensionList(playlistExtensions, 1024);
+ wchar_t *p = playlistExtensions;
+ while (p && *p)
+ {
+ config_register(p, 0);
+ p += lstrlenW(p) + 1;
+ }
+
+ a = L"wsz\0wpz\0wal\0wlz\0";
+ while (a && *a)
+ {
+ config_register(a, 0);
+ a += lstrlenW(a) + 1;
+ }
+ config_regcdplayer(0, 0);
+ if (config_isdircontext()) config_removedircontext(0);
+ config_registermediaplayer(0);
+ w5s_deinit();
+ Wasabi_Unload();
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
+ RemoveRegistrar();
+ ExitProcess(0);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/ADD", 4) && (!lpszCmdParam[4] || lpszCmdParam[4] == L' '))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 4);
+ *bAdd = 1;
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/ADDPLAYLIST", 12) && (!lpszCmdParam[12] || lpszCmdParam[12] == L' '))
+ {
+ // winamp.exe /ADDPLAYLIST playlist.m3u "Playlist Name" {GUID}
+ lpszCmdParam = SkipXW(lpszCmdParam, 12);
+ setup_config();
+ Wasabi_Load();
+ w5s_init();
+ if (AGAVE_API_PLAYLISTS)
+ {
+ config_read(1);
+ wchar_t playlist_filename[MAX_PATH] = {0};
+ wchar_t playlist_guid_str[256] = {0};
+ GUID playlist_guid = INVALID_GUID;
+ GetParameter(lpszCmdParam, playlist_filename, MAX_PATH);
+ if (playlist_filename[0])
+ {
+ wchar_t playlist_name[256] = {0};
+ lpszCmdParam = EatSpaces(lpszCmdParam);
+ lpszCmdParam = FindNextCommand(lpszCmdParam);
+ GetParameter(lpszCmdParam, playlist_name, 256);
+
+ lpszCmdParam = EatSpaces(lpszCmdParam);
+ lpszCmdParam = FindNextCommand(lpszCmdParam);
+ GetParameter(lpszCmdParam, playlist_guid_str, 256);
+
+ if (playlist_name[0] == 0)
+ StringCchCopyW(playlist_name, 256, PathFindFileNameW(playlist_filename));
+ if (playlist_guid_str[0] != 0)
+ {
+ int skip = playlist_guid_str[0] == L'{';
+ playlist_guid_str[37]=0;
+ UuidFromStringW((RPC_WSTR)(&playlist_guid_str[skip]), (UUID *)&playlist_guid);
+ }
+
+ AGAVE_API_PLAYLISTS->AddPlaylist(playlist_filename, playlist_name, playlist_guid);
+ AGAVE_API_PLAYLISTS->Flush();
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(0);
+ }
+ }
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(1);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/CREATEPLAYLIST", 15) && (!lpszCmdParam[15] || lpszCmdParam[15] == L' '))
+ {
+ // winamp.exe /CREATEPLAYLIST "Playlist Name" {GUID}
+ lpszCmdParam = SkipXW(lpszCmdParam, 15);
+ setup_config();
+ Wasabi_Load();
+ w5s_init();
+ if (AGAVE_API_PLAYLISTS)
+ {
+ config_read(1);
+ wchar_t playlist_name[256] = {0};
+ wchar_t playlist_guid_str[256] = {0};
+ GUID playlist_guid = INVALID_GUID;
+ GetParameter(lpszCmdParam, playlist_name, 256);
+ if (playlist_name[0])
+ {
+ lpszCmdParam = EatSpaces(lpszCmdParam);
+ lpszCmdParam = FindNextCommand(lpszCmdParam);
+ GetParameter(lpszCmdParam, playlist_guid_str, 256);
+
+ if (playlist_guid_str[0] != 0)
+ {
+ int skip = playlist_guid_str[0] == L'{';
+ playlist_guid_str[37]=0;
+ UuidFromStringW((RPC_WSTR)(&playlist_guid_str[skip]), (UUID *)&playlist_guid);
+ }
+ if (playlist_guid != INVALID_GUID)
+ {
+ size_t existing_playlist_index;
+ // check for duplicate GUID
+ if (AGAVE_API_PLAYLISTS->GetPosition(playlist_guid, &existing_playlist_index) != API_PLAYLISTS_SUCCESS)
+ {
+ wchar_t playlist_filename[MAX_PATH] = {0};
+ createPlayListDBFileName(playlist_filename); // generate filename
+ AGAVE_API_PLAYLISTS->AddPlaylist(playlist_filename, playlist_name, playlist_guid);
+ AGAVE_API_PLAYLISTS->Flush();
+ }
+ }
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(0);
+ }
+ }
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(1);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/APPENDPLAYLIST", 15) && (!lpszCmdParam[15] || lpszCmdParam[15] == L' '))
+ {
+ // winamp.exe /APPENDPLAYLIST {GUID} filename.mp3
+ lpszCmdParam = SkipXW(lpszCmdParam, 15);
+ setup_config();
+ Wasabi_Load();
+ w5s_init();
+ if (AGAVE_API_PLAYLISTS && AGAVE_API_PLAYLISTMANAGER)
+ {
+ config_read(1);
+ wchar_t playlist_guid_str[256] = {0};
+ GUID playlist_guid = INVALID_GUID;
+ GetParameter(lpszCmdParam, playlist_guid_str, 256);
+ if (playlist_guid_str[0])
+ {
+ wchar_t filename[MAX_PATH] = {0};
+ const wchar_t *playlist_filename;
+ lpszCmdParam = EatSpaces(lpszCmdParam);
+ lpszCmdParam = FindNextCommand(lpszCmdParam);
+ GetParameter(lpszCmdParam, filename, MAX_PATH);
+
+ int skip = playlist_guid_str[0] == L'{';
+ playlist_guid_str[37]=0;
+ UuidFromStringW((RPC_WSTR)(&playlist_guid_str[skip]), (UUID *)&playlist_guid);
+
+ MergePlaylist merged_playlist;
+
+ size_t playlist_index;
+ // get playlist filename from AGAVE_API_PLAYLISTS
+ if (AGAVE_API_PLAYLISTS->GetPosition(playlist_guid, &playlist_index) == API_PLAYLISTS_SUCCESS
+ && (NULL != (playlist_filename = AGAVE_API_PLAYLISTS->GetFilename(playlist_index))))
+ {
+ // load playlist into merge_playlist
+ if (AGAVE_API_PLAYLISTMANAGER->Load(playlist_filename, &merged_playlist) == PLAYLISTMANAGER_SUCCESS)
+ {
+ MergePlaylist appended_playlist;
+ // if filename is a playlist, load it
+ if (AGAVE_API_PLAYLISTMANAGER->Load(filename, &appended_playlist) == PLAYLISTMANAGER_SUCCESS)
+ {
+ merged_playlist.AppendPlaylist(appended_playlist);
+ }
+ else if (PathIsDirectoryW(filename))
+ { // if it's a directory
+ AGAVE_API_PLAYLISTMANAGER->LoadDirectory(filename, &appended_playlist, 0);
+ merged_playlist.AppendPlaylist(appended_playlist);
+ }
+ else
+ {
+ // TODO: get metadata, but we don't have any plugins loaded
+ if (!merged_playlist.HasFilename(filename))
+ merged_playlist.AppendWithInfo(filename, 0, -1);
+ }
+ if (AGAVE_API_PLAYLISTMANAGER->Save(playlist_filename, &merged_playlist) == PLAYLISTMANAGER_SUCCESS)
+ {
+ size_t num_items = merged_playlist.GetNumItems();
+ AGAVE_API_PLAYLISTS->SetInfo(playlist_index, api_playlists_itemCount, &num_items, sizeof(num_items));
+ uint64_t total_time = merged_playlist.total_time/1000ULL;
+ AGAVE_API_PLAYLISTS->SetInfo(playlist_index, api_playlists_totalTime, &total_time, sizeof(total_time));
+ AGAVE_API_PLAYLISTS->Flush();
+ }
+ }
+ }
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(0);
+ }
+ }
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(1);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/ENUMPLAYLISTS", 14))
+ {
+ setup_config();
+ Wasabi_Load();
+ w5s_init();
+ if (AGAVE_API_PLAYLISTS)
+ {
+ size_t count = AGAVE_API_PLAYLISTS->GetCount();
+ if (count > 0)
+ {
+ for (size_t index = 0; index < count; index++)
+ {
+ GUID guid = AGAVE_API_PLAYLISTS->GetGUID(index);
+ fprintf(stdout, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X},%s,%s\n",
+ (int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
+ (int)guid.Data4[0], (int)guid.Data4[1], (int)guid.Data4[2],
+ (int)guid.Data4[3], (int)guid.Data4[4], (int)guid.Data4[5],
+ (int)guid.Data4[6], (int)guid.Data4[7],
+ (char*)(AutoChar(AGAVE_API_PLAYLISTS->GetFilename(index), CP_UTF8)),
+ (char*)(AutoChar(AGAVE_API_PLAYLISTS->GetName(index), CP_UTF8)));
+ }
+ fflush(stdout);
+ }
+
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(0);
+ }
+ w5s_deinit();
+ Wasabi_Unload();
+ ExitProcess(1);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/BOOKMARK", 9) && (!lpszCmdParam[9] || lpszCmdParam[9] == L' '))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 9);
+ *bBookmark = 1;
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/CONFIG=", 8))
+ {
+ wchar_t p[1024] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ GetParameter(lpszCmdParam, p, 1024);
+ config_setinifile(p);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/INIDIR=", 8))
+ {
+ wchar_t p[1024] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ GetParameter(lpszCmdParam, p, 1024);
+ config_setinidir(p);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/M3UDIR=", 8))
+ {
+ wchar_t p[1024] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ GetParameter(lpszCmdParam, p, 1024);
+ config_setm3udir(p);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/CLASS=", 7))
+ {
+ wchar_t p[1024] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 7);
+ GetParameter(lpszCmdParam, p, 1024);
+ StringCchCopyW(szAppName, 64, p);
+ }
+ else if (IsCommand(lpszCmdParam, L"/DELM3U", 7))
+ {
+ setup_config();
+ DeleteFileW(M3U_FILE);
+ DeleteFileW(OLD_M3U_FILE);
+ RemoveRegistrar();
+ ExitProcess(0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/QUIT", 5) ||
+ IsCommand(lpszCmdParam, L"/EXIT", 5) ||
+ IsCommand(lpszCmdParam, L"/CLOSE", 6))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 5 + IsCommand(lpszCmdParam, L"/CLOSE", 6));
+ HWND hwnd_other_winamp = find_otherwinamp_fast();
+ if (IsWindow(hwnd_other_winamp))
+ PostMessageW(hwnd_other_winamp, WM_CLOSE, 0, 0);
+ ExitProcess(0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/KILL", 5))
+ {
+ HWND hwnd_other_winamp;
+ DWORD other_winamp_procId = 0;
+ lpszCmdParam = SkipXW(lpszCmdParam, 5);
+ hwnd_other_winamp = find_otherwinamp_fast();
+ if (hwnd_other_winamp)
+ {
+ PostMessageW(hwnd_other_winamp, WM_CLOSE, 0, 0);
+
+ GetWindowThreadProcessId(hwnd_other_winamp, &other_winamp_procId); // get the process ID
+ if (other_winamp_procId) // if we didn't get one, it probably already handled the WM_CLOSE message ...
+ {
+ HANDLE other_winamp_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE | SYNCHRONIZE, FALSE, other_winamp_procId);
+ if (other_winamp_process) // if we got a process handle (it might have quit already in the meantime ...)
+ {
+ if (WaitForSingleObject(other_winamp_process, 3000) == WAIT_TIMEOUT) // wait 5 seconds for it to close
+ {
+ DWORD exitCode = 0;
+ TerminateProcess(other_winamp_process, exitCode); // terminate if we timed out
+ WaitForSingleObject(other_winamp_process, 1000); // wait some more because TerminateProcess() returns immediately
+ }
+ CloseHandle(other_winamp_process); // release our reference to the handle
+ }
+ }
+ }
+ RemoveRegistrar();
+ ExitProcess(0);
+ }
+ /*else if (!_wcsnicmp(lpszCmdParam, L"/RETURN=", 8))
+ {
+ wchar_t p[40] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ GetParameter(lpszCmdParam, p, 40);
+ ExitProcess(_wtoi(p));
+ }*/
+#ifndef _WIN64
+#ifdef BURN_SUPPORT
+ else if (!_wcsnicmp(lpszCmdParam, L"/BURN=", 6))
+ {
+ wchar_t p[1024] = {0};
+ unsigned int retCode;
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ GetParameter(lpszCmdParam, p, 1024);
+ CoInitialize(0);
+ setup_config();
+ Wasabi_Load();
+ SpectralAnalyzer_Create();
+ w5s_init(NULL);
+ in_init(NULL);
+ config_read(1);
+ retCode = burn_doBurn(AutoChar(p), hMainWindow, hMainInstance);
+ in_deinit(NULL);
+ w5s_deinit(NULL);
+ Wasabi_Unload();
+ SpectralAnalyzer_Destroy();
+ RemoveRegistrar();
+ ExitProcess(retCode);
+ }
+#endif
+#endif
+ /*else if (!_wcsnicmp(lpszCmdParam, L"/WATCHER", 8))
+ {
+ wchar_t p[2048] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 9);
+ GetParameter(lpszCmdParam, p, 2048);
+ // eat parameter for now...
+ RemoveRegistrar();
+ ExitProcess(0); // and do not do anything...
+ }*/
+ else if (IsCommand(lpszCmdParam, L"/STARTMIN", 9))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 10);
+ *nCmdShow = SW_MINIMIZE;
+ }
+ else if (IsCommand(lpszCmdParam, L"/STARTMAX", 9))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 10);
+ *nCmdShow = SW_RESTORE;
+ }
+ else if (IsCommand(lpszCmdParam, L"/PREV", 5))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON1, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/PLAY", 5))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON2, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/PAUSE", 6))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 7);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON3, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/STOP", 5))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON4, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/STOPFADE", 9))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 10);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON4_SHIFT, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/STOPAFTER", 10))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 11);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON4_CTRL, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/NEXT", 5))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON5, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/PLAYPAUSE", 10))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 10);
+ *bCommand = MAKEWPARAM(IPC_ISPLAYING, 2);
+ }
+ else if (IsCommand(lpszCmdParam, L"/FWD", 4))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 4);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON5_SHIFT, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/REV", 4))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 4);
+ *bCommand = MAKEWPARAM(WINAMP_BUTTON1_SHIFT, 0);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/CD", 3)) // CD<[0]-3>
+ {
+ wchar_t p[3] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 3);
+ GetParameter(lpszCmdParam, p, 3);
+
+ // only allow 4 drives so we limit to g_audiocdletters
+ int id = _wtoi(p);
+ if (id >= 0 && id < 4)
+ {
+ *bCommand = MAKEWPARAM(ID_MAIN_PLAY_AUDIOCD + id, 0);
+ }
+ else
+ ExitProcess(0);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/RANDOM=", 8))
+ {
+ wchar_t p[2] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ GetParameter(lpszCmdParam, p, 2);
+ if (p[0] == '0') *bCmdParam = 0;
+ else if (p[0] == '1') *bCmdParam = 1;
+ *bCommand = MAKEWPARAM(IPC_SET_SHUFFLE, 1);
+ }
+ else if (IsCommand(lpszCmdParam, L"/RANDOM", 7))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 7);
+ *bCommand = MAKEWPARAM(WINAMP_FILE_SHUFFLE, 0);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/SHUFFLE=", 9))
+ {
+ wchar_t p[2] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 9);
+ GetParameter(lpszCmdParam, p, 2);
+ if (p[0] == '0') *bCmdParam = 0;
+ else if (p[0] == '1') *bCmdParam = 1;
+ else break;
+ *bCommand = MAKEWPARAM(IPC_SET_SHUFFLE, 1);
+ }
+ else if (IsCommand(lpszCmdParam, L"/SHUFFLE", 8))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 9);
+ *bCommand = MAKEWPARAM(WINAMP_FILE_SHUFFLE, 0);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/REPEAT=", 8))
+ {
+ wchar_t p[2] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ GetParameter(lpszCmdParam, p, 2);
+ if (p[0] == '0') *bCmdParam = 0;
+ else if (p[0] == '1') *bCmdParam = 1;
+ else break;
+ *bCommand = MAKEWPARAM(IPC_SET_REPEAT, 1);
+ }
+ else if (IsCommand(lpszCmdParam, L"/REPEAT", 7))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 7);
+ *bCommand = MAKEWPARAM(WINAMP_FILE_REPEAT, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/PANLEFT", 8))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ *bCommand = MAKEWPARAM(EQ_PANLEFT, 2);
+ }
+ else if (IsCommand(lpszCmdParam, L"/PANRIGHT", 9))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 9);
+ *bCommand = MAKEWPARAM(EQ_PANRIGHT, 2);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/PAN=", 5))
+ {
+ wchar_t p[5] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 5);
+ GetParameter(lpszCmdParam, p, 5);
+ if (p[0])
+ {
+ *bCmdParam = _wtoi(p);
+ *bCommand = MAKEWPARAM(IPC_SETPANNING, 2);
+ }
+ else
+ ExitProcess(0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/VOLUP", 6))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 6);
+ *bCommand = MAKEWPARAM(WINAMP_VOLUMEUP, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/VOLDOWN", 8))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ *bCommand = MAKEWPARAM(WINAMP_VOLUMEDOWN, 0);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/VOL=", 5))
+ {
+ wchar_t p[4] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 5);
+ GetParameter(lpszCmdParam, p, 4);
+ if (p[0])
+ {
+ int vol = _wtoi(p);
+ if (vol < 0) vol = 0;
+ if (vol > 100) vol = 100;
+ *bCmdParam = ceil(vol * 2.55);
+ *bCommand = MAKEWPARAM(IPC_SETVOLUME, 1);
+ }
+ else
+ ExitProcess(0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/JUMPTO", 7))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 8);
+ *bCommand = MAKEWPARAM(WINAMP_JUMPFILE, 0);
+ }
+ else if (IsCommand(lpszCmdParam, L"/CLEAR", 6))
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 7);
+ *bCommand = MAKEWPARAM(IPC_DELETE, 1);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/COMMAND=", 9))
+ {
+ wchar_t p[16] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 9);
+ GetParameter(lpszCmdParam, p, 16);
+ int id = _wtoi(p);
+ if (id > 0 && id < 65536)
+ {
+ *bCommand = MAKEWPARAM(id, 0);
+ }
+ else
+ ExitProcess(0);
+ }
+ else if (!_wcsnicmp(lpszCmdParam, L"/WA_IPC", 7) && (!lpszCmdParam[7] || lpszCmdParam[7] == L' '))
+ {
+ wchar_t p[16] = {0};
+ lpszCmdParam = SkipXW(lpszCmdParam, 7);
+ GetParameter(lpszCmdParam, p, 16);
+
+ int id = _wtoi(p);
+ if (id > 0 && id <= 65536)
+ {
+ *bCommand = MAKEWPARAM(id, 1);
+
+ if (lpszCmdParam && *lpszCmdParam)
+ lpszCmdParam = CharNextW(lpszCmdParam);
+ while (lpszCmdParam && *lpszCmdParam)
+ {
+ if (*lpszCmdParam == L' ') break;
+ lpszCmdParam = CharNextW(lpszCmdParam);
+ }
+
+ wchar_t p2[16] = {0};
+ GetParameter(lpszCmdParam, p2, 16);
+ id = _wtoi(p2);
+ if (id >= 0 && id <= 65536)
+ {
+ *bCmdParam = id;
+
+ if (lpszCmdParam && *lpszCmdParam)
+ lpszCmdParam = CharNextW(lpszCmdParam);
+ while (lpszCmdParam && *lpszCmdParam)
+ {
+ if (*lpszCmdParam == L' ') break;
+ lpszCmdParam = CharNextW(lpszCmdParam);
+ }
+ }
+ else
+ ExitProcess(0);
+ }
+ else
+ ExitProcess(0);
+ }
+ else if (*lpszCmdParam == L'/') // ignore /options :)
+ {
+ lpszCmdParam = SkipXW(lpszCmdParam, 1);
+ }
+ else
+ break;
+
+ lpszCmdParam = FindNextCommand(lpszCmdParam);
+ }
+
+ return lpszCmdParam;
+}
+
+void parseCmdLine(wchar_t *cmdline, HWND hwnd)
+{
+ wchar_t buf[MAX_PATH*4] = {0};
+ wchar_t tmp[MAX_PATH] = {0};
+ wchar_t *p;
+ if (wcsstr(cmdline, L"/BOOKMARK") == cmdline)
+ {
+ wchar_t bookmark[1024] = {0};
+ cmdline = SkipXW(cmdline, 9);
+ GetParameter(cmdline, bookmark, 1024);
+
+ COPYDATASTRUCT cds;
+ cds.dwData = IPC_ADDBOOKMARKW;
+ cds.lpData = (void *) bookmark;
+ cds.cbData = sizeof(wchar_t)*(lstrlenW((wchar_t*) cds.lpData) + 1);
+ SendMessageW(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
+ return ;
+ }
+ else if (wcsstr(cmdline, L"/HANDLE") == cmdline)
+ {
+ wchar_t uri[1024] = {0};
+ cmdline = SkipXW(cmdline, 7);
+ GetParameter(cmdline, uri, 1024);
+ COPYDATASTRUCT cds;
+ cds.dwData = IPC_HANDLE_URI;
+ cds.lpData = (void *) uri;
+ cds.cbData = sizeof(wchar_t)*(lstrlenW((wchar_t*) cds.lpData) + 1);
+ SendMessageW(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
+ return ;
+ }
+ lstrcpynW(buf, cmdline, MAX_PATH*4);
+ p = buf;
+
+ wchar_t param[1024] = {0};
+ while (p && *p)
+ {
+ p = EatSpaces(p);
+
+ GetParameter(p, param, 1024);
+ if (!hwnd)
+ {
+ PlayList_appendthing(param, 0, 0);
+ }
+ else
+ {
+ COPYDATASTRUCT cds;
+ wchar_t *p2 = 0;
+ if (!PathIsURLW(param) && GetFullPathNameW(param, MAX_PATH, tmp, &p2) && tmp[0])
+ {
+ cds.dwData = IPC_PLAYFILEW;
+ cds.lpData = (void *) tmp;
+ cds.cbData = sizeof(wchar_t)*(lstrlenW((wchar_t *) cds.lpData) + 1);
+ SendMessageW(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
+ }
+ else
+ {
+ cds.dwData = IPC_PLAYFILEW;
+ cds.lpData = (void *) param;
+ cds.cbData = sizeof(wchar_t) * (lstrlenW((wchar_t *) cds.lpData) + 1);
+ SendMessageW(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
+ }
+ }
+ p = FindNextCommand(p);
+ }
+} // parseCmdLine()
+
+wchar_t *CheckFileBase(wchar_t *lpszCmdParam, HWND hwnd_other, int *exit, int mode)
+{
+ wchar_t buf[32] = {0};
+ *exit=0;
+ lstrcpynW(buf, extensionW(lpszCmdParam), 32);
+ if (wcsstr(buf, L"\"")) wcsstr(buf, L"\"")[0] = 0;
+
+ // process .wsz/.wal file or .wlz (depending on the mode enabled)
+ if ((!mode && (!_wcsicmp(buf, L"wsz") || !_wcsicmp(buf, L"wal"))) || (mode && !_wcsicmp(buf, L"wlz")))
+ {
+ wchar_t *p = lpszCmdParam, buf[MAX_PATH] = {0}, buf2[MAX_PATH] = {0},
+ outname[MAX_PATH] = {0}, current[MAX_PATH] = {0};
+
+ while (p &&*p == L' ') p++;
+ if (p && *p == L'\"') { p++; if (wcsstr(p, L"\"")) wcsstr(p, L"\"")[0] = 0; }
+
+ // this is roughly equivalent to PathUndecorate, which we can't use because it requires IE 5.0+
+ StringCchCopyW(outname, MAX_PATH, PathFindFileNameW(p));
+ StringCchCopyW(buf, MAX_PATH, (!mode ? SKINDIR : LANGDIR));
+ PathCombineW(buf2, buf, outname);
+
+ void _r_sW(const char *name, wchar_t *data, int mlen);
+ _r_sW((!mode ? "skin" : "langpack"), current, MAX_PATH);
+
+ bool name_match = !_wcsicmp(outname, current);
+ bool file_match = !_wcsicmp(p, buf2);
+ //if (_wcsicmp(outname, current))
+ if (!name_match || name_match && !file_match)
+ {
+ // prompt if the user is ok to install (subject to user preferences)
+ int ret = IDYES;
+ if (!mode ? config_skin_prompt : config_wlz_prompt)
+ {
+ ret = LPMessageBox(NULL, (!mode ? IDS_SKINS_INSTALL_PROMPT : IDS_LANG_INSTALL_PROMPT),
+ (!mode ? IDS_SKINS_INSTALL_HEADER :IDS_LANG_INSTALL_HEADER),
+ MB_YESNO | MB_ICONQUESTION);
+ }
+
+ if (ret != IDYES)
+ {
+ *exit = 1;
+ return lpszCmdParam;
+ }
+ else
+ {
+ if(*exit == -2)
+ {
+ *exit = -1;
+ }
+ }
+
+ {
+ wchar_t *tmp;
+ tmp = outname + lstrlenW(outname);
+ size_t tmpsize = MAX_PATH - (tmp - outname);
+ while (tmp >= outname && *tmp != L'[') tmp--;
+ if(!mode)
+ {
+ if (tmp >= outname && tmp[1] && !_wcsicmp(tmp + 2, L"].wsz"))
+ StringCchCopyW(tmp, tmpsize, L".wsz");
+ if (tmp >= outname && tmp[1] && !_wcsicmp(tmp + 2, L"].wal"))
+ StringCchCopyW(tmp, tmpsize, L".wal");
+ }
+ else
+ {
+ if (tmp >= outname && tmp[1] && !_wcsicmp(tmp + 2, L"].wlz"))
+ StringCchCopyW(tmp, tmpsize, L".wlz");
+ }
+ }
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ if (FAILED(registrar->InstallItem(p, buf, outname)))
+ {
+ wchar_t buffer[MAX_PATH*3] = {0};
+ StringCchPrintfW(buffer,sizeof(buffer),getStringW((!mode?IDS_SKINS_INSTALL_ERROR:IDS_LANG_INSTALL_ERROR),NULL,0),outname,p,buf);
+ MessageBoxW(NULL, buffer, getStringW(!mode?IDS_SKINS_INSTALL_HEADER:IDS_LANG_INSTALL_HEADER,NULL,0), MB_OK | MB_ICONEXCLAMATION);
+ }
+ registrar->Release();
+ }
+ }
+
+ if (hwnd_other)
+ {
+ if(!mode)
+ {
+ _w_sW("skin", outname);
+ COPYDATASTRUCT cds;
+ cds.dwData = IPC_SETSKINW;
+ cds.lpData = (void *) outname;
+ cds.cbData = sizeof(wchar_t)*(lstrlenW(outname) + 1);
+ SendMessageW(hwnd_other, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
+ ShowWindow(hwnd_other, SW_RESTORE);
+ SetForegroundWindow(hwnd_other);
+ }
+ else
+ {
+ // since we can't reliably unload resources on the fly, force a restart
+ _w_sW("langpack", outname);
+ PostMessageW(hwnd_other,WM_USER,0,IPC_RESTARTWINAMP);
+ }
+ *exit=1;
+ }
+ else
+ {
+ if(!mode)
+ {
+ g_skinloadedmanually = 1;
+ _w_sW("skin", outname);
+ }
+ else
+ {
+ _w_sW("langpack", outname);
+ }
+ }
+ lpszCmdParam = L"";
+ }
+
+ return lpszCmdParam;
+} \ No newline at end of file
diff --git a/Src/Winamp/commandLink.cpp b/Src/Winamp/commandLink.cpp
new file mode 100644
index 00000000..69f18189
--- /dev/null
+++ b/Src/Winamp/commandLink.cpp
@@ -0,0 +1,698 @@
+#include "main.h"
+#include "./commandLink.h"
+#include "./api.h"
+//#include "./guiObjects.h"
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <commctrl.h>
+#include <strsafe.h>
+
+#ifndef LONGX86
+#ifdef _WIN64
+ #define LONGX86 LONG_PTR
+#else /*_WIN64*/
+ #define LONGX86 LONG
+#endif /*_WIN64*/
+#endif // LONGX86
+
+
+#define MARGIN_LEFT 2
+#define MARGIN_TOP 0
+#define MARGIN_RIGHT 2
+#define MARGIN_BOTTOM 1
+
+typedef struct __COMMANDLINK
+{
+ COLORREF rgbBk;
+ COLORREF rgbText;
+ COLORREF rgbTextVisited;
+ COLORREF rgbTextHighlight;
+ HCURSOR cursorHot;
+ HFONT textFont;
+ UINT state;
+ RECT margins;
+} COMMANDLINK;
+
+#define GetCommandLink(__hwnd) ((COMMANDLINK*)(LONG_PTR)(LONGX86)GetWindowLongPtrW((__hwnd), 0))
+
+static LRESULT CALLBACK CommandLink_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+EXTERN_C BOOL CommandLink_RegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASSEXW wc;
+ ATOM klassAtom;
+
+ if (GetClassInfoExW(hInstance, NWC_COMMANDLINKW, &wc))
+ return TRUE;
+
+ ZeroMemory(&wc, sizeof(WNDCLASSEXW));
+
+ wc.cbSize = sizeof(WNDCLASSEXW);
+ wc.hInstance = hInstance;
+ wc.lpszClassName = NWC_COMMANDLINKW;
+ wc.lpfnWndProc = CommandLink_WindowProc;
+ wc.style = CS_GLOBALCLASS;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.cbWndExtra = sizeof(COMMANDLINK*);
+
+ klassAtom = RegisterClassExW(&wc);
+ if (0 == klassAtom)
+ return FALSE;
+
+ if (NULL != WASABI_API_APP)
+ WASABI_API_APP->DirectMouseWheel_RegisterSkipClass(klassAtom);
+
+ return TRUE;
+}
+
+
+static COLORREF CommandLink_BlendColors(COLORREF rgbTop, COLORREF rgbBottom, INT alpha)
+{
+ if (alpha > 254) return rgbTop;
+ if (alpha < 0) return rgbBottom;
+
+ INT k = (((255 - alpha)*255 + 127)/255);
+
+ return RGB( (GetRValue(rgbTop)*alpha + k*GetRValue(rgbBottom) + 127)/255,
+ (GetGValue(rgbTop)*alpha + k*GetGValue(rgbBottom) + 127)/255,
+ (GetBValue(rgbTop)*alpha + k*GetBValue(rgbBottom) + 127)/255);
+}
+
+static HBRUSH CommandLink_GetPaintColors(HWND hwnd, HDC hdc, COLORREF *rgbBkOut, COLORREF *rgbFgOut)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return NULL;
+
+ COLORREF rgbBk, rgbFg;
+ UINT windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ BOOL defaultColors = (0 != (CLS_DEFAULTCOLORS & windowStyle));
+
+ rgbBk = (defaultColors) ? GetSysColor(COLOR_3DFACE) : link->rgbBk;
+ if (NULL != rgbBkOut) *rgbBkOut = rgbBk;
+
+ if (0 != (WS_DISABLED & windowStyle))
+ rgbFg = GetSysColor(COLOR_GRAYTEXT);
+ else
+ {
+ if (0 != (CLIS_VISITED & link->state))
+ rgbFg = (defaultColors) ? RGB(85, 26, 139) : link->rgbTextVisited;
+ else
+ rgbFg = (defaultColors) ? GetSysColor(COLOR_HOTLIGHT) : link->rgbText;
+
+ if (0 != ((CLIS_HOT | CLIS_PRESSED) & link->state))
+ {
+ if (0 == (CLS_HIGHLIGHTCOLOR & windowStyle))
+ rgbFg = CommandLink_BlendColors(rgbFg, rgbBk, 160);
+ else
+ rgbFg = link->rgbTextHighlight;
+ }
+ }
+
+ if (NULL != rgbFgOut)
+ *rgbFgOut = rgbFg;
+
+
+ HBRUSH backBrush = NULL;
+ if (FALSE != defaultColors)
+ {
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent)
+ {
+ COLORREF backBk = SetBkColor(hdc, rgbBk);
+ COLORREF backFg = SetBkColor(hdc, rgbFg);
+ backBrush = (HBRUSH)SendMessageW(hParent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd);
+ rgbBk = SetBkColor(hdc, backBk);
+ SetBkColor(hdc, backFg);
+ }
+ }
+ return backBrush;
+}
+
+static BOOL CommandLink_GetTextRect(HDC hdc, LPCWSTR pszText, INT cchText, const RECT *prcClient, RECT *prcTextOut, const RECT *margins)
+{
+ if (NULL == prcClient || NULL == prcTextOut)
+ return FALSE;
+
+ SIZE textSize;
+ if (0 == cchText || !GetTextExtentPoint32W(hdc, pszText, cchText, &textSize))
+ return SetRectEmpty(prcTextOut);
+
+ prcTextOut->left = ((prcClient->right - prcClient->left) - textSize.cx) / 2;
+ if (prcTextOut->left < (prcClient->left + margins->left))
+ prcTextOut->left = prcClient->left + margins->left;
+
+ prcTextOut->top = ((prcClient->bottom - prcClient->top) - textSize.cy) / 2;
+ if (prcTextOut->top < (prcClient->top + margins->top))
+ prcTextOut->top = prcClient->top + margins->top;
+
+ prcTextOut->right = prcTextOut->left + textSize.cx;
+ if (prcTextOut->right > (prcClient->right - margins->right))
+ prcTextOut->right = prcClient->right - margins->right;
+
+ prcTextOut->bottom = prcTextOut->top + textSize.cy;
+ if (prcTextOut->bottom > (prcClient->bottom - margins->bottom))
+ prcTextOut->bottom = prcClient->bottom - margins->bottom;
+
+ return TRUE;
+}
+
+static BOOL CommandLink_GetIdealSizeReal(HWND hwnd, SIZE *sizeOut)
+{
+ if (NULL == sizeOut)
+ return FALSE;
+
+ ZeroMemory(sizeOut, sizeof(SIZE));
+
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return FALSE;
+
+ WCHAR szText[256] = {0};
+ INT cchText = GetWindowTextW(hwnd, szText, ARRAYSIZE(szText));
+
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS);
+ if (NULL == hdc) return FALSE;
+
+ HFONT originalFont = (HFONT)SelectObject(hdc, link->textFont);
+ BOOL resultOk;
+
+ if (0 == cchText)
+ {
+ TEXTMETRICW tm;
+ resultOk = GetTextMetricsW(hdc, &tm);
+ if (resultOk) sizeOut->cy = tm.tmHeight;
+ }
+ else
+ resultOk = GetTextExtentPoint32W(hdc, szText, cchText, sizeOut);
+
+ if (originalFont != link->textFont) SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+
+ if (resultOk)
+ {
+ sizeOut->cx += (link->margins.left + link->margins.right);
+ sizeOut->cy += (link->margins.top + link->margins.bottom);
+ }
+ return resultOk;
+}
+
+static BOOL CommandLink_SetStateEx(HWND hwnd, UINT newState, UINT stateMask, BOOL fRedraw)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return FALSE;
+
+ UINT oldState = link->state;
+ link->state = (link->state & ~stateMask) | (newState & stateMask);
+
+ if (oldState != link->state && fRedraw)
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ return TRUE;
+}
+
+static void CommandLink_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return;
+
+ RECT clientRect, partRect;
+ if (!GetClientRect(hwnd, &clientRect)) return;
+
+ DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+
+ COLORREF rgbBk, rgbFg;
+ HBRUSH backBrush = CommandLink_GetPaintColors(hwnd, hdc, &rgbBk, &rgbFg);
+
+ COLORREF originalBk = SetBkColor(hdc, rgbBk);
+ COLORREF originalFg = SetTextColor(hdc, rgbFg);
+
+ HFONT originalFont = (HFONT)SelectObject(hdc, link->textFont);
+
+ WCHAR szText[256] = {0};
+ INT cchText = GetWindowTextW(hwnd, szText, ARRAYSIZE(szText));
+
+ RECT textRect;
+ CommandLink_GetTextRect(hdc, szText, cchText, &clientRect, &textRect, &link->margins);
+
+ if (fErase)
+ {
+ if(NULL != backBrush)
+ {
+ FillRect(hdc, prcPaint, backBrush);
+ }
+ else
+ {
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prcPaint, NULL, 0, NULL);
+ }
+ }
+
+ if (0 != ((CLIS_HOT | CLIS_PRESSED) & link->state) ||
+ 0 != (CLS_ALWAYSUNDERLINE & windowStyle))
+ {
+ TEXTMETRIC tm;
+ if (GetTextMetrics(hdc, &tm))
+ {
+ CopyRect(&partRect, &textRect);
+ partRect.top = partRect.top + tm.tmAscent + 1;
+ partRect.bottom = partRect.top + 1;
+
+ COLORREF originalColor = SetBkColor(hdc, rgbFg);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &partRect, NULL, 0, NULL);
+ if (originalColor != rgbFg) SetBkColor(hdc, originalColor);
+ }
+ }
+
+ if (0 != cchText)
+ {
+ INT originalMode = SetBkMode(hdc, TRANSPARENT);
+ UINT originalAlign = SetTextAlign(hdc, TA_LEFT | TA_TOP);
+ ExtTextOutW(hdc, textRect.left, textRect.top, ETO_CLIPPED, &textRect, szText, cchText, NULL);
+ if (TRANSPARENT != originalMode) SetBkMode(hdc, originalMode);
+ if ((TA_LEFT | TA_TOP) != originalAlign) SetTextAlign(hdc, originalAlign);
+ }
+
+ if (CLIS_FOCUSED == ((CLIS_FOCUSED | CLIS_HIDEFOCUS) & link->state))
+ {
+ SetBkColor(hdc, 0x00FFFFFF);
+ SetTextColor(hdc, 0x000000000);
+ DrawFocusRect(hdc, &clientRect);
+ }
+
+ SelectObject(hdc, originalFont);
+ if (originalBk != rgbBk) SetBkColor(hdc, originalBk);
+ if (originalFg != rgbFg) SetTextColor(hdc, originalFg);
+
+}
+
+static void CommandLink_NotifyParent(HWND hwnd, UINT notificationId)
+{
+ NMHDR nmhdr;
+ nmhdr.code = notificationId;
+ nmhdr.hwndFrom = hwnd;
+ nmhdr.idFrom = GetDlgCtrlID(hwnd);
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent)
+ {
+ SendMessageW(hParent, WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
+ }
+}
+
+static void CommandLink_Click(HWND hwnd)
+{
+ CommandLink_NotifyParent(hwnd, NM_CLICK);
+
+ DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ if (0 != (CLS_TRACKVISITED & windowStyle))
+ CommandLink_SetStateEx(hwnd, CLIS_VISITED, CLIS_VISITED, TRUE);
+
+}
+
+static void CommandLink_QueryUiState(HWND hwnd)
+{
+ UINT uiState = (UINT)DefWindowProcW(hwnd, WM_QUERYUISTATE, 0, 0L);
+ CommandLink_SetStateEx(hwnd, (0 != (UISF_HIDEFOCUS & uiState)) ? CLIS_HIDEFOCUS : 0, CLIS_HIDEFOCUS, TRUE);
+}
+static LRESULT CommandLink_OnCreateWindow(HWND hwnd, CREATESTRUCT *pcs)
+{
+ UNREFERENCED_PARAMETER(pcs);
+
+ COMMANDLINK *link;
+
+ link = (COMMANDLINK*)calloc(1, sizeof(COMMANDLINK));
+ if (NULL == link)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtrW(hwnd, 0, (LONGX86)(LONG_PTR)link) && ERROR_SUCCESS != GetLastError())
+ {
+ free(link);
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ link->rgbBk = GetSysColor(COLOR_3DFACE);
+ link->rgbText = GetSysColor(COLOR_HOTLIGHT);
+ link->rgbTextVisited = (0x00FFFFFF & (~link->rgbText));
+ link->rgbTextHighlight = GetSysColor(COLOR_HOTLIGHT);
+ link->cursorHot = LoadCursor(NULL, IDC_HAND);
+ SetRect(&link->margins, MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM);
+
+ CommandLink_QueryUiState(hwnd);
+ return FALSE;
+}
+
+static void CommandLink_OnDestroy(HWND hwnd)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ SetWindowLongPtrW(hwnd, 0, 0L);
+ if (!link) return;
+
+ free(link);
+}
+
+static void CommandLink_OnPaint(HWND hwnd)
+{
+ PAINTSTRUCT ps;
+ if (BeginPaint(hwnd, &ps))
+ {
+ if (ps.rcPaint.left != ps.rcPaint.right)
+ CommandLink_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
+ EndPaint(hwnd, &ps);
+ }
+}
+
+static void CommandLink_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
+{
+ RECT clientRect;
+ if (GetClientRect(hwnd, &clientRect))
+ CommandLink_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
+}
+
+static void CommandLink_OnSetFocus(HWND hwnd, HWND lostFocus)
+{
+ UNREFERENCED_PARAMETER(lostFocus);
+ CommandLink_SetStateEx(hwnd, CLIS_FOCUSED, CLIS_FOCUSED, TRUE);
+ CommandLink_NotifyParent(hwnd, NM_SETFOCUS);
+}
+
+static void CommandLink_OnKillFocus(HWND hwnd, HWND receiveFocus)
+{
+ UNREFERENCED_PARAMETER(receiveFocus);
+ CommandLink_SetStateEx(hwnd, 0, CLIS_FOCUSED, TRUE);
+ CommandLink_NotifyParent(hwnd, NM_KILLFOCUS);
+}
+
+static void CommandLink_OnMouseMove(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ UNREFERENCED_PARAMETER(mouseFlags);
+ UNREFERENCED_PARAMETER(pts);
+
+ UINT windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL != link)
+ {
+ if (0 == (CLIS_HOT & link->state) && 0 != (CLS_HOTTRACK & windowStyle))
+ {
+ link->state |= CLIS_HOT;
+ InvalidateRect(hwnd, NULL, FALSE);
+
+ TRACKMOUSEEVENT tm;
+ tm.cbSize = sizeof(TRACKMOUSEEVENT);
+ tm.dwFlags = TME_LEAVE;
+ tm.hwndTrack = hwnd;
+ TrackMouseEvent(&tm);
+ }
+ }
+}
+
+static void CommandLink_OnMouseLeave(HWND hwnd)
+{
+ CommandLink_SetStateEx(hwnd, 0, CLIS_HOT, TRUE);
+}
+
+static void CommandLink_OnLButtonDown(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ UNREFERENCED_PARAMETER(mouseFlags);
+ UNREFERENCED_PARAMETER(pts);
+
+ if (IsWindowEnabled(hwnd) && hwnd != GetFocus())
+ SetFocus(hwnd);
+
+ CommandLink_SetStateEx(hwnd, CLIS_PRESSED, CLIS_PRESSED, TRUE);
+ if (hwnd != GetCapture())
+ SetCapture(hwnd);
+
+}
+
+static void CommandLink_OnLButtonUp(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ UNREFERENCED_PARAMETER(mouseFlags);
+
+ RECT clientRect;
+ POINT pt;
+ POINTSTOPOINT(pt, pts);
+
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL != link && 0 != (CLIS_PRESSED & link->state))
+ {
+ if (GetClientRect(hwnd, &clientRect) && PtInRect(&clientRect, pt))
+ CommandLink_Click(hwnd);
+ CommandLink_SetStateEx(hwnd, 0, CLIS_PRESSED, TRUE);
+ }
+
+ if (hwnd == GetCapture())
+ SetCapture(NULL);
+}
+
+static void CommandLink_OnKeyDown(HWND hwnd, UINT virtualKey, UINT keyFlags)
+{
+ UNREFERENCED_PARAMETER(hwnd);
+ UNREFERENCED_PARAMETER(virtualKey);
+ UNREFERENCED_PARAMETER(keyFlags);
+
+}
+
+static void CommandLink_OnKeyUp(HWND hwnd, UINT virtualKey, UINT keyFlags)
+{
+ UNREFERENCED_PARAMETER(keyFlags);
+
+ switch(virtualKey)
+ {
+ case VK_SPACE:
+ CommandLink_Click(hwnd);
+ break;
+ }
+
+}
+
+static void CommandLink_OnEnable(HWND hwnd, BOOL fEnabled)
+{
+ UNREFERENCED_PARAMETER(fEnabled);
+ InvalidateRect(hwnd, NULL, TRUE);
+}
+
+
+static void CommandLink_OnUpdateUiState(HWND hwnd, UINT actionId, UINT stateId)
+{
+ DefWindowProcW(hwnd, WM_UPDATEUISTATE, MAKEWPARAM(actionId, stateId), 0L);
+ CommandLink_QueryUiState(hwnd);
+}
+
+static void CommandLink_OnSetFont(HWND hwnd, HFONT newFont, BOOL fRedraw)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL != link) link->textFont = newFont;
+
+ if (FALSE != fRedraw)
+ InvalidateRect(hwnd, NULL, TRUE);
+}
+
+static LRESULT CommandLink_OnGetFont(HWND hwnd)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ return (LRESULT)((NULL != link) ? link->textFont : NULL);
+}
+
+static LRESULT CommandLink_OnSetCursor(HWND hwnd, HWND cursorWindow, UINT hitTest, UINT uMsg)
+{
+ UNREFERENCED_PARAMETER(cursorWindow);
+ UNREFERENCED_PARAMETER(hitTest);
+ UNREFERENCED_PARAMETER(uMsg);
+
+ if (IsWindowEnabled(hwnd))
+ {
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL != link && NULL != link->cursorHot)
+ {
+ SetCursor(link->cursorHot);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static LRESULT CommandLink_OnGetIdealHeight(HWND hwnd)
+{
+ SIZE windowSize;
+ return (CommandLink_GetIdealSizeReal(hwnd, &windowSize)) ? windowSize.cy : 0;
+}
+
+static LRESULT CommandLink_OnGetIdealSize(HWND hwnd, SIZE *sizeOut)
+{
+ return CommandLink_GetIdealSizeReal(hwnd, sizeOut);
+}
+
+static void CommandLink_OnResetVisited(HWND hwnd)
+{
+ CommandLink_SetStateEx(hwnd, 0, CLIS_VISITED, TRUE);
+}
+
+
+static BOOL CommandLink_OnGetMargins(HWND hwnd, RECT *prc)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == prc || NULL == link) return FALSE;
+ return CopyRect(prc, &link->margins);
+}
+
+static BOOL CommandLink_OnSetMargins(HWND hwnd, const RECT *prc)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == prc || NULL == link) return FALSE;
+ return CopyRect(&link->margins, prc);
+}
+
+static BOOL CommandLink_OnSetBackColor(HWND hwnd, COLORREF rgb)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return FALSE;
+
+ link->rgbBk = rgb;
+ return TRUE;
+}
+
+static BOOL CommandLink_OnGetBackColor(HWND hwnd)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ return (NULL != link) ? link->rgbBk : RGB(255, 0, 255);
+}
+
+static BOOL CommandLink_OnSetTextColor(HWND hwnd, COLORREF rgb)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return FALSE;
+
+ link->rgbText = rgb;
+ return TRUE;
+}
+
+static BOOL CommandLink_OnGetTextColor(HWND hwnd)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ return (NULL != link) ? link->rgbText : RGB(255, 0, 255);
+}
+
+static BOOL CommandLink_OnSetVisitedColor(HWND hwnd, COLORREF rgb)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return FALSE;
+
+ link->rgbTextVisited = rgb;
+ return TRUE;
+}
+
+static BOOL CommandLink_OnGetVisitedColor(HWND hwnd)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ return (NULL != link) ? link->rgbTextVisited : RGB(255, 0, 255);
+}
+
+static BOOL CommandLink_OnSetHighlightColor(HWND hwnd, COLORREF rgb)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ if (NULL == link) return FALSE;
+
+ link->rgbTextHighlight = rgb;
+ return TRUE;
+}
+
+static BOOL CommandLink_OnGetHighlightColor(HWND hwnd)
+{
+ COMMANDLINK *link = GetCommandLink(hwnd);
+ return (NULL != link) ? link->rgbTextHighlight : RGB(255, 0, 255);
+}
+
+static LRESULT CALLBACK CommandLink_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( uMsg )
+ {
+ case WM_CREATE:
+ return CommandLink_OnCreateWindow( hwnd, (CREATESTRUCT *) lParam );
+ case WM_DESTROY:
+ CommandLink_OnDestroy( hwnd );
+ return 0;
+ case WM_PAINT:
+ CommandLink_OnPaint( hwnd );
+ return 0;
+ case WM_PRINTCLIENT:
+ CommandLink_OnPrintClient( hwnd, (HDC) wParam, (UINT) lParam );
+ return 0;
+ case WM_ERASEBKGND:
+ return 0;
+ case WM_SETFONT:
+ CommandLink_OnSetFont( hwnd, (HFONT) wParam, (BOOL) LOWORD( lParam ) );
+ return 0;
+ case WM_GETFONT:
+ return CommandLink_OnGetFont( hwnd );
+ case WM_SETFOCUS:
+ CommandLink_OnSetFocus( hwnd, (HWND) wParam );
+ return 0;
+ case WM_KILLFOCUS:
+ CommandLink_OnKillFocus( hwnd, (HWND) wParam );
+ return 0;
+ case WM_MOUSEMOVE:
+ CommandLink_OnMouseMove( hwnd, (UINT) wParam, MAKEPOINTS( lParam ) );
+ return 0;
+ case WM_MOUSELEAVE:
+ CommandLink_OnMouseLeave( hwnd );
+ return 0;
+ case WM_LBUTTONDOWN:
+ CommandLink_OnLButtonDown( hwnd, (UINT) wParam, MAKEPOINTS( lParam ) );
+ return 0;
+ case WM_LBUTTONUP:
+ CommandLink_OnLButtonUp( hwnd, (UINT) wParam, MAKEPOINTS( lParam ) );
+ return 0;
+ case WM_KEYDOWN:
+ CommandLink_OnKeyDown( hwnd, (UINT) wParam, (UINT) lParam );
+ return 0;
+ case WM_KEYUP:
+ CommandLink_OnKeyUp( hwnd, (UINT) wParam, (UINT) lParam );
+ return 0;
+ case WM_ENABLE:
+ CommandLink_OnEnable( hwnd, (BOOL) wParam );
+ return 0;
+ case WM_UPDATEUISTATE:
+ CommandLink_OnUpdateUiState( hwnd, LOWORD( wParam ), HIWORD( wParam ) );
+ return 0;
+ case WM_SETCURSOR:
+ return CommandLink_OnSetCursor( hwnd, (HWND) wParam, LOWORD( lParam ), HIWORD( lParam ) );
+
+ case CLM_GETIDEALHEIGHT:
+ return CommandLink_OnGetIdealHeight( hwnd );
+ case CLM_GETIDEALSIZE:
+ return CommandLink_OnGetIdealSize( hwnd, (SIZE *) lParam );
+ case CLM_RESETVISITED:
+ CommandLink_OnResetVisited( hwnd );
+ return 0;
+ case CLM_GETMARGINS:
+ return CommandLink_OnGetMargins( hwnd, (RECT *) lParam );
+ case CLM_SETMARGINS:
+ return CommandLink_OnSetMargins( hwnd, (const RECT *) lParam );
+ case CLM_SETBACKCOLOR:
+ return CommandLink_OnSetBackColor( hwnd, (COLORREF) lParam );
+ case CLM_GETBACKCOLOR:
+ return CommandLink_OnGetBackColor( hwnd );
+ case CLM_SETTEXTCOLOR:
+ return CommandLink_OnSetTextColor( hwnd, (COLORREF) lParam );
+ case CLM_GETTEXTCOLOR:
+ return CommandLink_OnGetTextColor( hwnd );
+ case CLM_SETVISITEDCOLOR:
+ return CommandLink_OnSetVisitedColor( hwnd, (COLORREF) lParam );
+ case CLM_GETVISITEDCOLOR:
+ return CommandLink_OnGetVisitedColor( hwnd );
+ case CLM_SETHIGHLIGHTCOLOR:
+ return CommandLink_OnSetHighlightColor( hwnd, (COLORREF) lParam );
+ case CLM_GETHIGHLIGHTCOLOR:
+ return CommandLink_OnGetHighlightColor( hwnd );
+ }
+
+ return DefWindowProcW( hwnd, uMsg, wParam, lParam );
+}
diff --git a/Src/Winamp/commandLink.h b/Src/Winamp/commandLink.h
new file mode 100644
index 00000000..8f4d143f
--- /dev/null
+++ b/Src/Winamp/commandLink.h
@@ -0,0 +1,106 @@
+#ifndef NULLOSFT_DROPBOX_PLUGIN_COMMANDLINK_HEADER
+#define NULLOSFT_DROPBOX_PLUGIN_COMMANDLINK_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#define NWC_COMMANDLINKA "NullsoftCommandLink"
+#define NWC_COMMANDLINKW L"NullsoftCommandLink"
+
+#ifdef UNICODE
+#define NWC_COMMANDLINK NWC_COMMANDLINKW
+#else
+#define NWC_COMMANDLINK NWC_COMMANDLINKA
+#endif // !UNICODE
+
+// styles
+#define CLS_HOTTRACK 0x0001
+#define CLS_TRACKVISITED 0x0002
+#define CLS_DEFAULTCOLORS 0x0008
+#define CLS_ALWAYSUNDERLINE 0x0010
+#define CLS_HIGHLIGHTCOLOR 0x0020 // enables CLM_SETHIGHLIGHTCOLOR/CLM_GETHIGHLIGHTCOLOR
+
+// states
+#define CLIS_VISITED 0x0001
+#define CLIS_HOT 0x0002
+#define CLIS_PRESSED 0x0004
+#define CLIS_FOCUSED 0x0008
+#define CLIS_HIDEFOCUS 0x0010
+
+#define CommandLink_CreateWindow(__windowStyleEx, __linkText, __windowStyle, __x, __y, __cx, __cy, __parentWindow, __controlId)\
+ CreateWindowEx((__windowStyleEx), NWC_COMMANDLINK, (__linkText), (__windowStyle),\
+ (__x), (__y), (__cx), (__cy), (__parentWindow), (HMENU)(INT_PTR)(__controlId), NULL, 0)
+
+
+#define CLM_FIRST (WM_USER + 1)
+
+#define CLM_GETIDEALHEIGHT (CLM_FIRST + 0)
+#define CommandLink_GetIdealHeight(/*HNWD*/__hwnd)\
+ ((INT)SendMessageW((__hwnd), CLM_GETIDEALHEIGHT, 0, 0L))
+
+#define CLM_GETIDEALSIZE (CLM_FIRST + 1)
+#define CommandLink_GetIdealSize(/*HNWD*/ __hwnd, /*LPSIZE*/ __sizeOut)\
+ ((BOOL)SendMessageW((__hwnd), CLM_GETIDEALSIZE, 0, (LPARAM)(__sizeOut)))
+
+#define CLM_RESETVISITED (CLM_FIRST + 2)
+#define CommandLink_ResetVisited(/*HNWD*/__hwnd)\
+ (SendMessageW((__hwnd), CLM_RESETVISITED, 0, 0L))
+
+#define CLM_GETMARGINS (CLM_FIRST + 3) //lParam = (RECT*)*margins; Return TRUE on success
+#define CommandLink_GetMargins(/*HNWD*/ __hwnd, /*LPRECT*/ __rectOut)\
+ ((BOOL)SendMessageW((__hwnd), CLM_GETMARGINS, 0, (LPARAM)(__rectOut)))
+
+#define CLM_SETMARGINS (CLM_FIRST + 4) //lParam = (RECT*)*margins; Return TRUE on success
+#define CommandLink_SetMargins(/*HNWD*/ __hwnd, /*LPCRECT*/ __rectIn)\
+ ((BOOL)SendMessageW((__hwnd), CLM_SETMARGINS, 0, (LPARAM)(__rectIn)))
+
+#define CLM_SETBACKCOLOR (CLM_FIRST + 5) //lParam = (LPARAM)rgb; Return TRUE on success
+#define CommandLink_SetBackColor(/*HNWD*/ __hwnd, /*COLORREF*/ __rgb)\
+ ((BOOL)SendMessageW((__hwnd), CLM_SETBACKCOLOR, 0, (LPARAM)(__rgb)))
+
+#define CLM_GETBACKCOLOR (CLM_FIRST + 6) //Return COLORREF
+#define CommandLink_GetBackColor(/*HNWD*/ __hwnd)\
+ ((COLORREF)SendMessageW((__hwnd), CLM_GETBACKCOLOR, 0, 0L))
+
+#define CLM_SETTEXTCOLOR (CLM_FIRST + 7) //lParam = (LPARAM)rgb; Return TRUE on success
+#define CommandLink_SetTextColor(/*HNWD*/ __hwnd, /*COLORREF*/ __rgb)\
+ ((BOOL)SendMessageW((__hwnd), CLM_SETTEXTCOLOR, 0, (LPARAM)(__rgb)))
+
+#define CLM_GETTEXTCOLOR (CLM_FIRST + 8) //Return COLORREF
+#define CommandLink_GetTextColor(/*HNWD*/ __hwnd)\
+ ((COLORREF)SendMessageW((__hwnd), CLM_GETTEXTCOLOR, 0, 0L))
+
+#define CLM_SETVISITEDCOLOR (CLM_FIRST + 9) //lParam = (LPARAM)rgb; Return TRUE on success
+#define CommandLink_SetVisitedColor(/*HNWD*/ __hwnd, /*COLORREF*/ __rgb)\
+ ((BOOL)SendMessageW((__hwnd), CLM_SETVISITEDCOLOR, 0, (LPARAM)(__rgb)))
+
+#define CLM_GETVISITEDCOLOR (CLM_FIRST + 10) //Return COLORREF
+#define CommandLink_GetVisitedColor(/*HNWD*/ __hwnd)\
+ ((COLORREF)SendMessageW((__hwnd), CLM_GETVISITEDCOLOR, 0, 0L))
+
+#define CLM_SETHIGHLIGHTCOLOR (CLM_FIRST + 11) //lParam = (LPARAM)rgb; Return TRUE on success
+#define CommandLink_SetHighlightColor(/*HNWD*/ __hwnd, /*COLORREF*/ __rgb)\
+ ((BOOL)SendMessageW((__hwnd), CLM_SETHIGHLIGHTCOLOR, 0, (LPARAM)(__rgb)))
+
+#define CLM_GETHIGHLIGHTCOLOR (CLM_FIRST + 12) //Return COLORREF
+#define CommandLink_GetHighlightColor(/*HNWD*/ __hwnd)\
+ ((COLORREF)SendMessageW((__hwnd), CLM_GETHIGHLIGHTCOLOR, 0, 0L))
+
+
+
+// notifications
+// NM_CLICK
+// NM_SETFOCUS
+// NM_KILLFOCUS
+
+
+
+// internal call ( do not use)
+EXTERN_C BOOL CommandLink_RegisterClass(HINSTANCE hInstance);
+
+
+
+#endif //NULLOSFT_DROPBOX_PLUGIN_COMMANDLINK_HEADER \ No newline at end of file
diff --git a/Src/Winamp/compatibility.manifest b/Src/Winamp/compatibility.manifest
new file mode 100644
index 00000000..755c272c
--- /dev/null
+++ b/Src/Winamp/compatibility.manifest
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!--The ID below indicates application support for Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ <!--The ID below indicates application support for Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!--The ID below indicates application support for Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!--The ID below indicates application support for Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!--The ID below indicates application support for Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- This tag is required for XAML islands usage in the process for media scenarios. -->
+ <!-- This version corresponds to the Windows 10 May 2019 Update. -->
+ <maxversiontested Id="10.0.18362.0"/>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/Src/Winamp/config.h b/Src/Winamp/config.h
new file mode 100644
index 00000000..69f16fbb
--- /dev/null
+++ b/Src/Winamp/config.h
@@ -0,0 +1,188 @@
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#ifdef CONFIG_IMPL
+#define CONFIG_EXT
+#define DEF_VAL(x) =( x )
+#else
+#define CONFIG_EXT extern
+#define DEF_VAL(x)
+#endif // CONFIG_IMPL
+
+/* --- This lets us change the registry strings at compile-time, for special builds --- */
+
+#ifndef WINAMP_FILE
+#define REGISTRY_PREFIX "Winamp"
+#endif
+
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+
+#define WINAMP_FILE REGISTRY_PREFIX ".File"
+#define WINAMP_FILEW WIDEN(REGISTRY_PREFIX) L".File"
+#define WINAMP_PLAYLIST REGISTRY_PREFIX ".PlayList"
+#define WINAMP_PLAYLISTW WIDEN(REGISTRY_PREFIX) L".PlayList"
+#define WINAMP_SKINZIP REGISTRY_PREFIX ".SkinZip"
+#define WINAMP_SKINZIPW WIDEN(REGISTRY_PREFIX) L".SkinZip"
+#define WINAMP_LANGZIP REGISTRY_PREFIX ".LangZip"
+#define WINAMP_LANGZIPW WIDEN(REGISTRY_PREFIX) L".LangZip"
+#define WINAMP_PLAY REGISTRY_PREFIX ".Play"
+#define WINAMP_PLAYW WIDEN(REGISTRY_PREFIX) L".Play"
+#define WINAMP_ENQUEUE REGISTRY_PREFIX ".Enqueue"
+#define WINAMP_ENQUEUEW WIDEN(REGISTRY_PREFIX) L".Enqueue"
+#define WINAMP_BOOKMARK REGISTRY_PREFIX ".Bookmark"
+#define WINAMP_BOOKMARKW WIDEN(REGISTRY_PREFIX) L".Bookmark"
+
+/* -------------------------------------------------------------------------------- --- */
+
+extern void _r_s(char *name,char *data, int mlen);
+extern void _w_s(char *name, char *data);
+void _w_sW(const char *name, const wchar_t *data);
+void _r_sW(const char *name, wchar_t *data, int mlen);
+extern int _r_i(char *name, int def);
+extern void _w_i(char *name, intptr_t d);
+
+CONFIG_EXT int config_utf8 DEF_VAL(1);
+CONFIG_EXT wchar_t M3UDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t M3UBASE[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t CONFIGDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t SHAREDDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t PROGDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t ML_INI_FILE[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t INI_FILE[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT char INI_FILEA[MAX_PATH] DEF_VAL("");
+CONFIG_EXT wchar_t M3U_FILE[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t OLD_M3U_FILE[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t EQDIR1[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t EQDIR2[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t TEMP_FILE[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t PLUGINDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t SYSPLUGINDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t VISDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t DSPDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t SKINDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t DEMOMP3[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t SKINTEMPDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t LANGTEMPDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t BOOKMARKFILE[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t BOOKMARKFILE8[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t LANGDIR[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT wchar_t JSAPI2_INIFILE[MAX_PATH] DEF_VAL(L"");
+
+#define PE_FONTSIZE 12
+CONFIG_EXT int config_pe_fontsize DEF_VAL(PE_FONTSIZE);
+#define PE_DIRECTION_AUTO 0
+#define PE_DIRECTION_LTR 1
+#define PE_DIRECTION_RTL 2
+CONFIG_EXT int config_pe_direction DEF_VAL(PE_DIRECTION_LTR);
+CONFIG_EXT wchar_t config_langpack[MAX_PATH] DEF_VAL(L""), config_langpack2[MAX_PATH] DEF_VAL(L""), lang_directory[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT unsigned char config_wlz_menu DEF_VAL(0);
+CONFIG_EXT int config_skin_prompt DEF_VAL(1);
+CONFIG_EXT int config_wlz_prompt DEF_VAL(1);
+CONFIG_EXT char config_proxy[256], config_inet_mode DEF_VAL(0);
+CONFIG_EXT char config_defext[32] DEF_VAL("mp3");
+CONFIG_EXT wchar_t config_titlefmt[1024] DEF_VAL(L"[%artist% - ]$if2(%title%,$filepart(%filename%))");
+CONFIG_EXT int config_useexttitles DEF_VAL(1);
+CONFIG_EXT wchar_t config_visplugin_name[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT char config_visplugin_num, config_visplugin_priority DEF_VAL(2), config_visplugin_autoexec;
+CONFIG_EXT unsigned char config_shuffle_morph_rate DEF_VAL(50);
+CONFIG_EXT unsigned char config_playlist_recyclebin DEF_VAL(1);
+CONFIG_EXT unsigned char config_ospb DEF_VAL(0), config_eqdsize DEF_VAL(1);
+CONFIG_EXT char config_outname[128] DEF_VAL("out_ds.dll");
+CONFIG_EXT wchar_t config_dspplugin_name[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT unsigned char config_dspplugin_num;
+CONFIG_EXT unsigned char config_sticon,config_usecursors DEF_VAL(1);
+CONFIG_EXT unsigned char config_splash DEF_VAL(0) ,config_minst;
+CONFIG_EXT unsigned char config_taskbar,config_fixtitles DEF_VAL(3);
+CONFIG_EXT unsigned char config_ascb_new DEF_VAL(1),config_ttips DEF_VAL(1), config_priority DEF_VAL(1);
+CONFIG_EXT unsigned char config_riol DEF_VAL(4);
+CONFIG_EXT unsigned char config_whichicon DEF_VAL(1),config_whichicon2 DEF_VAL(1),config_addtolist;
+CONFIG_EXT unsigned char config_snap DEF_VAL(1), config_snaplen DEF_VAL(10), config_parent DEF_VAL(1);
+CONFIG_EXT unsigned char config_hilite DEF_VAL(1);
+CONFIG_EXT unsigned char config_disvis DEF_VAL(1), config_pladv DEF_VAL(1);
+CONFIG_EXT unsigned char config_shownumsinpl DEF_VAL(1),config_zeropadplnum DEF_VAL(0),config_keeponscreen DEF_VAL(1);
+CONFIG_EXT unsigned char config_dropaotfs DEF_VAL(1);
+CONFIG_EXT unsigned char config_nomwheel DEF_VAL(0);
+CONFIG_EXT unsigned char config_autoload_eq;
+CONFIG_EXT unsigned char config_use_eq;
+CONFIG_EXT int config_wx DEF_VAL(26), config_wy DEF_VAL(29);
+CONFIG_EXT unsigned char config_minimized;
+CONFIG_EXT unsigned char config_aot;
+CONFIG_EXT unsigned char config_shuffle, config_repeat;
+CONFIG_EXT unsigned char config_volume DEF_VAL(200), config_easymove DEF_VAL(1);
+CONFIG_EXT char config_pan;
+CONFIG_EXT unsigned char config_dsize;
+CONFIG_EXT unsigned char config_timeleftmode;
+CONFIG_EXT unsigned char config_autoscrollname DEF_VAL(1), config_sa DEF_VAL(1), config_safire DEF_VAL(4),
+ config_saref DEF_VAL(2), config_safalloff DEF_VAL(2),config_sa_peaks DEF_VAL(1),
+ config_sa_peak_falloff DEF_VAL(1);
+CONFIG_EXT int config_eq_wx DEF_VAL(26), config_eq_wy DEF_VAL(145), config_eq_open DEF_VAL(1), config_mw_open DEF_VAL(1);
+CONFIG_EXT int config_pe_wx DEF_VAL(26), config_pe_wy DEF_VAL(261), config_pe_open DEF_VAL(1), config_pe_width DEF_VAL(275),
+ config_pe_height DEF_VAL(116), config_pe_height_ws;
+/*
+CONFIG_EXT int config_si_wx DEF_VAL(0), config_si_wy DEF_VAL(0), config_si_width DEF_VAL(100), config_si_height DEF_VAL(100),
+ config_si_autoshow DEF_VAL(1), config_si_autosize DEF_VAL(1), config_si_autohide DEF_VAL(1), config_si_open DEF_VAL(0);
+ */
+CONFIG_EXT int config_plscrollsize DEF_VAL(1), config_plmw2xscroll DEF_VAL(1);
+CONFIG_EXT unsigned char config_windowshade,config_rofiob,config_eq_ws;
+CONFIG_EXT unsigned char config_preamp DEF_VAL(31);
+CONFIG_EXT int config_pilp;
+CONFIG_EXT unsigned char config_randskin;
+CONFIG_EXT wchar_t config_cwd[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT int config_newverchk DEF_VAL(1);
+CONFIG_EXT int config_newverchk_rc DEF_VAL(0);
+CONFIG_EXT int config_user_consent_join_channels DEF_VAL(-1);
+CONFIG_EXT int config_newverchk2 DEF_VAL(1);
+CONFIG_EXT int config_newverchk3 DEF_VAL(0);
+CONFIG_EXT int config_embedwnd_freesize;
+CONFIG_EXT wchar_t config_skin[MAX_PATH] DEF_VAL(L""), skin_directory[MAX_PATH] DEF_VAL(L"");
+CONFIG_EXT int config_dotitlenum DEF_VAL(1);
+CONFIG_EXT int config_dotasknum DEF_VAL(1);
+CONFIG_EXT char config_check_ft_startup DEF_VAL(0), config_updated_ft_startup DEF_VAL(0), config_uid_ft DEF_VAL(0);
+CONFIG_EXT char config_bifont DEF_VAL(0); // bitmapped font (off by default)
+CONFIG_EXT char config_bifont_alt DEF_VAL(0); // non-bitmapped font alternative option (off by default)
+CONFIG_EXT char config_browserbrand[16] DEF_VAL("");
+
+/* --- video --- */
+CONFIG_EXT int config_video_wx DEF_VAL(26), config_video_wy DEF_VAL(145),
+config_video_open DEF_VAL(0),
+config_video_width DEF_VAL(275), config_video_height DEF_VAL(232),
+config_video_ratio1 DEF_VAL(4), config_video_ratio2 DEF_VAL(3),
+config_video_useratio;
+
+CONFIG_EXT int config_video_aspectadj DEF_VAL(1);
+CONFIG_EXT int config_video_updsize DEF_VAL(0);
+CONFIG_EXT int config_video_noss DEF_VAL(1);
+CONFIG_EXT int config_video_logo DEF_VAL(1);
+CONFIG_EXT int config_video_osd DEF_VAL(1);
+CONFIG_EXT int config_video_stopclose DEF_VAL(1);
+//CONFIG_EXT int config_video_auto_fs DEF_VAL(0); // plague> moved to WinampAttributes.h
+
+//#define EXPERIMENTAL_CONTRAST
+#ifdef EXPERIMENTAL_CONTRAST
+CONFIG_EXT int config_video_contrast DEF_VAL(128);
+CONFIG_EXT int config_video_brightness DEF_VAL(128);
+#endif
+
+CONFIG_EXT int config_video_remove_fs_on_stop DEF_VAL(1);
+CONFIG_EXT int config_video_fliprgb DEF_VAL(0);
+
+CONFIG_EXT int config_wav_do_header DEF_VAL(1);
+CONFIG_EXT int config_wav_convert DEF_VAL(0);
+CONFIG_EXT char config_wav_ext[8] DEF_VAL("WAV");
+CONFIG_EXT int config_no_visseh;
+CONFIG_EXT int config_no_registry DEF_VAL(0);
+
+CONFIG_EXT int config_last_classic_skin_page DEF_VAL(0);
+CONFIG_EXT int config_last_playback_page DEF_VAL(0);
+CONFIG_EXT int config_last_fileinfo_page DEF_VAL(0);
+CONFIG_EXT int config_upd_mode DEF_VAL(0);
+CONFIG_EXT wchar_t config_artwork_filter[64] DEF_VAL(L"cover");
+
+CONFIG_EXT int config_noml_ratings_prompt DEF_VAL(1);
+CONFIG_EXT int config_noml_ratings DEF_VAL(0);
+
+CONFIG_EXT int config_jtf_check DEF_VAL(0);
+CONFIG_EXT int config_block_img DEF_VAL(1);
+
+#endif // config.h \ No newline at end of file
diff --git a/Src/Winamp/contnr.h b/Src/Winamp/contnr.h
new file mode 100644
index 00000000..1aa401fa
--- /dev/null
+++ b/Src/Winamp/contnr.h
@@ -0,0 +1,123 @@
+/**************************************************************************
+ THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
+ ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+ PARTICULAR PURPOSE.
+
+ Copyright 1998 Microsoft Corporation. All Rights Reserved.
+**************************************************************************/
+
+/**************************************************************************
+
+ File: contnr.h
+
+ Description: This file contains the complete class specification of an
+ ActiveX control container. This purpose of this container
+ is to test a single control being hosted.
+
+**************************************************************************/
+
+#ifndef _CONTAINER_H_
+#define _CONTAINER_H_
+
+/**************************************************************************
+ #include statements
+**************************************************************************/
+
+#include <ocidl.h>
+
+/**************************************************************************
+ class definitions
+**************************************************************************/
+
+class CContainer : public IOleClientSite,
+ public IOleInPlaceSite,
+ public IOleInPlaceFrame,
+ public IOleControlSite,
+ public IDispatch
+{
+ private:
+ ULONG m_cRefs; // ref count
+ HWND m_hwnd; // window handle of the container
+ HWND m_hwndStatus; // status window handle
+ IUnknown *m_punk; // IUnknown of contained object
+ RECT m_rect; // size of control
+
+ public:
+ CContainer();
+ ~CContainer();
+
+ public:
+ // *** IUnknown Methods ***
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // *** IOleClientSite Methods ***
+ STDMETHOD (SaveObject)();
+ STDMETHOD (GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER *ppMk);
+ STDMETHOD (GetContainer)(LPOLECONTAINER *ppContainer);
+ STDMETHOD (ShowObject)();
+ STDMETHOD (OnShowWindow)(BOOL fShow);
+ STDMETHOD (RequestNewObjectLayout)();
+
+ // *** IOleWindow Methods ***
+ STDMETHOD (GetWindow) (HWND * phwnd);
+ STDMETHOD (ContextSensitiveHelp) (BOOL fEnterMode);
+
+ // *** IOleInPlaceSite Methods ***
+ STDMETHOD (CanInPlaceActivate) (void);
+ STDMETHOD (OnInPlaceActivate) (void);
+ STDMETHOD (OnUIActivate) (void);
+ STDMETHOD (GetWindowContext) (IOleInPlaceFrame ** ppFrame, IOleInPlaceUIWindow ** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo);
+ STDMETHOD (Scroll) (SIZE scrollExtent);
+ STDMETHOD (OnUIDeactivate) (BOOL fUndoable);
+ STDMETHOD (OnInPlaceDeactivate) (void);
+ STDMETHOD (DiscardUndoState) (void);
+ STDMETHOD (DeactivateAndUndo) (void);
+ STDMETHOD (OnPosRectChange) (LPCRECT lprcPosRect);
+
+ // *** IOleInPlaceUIWindow Methods ***
+ STDMETHOD (GetBorder)(LPRECT lprectBorder);
+ STDMETHOD (RequestBorderSpace)(LPCBORDERWIDTHS lpborderwidths);
+ STDMETHOD (SetBorderSpace)(LPCBORDERWIDTHS lpborderwidths);
+ STDMETHOD (SetActiveObject)(IOleInPlaceActiveObject * pActiveObject,
+ LPCOLESTR lpszObjName);
+
+ // *** IOleInPlaceFrame Methods ***
+ STDMETHOD (InsertMenus)(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
+ STDMETHOD (SetMenu)(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);
+ STDMETHOD (RemoveMenus)(HMENU hmenuShared);
+ STDMETHOD (SetStatusText)(LPCOLESTR pszStatusText);
+ STDMETHOD (EnableModeless)(BOOL fEnable);
+ STDMETHOD (TranslateAccelerator)(LPMSG lpmsg, WORD wID);
+
+ // *** IOleControlSite Methods ***
+ STDMETHOD (OnControlInfoChanged)(void);
+ STDMETHOD (LockInPlaceActive)(BOOL fLock);
+ STDMETHOD (GetExtendedControl)(IDispatch **ppDisp);
+ STDMETHOD (TransformCoords)(POINTL *pptlHimetric, POINTF *pptfContainer, DWORD dwFlags);
+ STDMETHOD (TranslateAccelerator)(LPMSG pMsg, DWORD grfModifiers);
+ STDMETHOD (OnFocus)(BOOL fGotFocus);
+ STDMETHOD (ShowPropertyFrame)(void);
+
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ public:
+ void add(BSTR clsid);
+ void remove();
+ void setParent(HWND hwndParent);
+ void setLocation(int x, int y, int width, int height);
+ void setVisible(BOOL fVisible);
+ void setFocus(BOOL fFocus);
+ void setStatusWindow(HWND hwndStatus);
+ void translateKey(MSG msg);
+ IDispatch *getDispatch();
+ IUnknown * getUnknown();
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/conversions.cpp b/Src/Winamp/conversions.cpp
new file mode 100644
index 00000000..6244b1ec
--- /dev/null
+++ b/Src/Winamp/conversions.cpp
@@ -0,0 +1,114 @@
+#include "main.h"
+#include <math.h>
+#pragma intrinsic(fabs)
+
+/*
+#ifndef _WIN64
+__inline static int lrint(double flt)
+{
+ int intgr;
+
+ _asm
+ {
+ fld flt
+ fistp intgr
+ }
+
+ return intgr;
+}
+#else
+__inline static int lrint(double flt)
+{
+ return (int)flt;
+}
+#endif
+*/
+
+#define PA_CLIP_( val, min, max )\
+ { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
+
+ void Float32_To_Int16_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count)
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+
+ while( count-- )
+ {
+ long samp = lrint((*src * (32768.0)));
+
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+inline static double clip(double x, double a, double b)
+{
+ double x1 = fabs (x-a);
+ double x2 = fabs (x-b);
+ x = x1 + (a+b);
+ x -= x2;
+ x *= 0.5;
+ return x;
+}
+
+/*
+benski> this might be faster than what the compiler spits out for the above function,
+but we should benchmark
+inline static double clip(double x, double a, double b)
+{
+ const double zero_point_five = 0.5;
+ __asm
+ {
+ fld x
+ fld a
+ fld b
+
+ fld st(2)
+ fsub st(0),st(2) // x-b
+ fabs
+ fadd st(0),st(2)
+ fadd st(0),st(1)
+
+ fld st(3)
+ fsub st(0), st(2)
+ fabs
+ fsubp st(1), st(0)
+ fmul zero_point_five
+
+ ffree st(4)
+ ffree st(3)
+ ffree st(2)
+ ffree st(1)
+ }
+}
+*/
+
+
+void Float32_To_Int24_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count)
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+ double scaled = *src * 0x7FFFFFFF;
+ scaled=clip( scaled, -2147483648., 2147483647. );
+ signed long temp = (signed long) scaled;
+
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
diff --git a/Src/Winamp/convert.cpp b/Src/Winamp/convert.cpp
new file mode 100644
index 00000000..475f7ff8
--- /dev/null
+++ b/Src/Winamp/convert.cpp
@@ -0,0 +1,781 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author:
+** Created:
+**/
+
+#include "main.h"
+#include "resource.h"
+#include "../nsv/enc_if.h"
+#include "../nu/threadname.h"
+#include "../nu/AutoWideFn.h"
+#include "../nu/AutoCharFn.h"
+#include "DecodeFile.h"
+
+extern DecodeFile *decodeFile;
+
+static wchar_t DLL_Dir[MAX_PATH];
+
+static intptr_t getEncoderFromFolder(const wchar_t *spec, int bps, int nch, int srate, int dstf, const wchar_t *curdir, int create, HMODULE *pmod, HWND hParent, converterEnumFmtStruct *enumCrap, char * inifile)
+{
+ WIN32_FIND_DATAW fd = {0};
+ wchar_t buf[MAX_PATH*2 + 1] = {0};
+
+ PathCombineW(buf, curdir, spec);
+
+ if (pmod) *pmod = NULL;
+
+ HANDLE h = FindFirstFileW(buf, &fd);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ PathCombineW(buf, curdir, fd.cFileName);
+
+ HMODULE mod = LoadLibraryW(buf);
+ if (mod)
+ {
+ // passes winamp's hwnd to the encoder (if supporting it)
+ void (*swh)(HWND hwnd);
+ *((void **)&swh) = GetProcAddress(mod, "SetWinampHWND");
+ if (swh)
+ {
+ swh(hMainWindow);
+ }
+
+ if (enumCrap)
+ {
+ unsigned int (*gat)(int idx, char *desc);
+ *((void **)&gat) = GetProcAddress(mod, "GetAudioTypes3");
+ if (gat)
+ {
+ int i = 0;
+ for (;;)
+ {
+ char desc[1024] = {0};
+ unsigned int type = gat(i++, desc);
+ if (!type) break;
+ enumCrap->enumProc(enumCrap->user_data, desc, type);
+ }
+ }
+ }
+ else
+ {
+ void (*ExtAudio3)(HWND hwndParent, int *ex, int ex_len);
+ *((void **)&ExtAudio3) = GetProcAddress(mod, "ExtAudio3");
+ if (ExtAudio3) ExtAudio3(hMainWindow, NULL, 0);
+
+ AudioCoder *ac = 0;
+ AudioCoder *(*ca)(int nch, int srate, int bps, unsigned int srct, unsigned int *outt, char *configfile);
+ *((void **)&ca) = GetProcAddress(mod, "CreateAudio3");
+
+ if (create == 0)
+ {
+ HWND (*ca)(HWND hwndParent, HINSTANCE hinst, unsigned int outt, char *configfile);
+ *((void**)&ca) = GetProcAddress(mod, "ConfigAudio3");
+ if (ca)
+ {
+ HWND h = ca(hParent, mod, dstf, inifile?inifile:INI_FILEA);
+ if (h)
+ {
+ *pmod = mod;
+ return (intptr_t)h;
+ }
+ }
+ }
+
+ //if (ca && (ac=ca(nch,srate,bps,srct,outt,configfile))) return ac;
+ if (create == 1 && ca && (ac = ca(nch, srate, bps, mmioFOURCC('P', 'C', 'M', ' '), (unsigned int *) & dstf, inifile?inifile:INI_FILEA))) //FUCKO: input format
+ {
+ *pmod = mod;
+ return (intptr_t)ac;
+ }
+ if (create == 2) {
+ unsigned int (*gat)(int idx, char *desc);
+ *((void **)&gat) = GetProcAddress(mod, "GetAudioTypes3");
+ if (gat)
+ {
+ int i = 0;
+ for (;;)
+ {
+ char desc[1024] = {0};
+ unsigned int type = gat(i++, desc);
+ if (!type) break;
+ if (type == dstf) {
+ *pmod = mod;
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ FreeLibrary(mod);
+ }
+ }
+ while (FindNextFileW(h, &fd));
+ FindClose(h);
+ }
+ return 0;
+}
+
+static intptr_t getEncoder(int bps, int nch, int srate, int *destformat, int create, HMODULE *pmod, HWND parent, converterEnumFmtStruct *enumCrap = 0,char * inifile=0)
+{
+ HKEY hKey = NULL;
+
+ if (!DLL_Dir[0] && RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion",
+ 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ DWORD l = sizeof(DLL_Dir);
+ DWORD t = 0;
+ if (RegQueryValueExW(hKey, L"CommonFilesDir", NULL, &t, (LPBYTE)DLL_Dir, &l ) != ERROR_SUCCESS || t != REG_SZ)
+ DLL_Dir[0] = 0;
+ PathAppendW(DLL_Dir, L"NSV");
+ RegCloseKey(hKey);
+ }
+
+ if (!DLL_Dir[0]) GetTempPathW(sizeof(DLL_Dir)/sizeof(*DLL_Dir), DLL_Dir);
+
+ //look in plugins folder
+
+ int ret;
+ if (ret = getEncoderFromFolder(L"enc_*.dll", bps, nch, srate, destformat[0], PLUGINDIR, create, pmod, parent, enumCrap,inifile))
+ return ret;
+
+ if (GetPrivateProfileIntW(AutoWide(app_name), L"scannsv", 0, INI_FILE))
+ {
+ //look in common files folder
+ if (ret = getEncoderFromFolder(L"nsv_coder_*.dll", bps, nch, srate, destformat[0], DLL_Dir, create, pmod, parent, enumCrap,inifile))
+ return ret;
+ }
+
+ return 0;
+}
+
+static DWORD WINAPI convertThread(void *param)
+{
+ convertFileStruct *cfs = (convertFileStruct *)param;
+ ifc_audiostream *decoder = cfs->decoder;
+ HANDLE fh = cfs->file_handle;
+ AudioCoder *ac = cfs->audio_coder;
+ HMODULE mod = cfs->encoder_mod;
+ int destformat = cfs->destformat[0];
+ int bps = cfs->bps;
+ int nch = cfs->channels;
+ //int srate = cfs->sample_rate;
+
+ size_t bytes_per_packet = nch*(bps/8);
+ size_t ret = 0;
+ SetThreadName((DWORD)-1, "Transcode");
+ cfs->bytes_done = 0;
+ cfs->bytes_out = 0;
+ DWORD laststatpost = 0;
+ do
+ {
+ int error=0;
+ char buf[65536] = {0};
+ size_t buf_size = sizeof(buf);
+ buf_size -= (buf_size % bytes_per_packet); // don't read half a sample or only some of the channels!
+ ret = decoder->ReadAudio(buf, buf_size, &cfs->killswitch, &error);
+
+ if (destformat == mmioFOURCC('P', 'C', 'M', ' ') /* || destformat==mmioFOURCC('W','A','V',' ')*/)
+ {
+ //FUCKO: resample in desired format
+ DWORD a = 0;
+ if (ret > 0) WriteFile(fh, buf, (DWORD)ret, &a, NULL);
+ cfs->bytes_out += a;
+ }
+ else
+ {
+ int framepos = 0;
+ int avail = (int) ret;
+ char *in = buf;
+ char out[32768] = {0};
+
+ // WM encoding needs to know that you're going to be done, before you stop calling Encode(...)
+ if ( ret == 0 )
+ {
+ if (ac && mod)
+ {
+ void (*finish)(const char *filename, AudioCoder *coder);
+ *((void **)&finish) = GetProcAddress(mod, "PrepareToFinish");
+ if (finish)
+ {
+ finish(cfs->destfile, ac);
+ }
+ }
+ }
+
+ for (;;)
+ {
+ int in_used = 0;
+ int v = ac->Encode(framepos++, in, avail, &in_used, out, sizeof(out));
+ if (v > 0)
+ {
+ DWORD a = 0;
+ WriteFile(fh, out, v, &a, NULL);
+ cfs->bytes_out += v;
+ }
+ if (in_used > 0)
+ {
+ avail -= in_used;
+ in += in_used;
+ }
+ if (!v && !in_used) break;
+ }
+ }
+ cfs->bytes_done += (int)ret;
+
+ if (GetTickCount() - laststatpost > 1000)
+ {
+ SendMessageW(cfs->callbackhwnd, WM_WA_IPC, (int)((double)cfs->bytes_done*100.0 / (double)cfs->bytes_total), IPC_CB_CONVERT_STATUS);
+ laststatpost = GetTickCount();
+ }
+ }
+ while (!cfs->killswitch && ret > 0);
+
+ CloseHandle(fh);
+
+ if (ac && mod)
+ {
+ void (*finish)(const char *filename, AudioCoder *coder);
+ *((void **)&finish) = GetProcAddress(mod, "FinishAudio3");
+ if (finish)
+ {
+ finish(cfs->destfile, ac);
+ }
+ }
+
+ decodeFile->CloseAudio(decoder);
+
+ if (!cfs->killswitch) PostMessageW(cfs->callbackhwnd, WM_WA_IPC, 0, IPC_CB_CONVERT_DONE);
+
+ return 1;
+}
+
+static DWORD WINAPI convertThreadW(void *param)
+{
+ convertFileStructW *cfs = (convertFileStructW *)param;
+ ifc_audiostream *decoder = (ifc_audiostream *)cfs->decoder;
+ HANDLE fh = cfs->file_handle;
+ AudioCoder *ac = cfs->audio_coder;
+ HMODULE mod = cfs->encoder_mod;
+ int destformat = cfs->destformat[0];
+ int bps = cfs->bps;
+ int nch = cfs->channels;
+ //int srate = cfs->sample_rate;
+
+ size_t bytes_per_packet = nch*(bps/8);
+ size_t ret = 0;
+ SetThreadName((DWORD)-1, "Transcode");
+ cfs->bytes_done = 0;
+ cfs->bytes_out = 0;
+ DWORD laststatpost = 0;
+ do
+ {
+ int error=0;
+ char buf[65536] = {0};
+ size_t buf_size = sizeof(buf);
+ buf_size -= (buf_size % bytes_per_packet); // don't read half a sample or only some of the channels!
+ ret = decoder->ReadAudio(buf, buf_size, &cfs->killswitch, &error);
+
+ if (destformat == mmioFOURCC('P', 'C', 'M', ' ') /* || destformat==mmioFOURCC('W','A','V',' ')*/)
+ {
+ //FUCKO: resample in desired format
+ DWORD a = 0;
+ if (ret > 0) WriteFile(fh, buf, (DWORD)ret, &a, NULL);
+ cfs->bytes_out += a;
+ }
+ else
+ {
+ int framepos = 0;
+ int avail = (int) ret;
+ char *in = buf;
+ char out[32768] = {0};
+
+ // WM encoding needs to know that you're going to be done, before you stop calling Encode(...)
+ if ( ret == 0 )
+ {
+ if (ac && mod)
+ {
+ // try unicode first
+ void (*finishW)(const wchar_t *filename, AudioCoder *coder);
+ *((void **)&finishW) = GetProcAddress(mod, "PrepareToFinishW");
+ if (finishW)
+ {
+ finishW(cfs->destfile, ac);
+ }
+ else // otherwise, pass it the 8.3 filename
+ {
+ void (*finish)(const char *filename, AudioCoder *coder);
+ *((void **)&finish) = GetProcAddress(mod, "PrepareToFinish");
+ if (finish)
+ {
+ finish(AutoCharFn(cfs->destfile), ac);
+ }
+ }
+ }
+ }
+
+ for (;;)
+ {
+ int in_used = 0;
+ int v = ac->Encode(framepos++, in, avail, &in_used, out, sizeof(out));
+ if (v > 0)
+ {
+ DWORD a = 0;
+ WriteFile(fh, out, v, &a, NULL);
+ cfs->bytes_out += v;
+ }
+ if (in_used > 0)
+ {
+ avail -= in_used;
+ in += in_used;
+ }
+ if (!v && !in_used) break;
+ }
+ }
+ cfs->bytes_done += (int)ret;
+
+ if (GetTickCount() - laststatpost > 1000)
+ {
+ SendMessageW(cfs->callbackhwnd, WM_WA_IPC, (int)((double)cfs->bytes_done*100.0 / (double)cfs->bytes_total), IPC_CB_CONVERT_STATUS);
+ laststatpost = GetTickCount();
+ }
+ }
+ while (!cfs->killswitch && ret > 0);
+
+ CloseHandle(fh);
+
+ if (ac && mod)
+ {
+ void (*finishW)(const wchar_t *filename, AudioCoder *coder);
+ *((void **)&finishW) = GetProcAddress(mod, "FinishAudio3W");
+ if (finishW)
+ {
+ finishW(cfs->destfile, ac);
+ }
+ else // otherwise, try the 8.3 filename
+ {
+ void (*finish)(const char *filename, AudioCoder *coder);
+ *((void **)&finish) = GetProcAddress(mod, "FinishAudio3");
+ if (finish)
+ {
+ finish(AutoCharFn(cfs->destfile), ac);
+ }
+ }
+ }
+
+ decodeFile->CloseAudio(decoder);
+
+ if (!cfs->killswitch) PostMessageW(cfs->callbackhwnd, WM_WA_IPC, 0, IPC_CB_CONVERT_DONE);
+
+ return 1;
+}
+
+// due to the language support, we can't just now return the string in cfs->error
+// but instead have to have it in a static string so it can be accessed once we
+// have returned without issues from later use of getString and it's buffer usage
+static char errorStr[2048];
+int convert_file(convertFileStruct *cfs)
+{
+ // clear the buffer on starting otherwise we may return an invalid error message
+ //memset(&errorStr, 0, sizeof(errorStr));
+ errorStr[0]=0;
+
+ if (cfs->destfile && cfs->sourcefile && !_stricmp(cfs->destfile, cfs->sourcefile))
+ {
+ cfs->error = getString(IDS_CONV_SRC_EQUALS_DEST,errorStr,2048);
+ return 0;
+ }
+
+ AudioParameters parameters;
+ ifc_audiostream *decoder = decodeFile->OpenAudioBackground(AutoWideFn(cfs->sourcefile), &parameters);
+ cfs->bytes_total= (int)(parameters.sizeBytes?parameters.sizeBytes:-1);
+
+ if (!decoder)
+ {
+ switch(parameters.errorCode)
+ {
+ case API_DECODEFILE_UNSUPPORTED:
+ cfs->error = getString(IDS_CONV_DECODER_MISSING,errorStr,2048);
+ return 0;
+ case API_DECODEFILE_NO_INTERFACE:
+ cfs->error = getString(IDS_CONV_INPUT_PLUGIN_NOT_SUPPORTING,errorStr,2048);
+ return 0;
+ case API_DECODEFILE_NO_RIGHTS:
+ cfs->error = getString(IDS_CONV_DRM_DECODE_FAIL,errorStr,2048);
+ return 0;
+ case API_DECODEFILE_FAIL_NO_WARN:
+ return 0;
+ default:
+ cfs->error = getString(IDS_CONV_ERROR_OPEN_FILE,errorStr,2048);
+ return 0;
+ }
+ }
+
+ cfs->decoder=0;
+ cfs->convert_thread=0;
+ cfs->file_handle=0;
+ cfs->audio_coder=0;
+ cfs->encoder_mod=0;
+ cfs->bps=0;
+ cfs->channels=0;
+ cfs->sample_rate=0;
+
+ //find the encoding DLL
+ if (cfs->destformat[0] != mmioFOURCC('P', 'C', 'M', ' '))
+ {
+ HMODULE mod = NULL;
+ char * inifile = NULL;
+ if(cfs->destformat[6] == mmioFOURCC('I','N','I',' ')) inifile = (char*)cfs->destformat[7];
+ AudioCoder *ac = (AudioCoder *)getEncoder(parameters.bitsPerSample, parameters.channels, parameters.sampleRate, (int *) & cfs->destformat, 1, &mod, NULL,0, inifile);
+ if (!ac)
+ {
+ decodeFile->CloseAudio(decoder);
+ cfs->error = getString(IDS_CONV_ERROR_OPEN_ENCODER,errorStr,2048);
+ return 0;
+ }
+ cfs->audio_coder = ac;
+ cfs->encoder_mod = mod;
+ }
+
+ cfs->killswitch = 0;
+ cfs->decoder = decoder;
+
+ cfs->bps = parameters.bitsPerSample;
+ cfs->channels = parameters.channels;
+ cfs->sample_rate = parameters.sampleRate;
+
+ //open destination file
+ HANDLE fh = CreateFileA(cfs->destfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if ( fh == INVALID_HANDLE_VALUE )
+ {
+ decodeFile->CloseAudio(decoder);
+ delete cfs->audio_coder;
+ cfs->audio_coder = 0;
+ cfs->error = getString(IDS_CONV_ERROR_OPEN_DEST,errorStr,2048);
+ return 0;
+ }
+ cfs->file_handle = fh;
+
+ DWORD id = 0;
+ cfs->convert_thread = CreateThread(NULL, 0, convertThread, cfs, 0, &id);
+
+ return 1;
+}
+
+static wchar_t errorStrW[2048];
+int convert_fileW(convertFileStructW *cfs)
+{
+ // clear the buffer on starting otherwise we may return an invalid error message
+ memset(&errorStrW, 0, sizeof(errorStrW));
+
+ if (cfs->destfile && cfs->sourcefile && !_wcsicmp(cfs->destfile, cfs->sourcefile))
+ {
+ cfs->error = getStringW(IDS_CONV_SRC_EQUALS_DEST,errorStrW,2048);
+ return 0;
+ }
+
+ AudioParameters parameters;
+ ifc_audiostream *decoder = decodeFile->OpenAudioBackground(cfs->sourcefile, &parameters);
+ cfs->bytes_total= (int)(parameters.sizeBytes?parameters.sizeBytes:-1);
+
+ if (!decoder)
+ {
+ switch(parameters.errorCode)
+ {
+ case API_DECODEFILE_UNSUPPORTED:
+ cfs->error = getStringW(IDS_CONV_DECODER_MISSING,errorStrW,2048);
+ return 0;
+ case API_DECODEFILE_NO_INTERFACE:
+ cfs->error = getStringW(IDS_CONV_INPUT_PLUGIN_NOT_SUPPORTING,errorStrW,2048);
+ return 0;
+ case API_DECODEFILE_NO_RIGHTS:
+ cfs->error = getStringW(IDS_CONV_DRM_DECODE_FAIL,errorStrW,2048);
+ return 0;
+ case API_DECODEFILE_FAIL_NO_WARN:
+ return 0;
+ default:
+ cfs->error = getStringW(IDS_CONV_ERROR_OPEN_FILE,errorStrW,2048);
+ return 0;
+ }
+ }
+
+ cfs->decoder=0;
+ cfs->convert_thread=0;
+ cfs->file_handle=0;
+ cfs->audio_coder=0;
+ cfs->encoder_mod=0;
+ cfs->bps=0;
+ cfs->channels=0;
+ cfs->sample_rate=0;
+
+ //find the encoding DLL
+ if (cfs->destformat[0] != mmioFOURCC('P', 'C', 'M', ' '))
+ {
+ HMODULE mod = NULL;
+ char * inifile = NULL;
+ if(cfs->destformat[6] == mmioFOURCC('I','N','I',' ')) inifile = (char*)cfs->destformat[7];
+ AudioCoder *ac = (AudioCoder *)getEncoder(parameters.bitsPerSample, parameters.channels, parameters.sampleRate, (int *) & cfs->destformat, 1, &mod, NULL,0, inifile);
+ if (!ac)
+ {
+ decodeFile->CloseAudio(decoder);
+ cfs->error = getStringW(IDS_CONV_ERROR_OPEN_ENCODER,errorStrW,2048);
+ return 0;
+ }
+ cfs->audio_coder = ac;
+ cfs->encoder_mod = mod;
+ }
+
+ cfs->killswitch = 0;
+ cfs->decoder = decoder;
+
+ cfs->bps = parameters.bitsPerSample;
+ cfs->channels = parameters.channels;
+ cfs->sample_rate = parameters.sampleRate;
+
+ //open destination file
+ HANDLE fh = CreateFileW(cfs->destfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if ( fh == INVALID_HANDLE_VALUE )
+ {
+ decodeFile->CloseAudio(decoder);
+ delete cfs->audio_coder;
+ cfs->audio_coder = 0;
+ FreeLibrary(cfs->encoder_mod);
+ cfs->encoder_mod = 0;
+ cfs->error = getStringW(IDS_CONV_ERROR_OPEN_DEST,errorStrW,2048);
+ return 0;
+ }
+ cfs->file_handle = fh;
+
+ DWORD id = 0;
+ cfs->convert_thread = CreateThread(NULL, 0, convertThreadW, cfs, 0, &id);
+
+ return 1;
+}
+
+int convert_file_test(convertFileStructW *cfs)
+{
+ // clear the buffer on starting otherwise we may return an invalid error message
+ errorStrW[0]=0;
+ AudioCoder *ac=0;
+ HMODULE mod=0;
+
+ if (cfs->destfile && cfs->sourcefile && !_wcsicmp(cfs->destfile, cfs->sourcefile))
+ {
+ cfs->error = getStringW(IDS_CONV_SRC_EQUALS_DEST,errorStrW,2048);
+ return 0;
+ }
+
+ AudioParameters parameters;
+ ifc_audiostream *decoder = decodeFile->OpenAudioBackground(cfs->sourcefile, &parameters);
+ cfs->bytes_total= (int)(parameters.sizeBytes?parameters.sizeBytes:-1);
+
+ if (!decoder)
+ {
+ switch(parameters.errorCode)
+ {
+ case API_DECODEFILE_UNSUPPORTED:
+ cfs->error = getStringW(IDS_CONV_DECODER_MISSING,errorStrW,2048);
+ return 0;
+ case API_DECODEFILE_NO_INTERFACE:
+ cfs->error = getStringW(IDS_CONV_INPUT_PLUGIN_NOT_SUPPORTING,errorStrW,2048);
+ return 0;
+ case API_DECODEFILE_NO_RIGHTS:
+ cfs->error = getStringW(IDS_CONV_DRM_DECODE_FAIL,errorStrW,2048);
+ return 0;
+ case API_DECODEFILE_FAIL_NO_WARN:
+ return 0;
+ default:
+ cfs->error = getStringW(IDS_CONV_ERROR_OPEN_FILE,errorStrW,2048);
+ return 0;
+ }
+ }
+
+ decodeFile->CloseAudio(decoder);
+ cfs->decoder=0;
+ cfs->convert_thread=0;
+ cfs->file_handle=0;
+ cfs->audio_coder=0;
+ cfs->encoder_mod=0;
+ cfs->bps=0;
+ cfs->channels=0;
+ cfs->sample_rate=0;
+
+ //find the encoding DLL
+ if (cfs->destformat[0] != mmioFOURCC('P', 'C', 'M', ' '))
+ {
+ char * inifile = NULL;
+ if(cfs->destformat[6] == mmioFOURCC('I','N','I',' ')) inifile = (char*)cfs->destformat[7];
+ ac = (AudioCoder *)getEncoder(parameters.bitsPerSample, parameters.channels, parameters.sampleRate, (int *) & cfs->destformat, 1, &mod, NULL,0, inifile);
+ if (!ac)
+ {
+ cfs->error = getStringW(IDS_CONV_ERROR_OPEN_ENCODER,errorStrW,2048);
+ return 0;
+ }
+ cfs->audio_coder = ac;
+ cfs->encoder_mod = mod;
+ }
+
+ cfs->killswitch = 0;
+ cfs->decoder = decoder;
+
+ cfs->bps = parameters.bitsPerSample;
+ cfs->channels = parameters.channels;
+ cfs->sample_rate = parameters.sampleRate;
+
+ //open destination file
+ HANDLE fh = CreateFileW(cfs->destfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if ( fh == INVALID_HANDLE_VALUE )
+ {
+ delete ac;
+ cfs->audio_coder = 0;
+ FreeLibrary(mod);
+ cfs->encoder_mod = 0;
+ cfs->error = getStringW(IDS_CONV_ERROR_OPEN_DEST,errorStrW,2048);
+ return 0;
+ }
+
+ delete ac;
+ cfs->audio_coder = 0;
+ FreeLibrary(mod);
+ cfs->encoder_mod = 0;
+ CloseHandle(fh);
+
+ return 1;
+}
+
+void convert_end(convertFileStruct *cfs)
+{
+ HANDLE handle = cfs->convert_thread;
+ cfs->killswitch = 1;
+ if (handle && handle != INVALID_HANDLE_VALUE)
+ {
+ WaitForSingleObject(handle, 20000);
+ CloseHandle(handle);
+ cfs->convert_thread = INVALID_HANDLE_VALUE;
+ }
+
+ delete(cfs->audio_coder);
+ cfs->audio_coder = 0;
+
+ HMODULE mod = cfs->encoder_mod;
+ if (mod)
+ {
+ FreeLibrary(mod);
+ cfs->encoder_mod = 0;
+ }
+}
+
+void convert_endW(convertFileStructW *cfs)
+{
+ HANDLE handle = cfs->convert_thread;
+ cfs->killswitch = 1;
+ if (handle && handle != INVALID_HANDLE_VALUE)
+ {
+ WaitForSingleObject(handle, 20000);
+ CloseHandle(handle);
+ cfs->convert_thread = INVALID_HANDLE_VALUE;
+ }
+
+ delete(cfs->audio_coder);
+ cfs->audio_coder = 0;
+
+ HMODULE mod = cfs->encoder_mod;
+ if (mod)
+ {
+ FreeLibrary(mod);
+ cfs->encoder_mod = 0;
+ }
+}
+
+void convert_enumfmts(converterEnumFmtStruct *cefs)
+{
+ // cefs->enumProc(cefs->user_data, ".WAV output", mmioFOURCC('W', 'A', 'V', ' '));
+ int destformat[8] = {0};
+ getEncoder(0, 0, 0, (int *)&destformat, 0, NULL, 0, cefs);
+}
+
+HWND convert_config(convertConfigStruct *ccs)
+{
+ HMODULE mod = NULL;
+ int destformat[8] = {ccs->format, };
+ char * inifile = NULL;
+ if(ccs->extra_data[6] == mmioFOURCC('I','N','I',' '))
+ inifile = (char*)ccs->extra_data[7];
+ HWND h = (HWND)getEncoder(0, 0, 0, (int *) & destformat, 0, &mod, ccs->hwndParent,0,inifile);
+ ccs->hwndConfig = h;
+ ccs->extra_data[0] = (intptr_t)mod;
+ return h;
+}
+
+void convert_config_end(convertConfigStruct *ccs)
+{
+ HMODULE mod = (HMODULE)ccs->extra_data[0];
+ DestroyWindow(ccs->hwndConfig);
+ if (mod) FreeLibrary(mod);
+}
+
+void convert_setPriority(convertSetPriority *csp)
+{
+ if (csp->cfs)
+ {
+ HANDLE handle = csp->cfs->convert_thread;
+ if (handle)
+ SetThreadPriority(handle, csp->priority);
+ else
+ {
+ //FUCKO> handle when separate process
+ }
+ }
+}
+
+void convert_setPriorityW(convertSetPriorityW *csp)
+{
+ if (csp->cfs)
+ {
+ HANDLE handle = (void *)csp->cfs->convert_thread;
+ if (handle)
+ SetThreadPriority(handle, csp->priority);
+ else
+ {
+ //FUCKO> handle when separate process
+ }
+ }
+}
+
+int convert_setConfigItem(convertConfigItem *cci) {
+ int ret = 0;
+ int destformat[8] = {(int)cci->format, };
+ HMODULE mod = NULL;
+ if (!cci->configfile) cci->configfile=INI_FILEA;
+ getEncoder(0,0,0, (int *) & destformat, 2, &mod, NULL,0,cci->configfile);
+ if(mod) {
+ int (*sci)(unsigned int outt, char *item, char *data, char *configfile);
+ *((void **)&sci) = GetProcAddress(mod, "SetConfigItem");
+ if(sci) {
+ ret = sci(cci->format,cci->item,cci->data,cci->configfile);
+ }
+ FreeLibrary(mod);
+ }
+ return ret;
+}
+
+int convert_getConfigItem(convertConfigItem *cci) {
+ int ret = 0;
+ int destformat[8] = {(int)cci->format, };
+ HMODULE mod = NULL;
+ if (!cci->configfile) cci->configfile=INI_FILEA;
+ getEncoder(0,0,0, (int *) & destformat, 2, &mod, NULL,0,cci->configfile);
+ if(mod) {
+ int (*gci)(unsigned int outt, char *item, char *data, int len, char *configfile);
+ *((void **)&gci) = GetProcAddress(mod, "GetConfigItem");
+ if(gci) {
+ ret = gci(cci->format,cci->item,cci->data,cci->len,cci->configfile);
+ }
+ FreeLibrary(mod);
+ }
+ return ret;
+}
diff --git a/Src/Winamp/creddlg.c b/Src/Winamp/creddlg.c
new file mode 100644
index 00000000..3c750ac2
--- /dev/null
+++ b/Src/Winamp/creddlg.c
@@ -0,0 +1,503 @@
+#include "./creddlg.h"
+
+
+#include <pshpack2.h>
+
+typedef struct _DLGTEMPLATEEX
+{
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ WORD menu;
+ WORD windowClass;
+ WCHAR title;
+ WORD pointsize;
+ WORD weight;
+ BYTE italic;
+ BYTE charset;
+ WCHAR typeface;
+} DLGTEMPLATEEX;
+
+#include <poppack.h>
+
+static const DLGTEMPLATEEX dlg_template = {1, 0xFFFF, 0,
+ WS_EX_DLGMODALFRAME | WS_EX_CONTROLPARENT | WS_EX_NOPARENTNOTIFY,
+ WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU,
+ 0, 0, 0, 0, 0, 0, 0, 0, };
+typedef struct _CREDDATA
+{
+
+ LPWSTR szUser;
+ INT cchUser;
+ LPWSTR szPassword;
+ INT cchPassword;
+ DWORD flags;
+ HBITMAP hbmp;
+ LPCWSTR greating;
+ INT retcode;
+
+} CREDDATA, *PCREDDATA;
+
+
+typedef struct _WNDLIST
+{
+ HWND hwndModal;
+ HWND *list;
+ INT count;
+ INT allocated;
+} WNDLIST;
+
+#define CREDCTRL L"CREDCTRL"
+
+#define BITMAP_HEIGHT 64
+#define DIALOG_HEIGHT 236
+#define DIALOG_WIDTH 316
+
+
+static LRESULT WINAPI WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static HWND CreateCredCtrl(const PCREDDATA pcd, INT x, INT y, INT cx, INT cy, HWND hwndParent, HINSTANCE hInstance, INT ctrlID);
+
+static void BlokedWndLst_Initialize(WNDLIST *plist, HWND hwndModal);
+static void BlokedWndLst_Add(WNDLIST *plist, HWND hwnd);
+static void BlokedWndLst_RemoveAll(WNDLIST *plist);
+static BOOL CALLBACK BlockedWndLst_EnumThread(HWND hwnd, LPARAM param);
+
+static HWND GetRoot(HWND hwnd )
+{
+ HWND hwndParent;
+ while ((WS_CHILD & GetWindowLongPtr(hwnd, GWL_STYLE)) && (hwndParent = GetParent(hwnd))) hwnd = hwndParent;
+ return hwnd;
+}
+
+static BOOL CALLBACK BlockedWndLst_EnumThread(HWND hwnd, LPARAM param)
+{
+ BlokedWndLst_Add((WNDLIST*)param, hwnd);
+ return TRUE;
+}
+
+static void BlokedWndLst_Initialize(WNDLIST *plist, HWND hwndModal)
+{
+ plist->hwndModal = GetRoot(hwndModal);
+ plist->count = 0;
+ plist->allocated = 0;
+ plist->list = NULL;
+
+ EnumThreadWindows(GetCurrentThreadId(), BlockedWndLst_EnumThread, (LPARAM)plist);
+
+}
+
+
+static void BlokedWndLst_Add(WNDLIST *plist, HWND hwnd)
+{
+ int i;
+ if (!hwnd || hwnd == plist->hwndModal || !IsWindowVisible(hwnd) || !IsWindowEnabled(hwnd)) return;
+ hwnd = GetRoot(hwnd);
+ if (!hwnd || hwnd == plist->hwndModal || !IsWindowVisible(hwnd) || !IsWindowEnabled(hwnd)) return;
+
+ for (i = 0; i < plist->count; i++) if (hwnd == plist->list[i]) return;
+
+ if (plist->count == plist->allocated)
+ {
+ plist->allocated += 8;
+ plist->list = realloc(plist->list, plist->allocated*sizeof(HWND));
+ }
+ if (!plist->list) return;
+ plist->list[plist->count] = hwnd;
+ plist->count++;
+ EnableWindow(hwnd, FALSE);
+}
+
+static void BlokedWndLst_RemoveAll(WNDLIST *plist)
+{
+ int i;
+ for ( i = 0; i < plist->count; i++) EnableWindow(plist->list[i], TRUE);
+ if (plist->list) free(plist->list);
+}
+
+
+
+
+static HWND CreateCredCtrl(const PCREDDATA pcd, INT x, INT y, INT cx, INT cy, HWND hwndParent, HINSTANCE hInstance, INT ctrlID)
+{
+ WNDCLASSW wndclass;
+
+ if (!GetClassInfoW(hInstance, CREDCTRL, &wndclass))
+ {
+ wndclass.lpszClassName = CREDCTRL;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
+ wndclass.hCursor = NULL;
+ wndclass.hIcon = NULL;
+ wndclass.hInstance = hInstance;
+ wndclass.lpszMenuName = NULL;
+ wndclass.style = 0x0;
+ wndclass.cbClsExtra = 0x0;
+ wndclass.cbWndExtra = sizeof(CREDDATA*);
+
+ if (!RegisterClassW(&wndclass)) return NULL;
+ }
+
+ return CreateWindowExW(WS_EX_CONTROLPARENT | WS_EX_NOPARENTNOTIFY, CREDCTRL, pcd->greating,
+ WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD,
+ x, y, cx, cy, hwndParent, (HMENU)(INT_PTR)ctrlID, hInstance, (LPVOID)pcd);
+}
+typedef struct _CONTROLS
+{
+ INT id;
+ LPCWSTR pClass;
+ DWORD style;
+ DWORD exStyle;
+ LPCWSTR pTitle;
+}CONTROLS;
+
+#define IDC_CREDCTRL 1101
+#define IDC_BMP_LOGO 1001
+#define IDC_LBL_GREATING 1002
+#define IDC_LBL_USERNAME 1003
+#define IDC_LBL_PASSWORD 1004
+#define IDC_EDT_USERNAME 1005
+#define IDC_EDT_PASSWORD 1006
+
+#define BASE_WND_STYLE WS_CHILD | WS_VISIBLE
+
+static CONTROLS controls[] =
+{
+ {IDC_BMP_LOGO, L"STATIC", BASE_WND_STYLE | SS_BITMAP | SS_REALSIZEIMAGE, WS_EX_NOPARENTNOTIFY, NULL },
+ {IDC_LBL_GREATING, L"STATIC", BASE_WND_STYLE, WS_EX_NOPARENTNOTIFY, NULL },
+ {IDC_LBL_USERNAME, L"STATIC", BASE_WND_STYLE, WS_EX_NOPARENTNOTIFY, L"User name:" },
+ {IDC_EDT_USERNAME, L"EDIT", BASE_WND_STYLE | WS_TABSTOP, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, NULL },
+ {IDC_LBL_PASSWORD, L"STATIC", BASE_WND_STYLE, WS_EX_NOPARENTNOTIFY, L"Password:" },
+ {IDC_EDT_PASSWORD, L"EDIT", BASE_WND_STYLE | WS_TABSTOP | ES_PASSWORD, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, NULL },
+ {IDOK, L"BUTTON", BASE_WND_STYLE | BS_DEFPUSHBUTTON | WS_TABSTOP, WS_EX_NOPARENTNOTIFY, L"Ok" },
+ {IDCANCEL, L"BUTTON", BASE_WND_STYLE | WS_TABSTOP, WS_EX_NOPARENTNOTIFY, L"Cancel" },
+};
+
+
+//// skinning
+#include "../winamp/wa_ipc.h"
+#include "../winamp/wa_dlg.h"
+
+
+typedef HRESULT (__stdcall *UX_SETWINDOWTHEME)(HWND, LPCWSTR, LPCWSTR);
+
+
+static LRESULT OnCreate(HWND hwnd, LPCREATESTRUCTW pcs)
+{
+ int i;
+ HFONT hf;
+ CREDDATA *pcd;
+ HMODULE uxdll;
+ UX_SETWINDOWTHEME uxSetWindowTheme = NULL;
+
+ pcd = (CREDDATA*)pcs->lpCreateParams;
+
+ SetLastError(0);
+ if (!SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG)(LONG_PTR)pcd) && GetLastError()) return -1;
+
+
+ hf = GetStockObject(DEFAULT_GUI_FONT);
+ if (CDS_SKINDIALOG & pcd->flags)
+ {
+ uxdll = LoadLibrary("uxtheme.dll");
+ uxSetWindowTheme = (uxdll) ? (UX_SETWINDOWTHEME)GetProcAddress(uxdll, "SetWindowTheme") : NULL;
+ if (uxSetWindowTheme) uxSetWindowTheme(hwnd, L" ", L" ");
+ }else uxdll = NULL;
+
+ for (i = 0; i < sizeof(controls)/sizeof(controls[0]); i++)
+ {
+ switch(controls[i].id)
+ {
+ case IDC_BMP_LOGO:
+ controls[i].style &= ~WS_VISIBLE;
+ if (pcd->hbmp) controls[i].style |= WS_VISIBLE;
+ break;
+ case IDC_LBL_GREATING:
+ controls[i].pTitle = pcs->lpszName;
+ break;
+ case IDC_EDT_USERNAME:
+ controls[i].exStyle &= ~WS_EX_CLIENTEDGE;
+ if (0 == (CDS_SKINDIALOG & pcd->flags)) controls[i].exStyle |= WS_EX_CLIENTEDGE;
+ controls[i].pTitle = (CDS_USEUSERNAME & pcd->flags) ? pcd->szUser : NULL;
+ break;
+ case IDC_EDT_PASSWORD:
+ controls[i].exStyle &= ~WS_EX_CLIENTEDGE;
+ if (0 == (CDS_SKINDIALOG & pcd->flags)) controls[i].exStyle |= WS_EX_CLIENTEDGE;
+ controls[i].pTitle = (CDS_USEPASSWORD & pcd->flags) ? pcd->szPassword : NULL;
+ break;
+ case IDOK:
+ case IDCANCEL:
+ controls[i].style &= ~BS_OWNERDRAW;
+ if (CDS_SKINDIALOG & pcd->flags) controls[i].style |= BS_OWNERDRAW;
+ break;
+ }
+
+ HWND hwndCtrl = CreateWindowExW(controls[i].exStyle, controls[i].pClass, controls[i].pTitle, controls[i].style,
+ 0, 0, 0, 0, hwnd, (HMENU)(INT_PTR)controls[i].id, NULL, NULL);
+ if (IsWindow(hwndCtrl))
+ {
+ SendMessageW(hwndCtrl, WM_SETFONT, (WPARAM)hf, FALSE);
+ if ((CDS_SKINDIALOG & pcd->flags) && uxSetWindowTheme) uxSetWindowTheme(hwndCtrl, L" ", L" ");
+ }
+ }
+
+ if (pcd->hbmp) SendDlgItemMessage(hwnd, IDC_BMP_LOGO, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)pcd->hbmp);
+
+ if (uxdll) FreeLibrary(uxdll);
+ pcd->retcode = -4; //- we are running
+ return 0;
+}
+
+static void LayoutWindows(HWND hwnd)
+{
+ int i;
+ RECT rc, ri;
+
+ GetClientRect(hwnd, &rc);
+
+ for (i = 0; i < sizeof(controls)/sizeof(controls[0]); i++)
+ {
+ HWND hwndCtrl = GetDlgItem(hwnd, controls[i].id);
+ switch(controls[i].id)
+ {
+ case IDC_BMP_LOGO:
+ SetRect(&ri, rc.left, rc.top, rc.right, rc.top + BITMAP_HEIGHT);
+ if (WS_VISIBLE & GetWindowLongPtr(hwndCtrl, GWL_STYLE)) rc.top = ri.bottom + 2;
+ InflateRect(&rc, -8, -8);
+ break;
+
+ case IDC_LBL_GREATING:
+ SetRect(&ri, rc.left, rc.top, rc.right, rc.top + 36);
+ rc.top = ri.bottom + 12;
+ break;
+ case IDC_LBL_USERNAME:
+ case IDC_LBL_PASSWORD:
+ SetRect(&ri, rc.left, rc.top, rc.left + 84, rc.top + 20);
+ break;
+ case IDC_EDT_USERNAME:
+ case IDC_EDT_PASSWORD:
+ ri.left = rc.left + 92;
+ SetRect(&ri, ri.left, rc.top, rc.right, rc.top + 20);
+ rc.top = ri.bottom + 8;
+ break;
+ case IDOK:
+ SetRect(&ri, rc.right - 150, rc.bottom - 22, rc.right - 78, rc.bottom);
+ break;
+ case IDCANCEL:
+ SetRect(&ri, rc.right - 72, rc.bottom - 22, rc.right, rc.bottom);
+ break;
+ }
+ SetWindowPos(hwndCtrl, NULL, ri.left, ri.top, ri.right - ri.left, ri.bottom - ri.top, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+}
+static LRESULT WINAPI WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PCREDDATA pcd;
+ pcd = (PCREDDATA)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if(pcd && (CDS_SKINDIALOG & pcd->flags))
+ {
+ INT_PTR a;
+ a = WADlg_handleDialogMsgs(hwnd, uMsg, wParam, lParam);
+ if (a) return a;
+ }
+ switch(uMsg)
+ {
+ case WM_CREATE: return OnCreate(hwnd, (LPCREATESTRUCTW) lParam);
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDOK:
+ if (pcd)
+ {
+ pcd->retcode = 1;
+ SetLastError(0);
+ GetWindowTextW(GetDlgItem(hwnd, IDC_EDT_USERNAME), pcd->szUser, pcd->cchUser);
+ if (GetLastError()) pcd->retcode = -1;
+ GetWindowTextW(GetDlgItem(hwnd, IDC_EDT_PASSWORD), pcd->szPassword, pcd->cchPassword);
+ if (GetLastError()) pcd->retcode = -1;
+ }
+ case IDCANCEL:
+ if (pcd && IDCANCEL == LOWORD(wParam)) pcd->retcode = 0;
+ DestroyWindow(GetParent(hwnd));
+ return 0;
+ }
+ break;
+ case WM_CLOSE:
+ if (pcd) pcd->retcode = 0;
+ DestroyWindow(GetParent(hwnd));
+ break;
+ case WM_WINDOWPOSCHANGED:
+ LayoutWindows(hwnd);
+ return 0;
+ case WM_PAINT:
+ if(pcd && (CDS_SKINDIALOG & pcd->flags))
+ {
+ int tab[] = { IDC_EDT_USERNAME | DCW_SUNKENBORDER , IDC_EDT_PASSWORD | DCW_SUNKENBORDER};
+ WADlg_DrawChildWindowBorders(hwnd, tab, 2);
+ }
+ break;
+ case WM_ERASEBKGND:
+ if(pcd && (CDS_SKINDIALOG & pcd->flags))
+ {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ FillRect((HDC)wParam, &rc, (HBRUSH) SendMessage(hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd));
+ return 1;
+ }
+ break;
+ }
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_WINDOWPOSCHANGED:
+ {
+ RECT rc;
+ HWND hwndChild;
+ hwndChild = FindWindowExW(hwnd, NULL, CREDCTRL, NULL);
+ if (hwndChild)
+ {
+ GetClientRect(hwnd, &rc);
+ SetWindowPos(hwndChild, NULL, 0,0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ }
+ break;
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ case IDOK:
+ {
+ HWND hwndChild;
+ hwndChild = FindWindowExW(hwnd, NULL, CREDCTRL, NULL);
+ if (hwndChild) SendMessage(hwndChild, WM_CLOSE, 0, 0L);
+ }
+ return TRUE;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+INT ShowCredentialDialog(const WACREDDLG *pcd)
+{
+ HWND hwnd;
+ MSG msg;
+ WNDLIST list;
+ CREDDATA cd;
+ embedWindowState embedWnd = {0};
+
+ if (!pcd || pcd->size != sizeof(WACREDDLG) || !pcd->szUser || !pcd->cchUser || !pcd->szPassword || !pcd->cchPassword) return -1;
+
+ ZeroMemory(&cd, sizeof(CREDDATA));
+
+ cd.szUser = pcd->szUser;
+ cd.szPassword = pcd->szPassword;
+ cd.cchUser = pcd->cchUser;
+ cd.cchPassword = pcd->cchPassword;
+ cd.flags = pcd->flags;
+ cd.greating = pcd->greating;
+ cd.hbmp = pcd->hbmp;
+ cd.retcode = -1;
+
+ if ((CDS_SKINDIALOG & pcd->flags) && pcd->hwndWA)
+ {
+ ZeroMemory(&embedWnd, sizeof(embedWindowState));
+ SetRect(&embedWnd.r, 0, 0, 1, 1);
+ embedWnd.flags = EMBED_FLAGS_NORESIZE | EMBED_FLAGS_NOTRANSPARENCY | EMBED_FLAGS_NOWINDOWMENU;
+ hwnd = (HWND)SendMessage(pcd->hwndWA, WM_WA_IPC, (LPARAM)&embedWnd, IPC_GET_EMBEDIF);
+ }
+ else hwnd = NULL;
+
+ if(!IsWindow(hwnd)) hwnd = CreateDialogIndirect(GetModuleHandleW(NULL), (LPCDLGTEMPLATEW)&dlg_template, pcd->hwndParent, DialogProc);
+
+ if (IsWindow(hwnd))
+ {
+ RECT rw;
+ INT fx, fy;
+
+ HWND hwndActive = GetActiveWindow();
+
+ SetWindowTextW(hwnd, pcd->title);
+
+ GetClientRect(hwnd, &rw);
+
+ HWND hwndCtrl = CreateCredCtrl(&cd, 0, 0, rw.right, rw.bottom, hwnd, GetModuleHandleW(NULL), IDC_CREDCTRL);
+
+ if ((CDS_SKINDIALOG & pcd->flags))
+ {
+ SetWindowPos(hwnd, NULL, 0, 0, 100, 100, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
+ GetWindowRect(hwnd, &rw);
+ fx = rw.right - rw.left;
+ fy = rw.bottom - rw.top;
+ GetWindowRect(hwndCtrl, &rw);
+ fx -= (rw.right - rw.left);
+ fy -= (rw.bottom - rw.top);
+ }
+ else
+ {
+ GetWindowRect(hwnd, &rw);
+ fx = rw.right - rw.left;
+ fy = rw.bottom - rw.top;
+ GetClientRect(hwnd, &rw);
+ fx -= (rw.right - rw.left);
+ fy -= (rw.bottom - rw.top);
+ }
+
+ if (pcd->hwndParent) GetWindowRect(pcd->hwndParent, &rw);
+ else GetWindowRect(GetDesktopWindow(), &rw);
+
+ SetWindowPos(hwnd, HWND_TOP,
+ rw.left + (rw.right - rw.left - (DIALOG_WIDTH + fx)) / 2,
+ rw.top + (rw.bottom - rw.top - (DIALOG_HEIGHT + fy - ((pcd->hbmp) ? 0 : BITMAP_HEIGHT))) / 2,
+ DIALOG_WIDTH + fx,
+ (DIALOG_HEIGHT + fy - ((pcd->hbmp) ? 0 : BITMAP_HEIGHT)),
+ 0);
+
+ ShowWindow(hwnd, SW_SHOW);
+
+ if (CDS_APPMODAL & pcd->flags) BlokedWndLst_Initialize(&list, hwnd);
+ else if (pcd->hwndParent) EnableWindow(GetRoot(pcd->hwndParent), FALSE);
+
+ BOOL result;
+ while(0 != (result = GetMessage(&msg, NULL, 0, 0)) && -1 != result)
+ {
+ if (!IsDialogMessage(hwnd, &msg))
+ {
+ if ((CDS_APPMODAL & pcd->flags) && WM_TIMER != msg.message) BlokedWndLst_Add(&list, msg.hwnd);
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ if (CDS_APPMODAL & pcd->flags) BlokedWndLst_RemoveAll(&list);
+ else if (pcd->hwndParent) EnableWindow(GetRoot(pcd->hwndParent), TRUE);
+
+ if (hwndActive) SetActiveWindow(hwndActive);
+
+ if (!result)
+ {
+ if (-4 == cd.retcode)
+ {
+ PostQuitMessage((INT)msg.wParam);
+ }
+ }
+ }
+ if (-4 == cd.retcode) cd.retcode = 0;
+ return cd.retcode;
+}
diff --git a/Src/Winamp/creddlg.h b/Src/Winamp/creddlg.h
new file mode 100644
index 00000000..e1508358
--- /dev/null
+++ b/Src/Winamp/creddlg.h
@@ -0,0 +1,78 @@
+#ifndef NULLSOFT_CREDAENTIAL_DIALOG_HEADER
+#define NULLSOFT_CREDAENTIAL_DIALOG_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+
+#include <windows.h>
+
+#define CDS_USEUSERNAME 0x0001 // szUser will be used to prepopulate user name field
+#define CDS_USEPASSWORD 0x0002 // szPassword will be used to prepopulate user name field
+#define CDS_SKINDIALOG 0x0004 // Dialog will be skinned (requires hwndWA)
+#define CDS_APPMODAL 0x0008 // Dialog will be application(thread) modal.
+
+typedef struct _WACREDDLG
+{
+ int size; // sizeof(WACREDDLG)
+ HWND hwndParent; // parents HWND (passing NULL can be bad idea especially if not CDS_APPMODAL)
+ LPWSTR szUser; // pointer to the user name buffer
+ INT cchUser; // size of the user name buffer in characters
+ LPWSTR szPassword; // pointer to the password buffer
+ INT cchPassword; // size of the password buffer in characters
+ DWORD flags; // any combination of CDS_XXX
+ LPCWSTR title; // title of the dialog
+ HBITMAP hbmp; // bitmap to display (can be NULL - this will make dialog smaller)
+ LPCWSTR greating; // text to display on top of user name filed
+ HWND hwndWA; // only if you want skinning handle to the Winamp main window
+
+} WACREDDLG, *PWACREDDLG;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+INT ShowCredentialDialog(const WACREDDLG *pcd); // displays dialog. Returns: error(-1), canceled(0), ok(1)
+
+#ifdef __cplusplus
+}
+#endif
+
+//Expample
+ //wchar_t usr[64], pwd[64];
+ //WACREDDLG dlg;
+ //ZeroMemory(&dlg, sizeof(WACREDDLG));
+ //dlg.size = sizeof(WACREDDLG);
+ //dlg.hwndWA = plugin.hwndParent;
+ //dlg.hwndParent = g_hwnd;
+ //dlg.flags = CDS_APPMODAL | CDS_USEPASSWORD | CDS_USEUSERNAME | CDS_SKINDIALOG;
+ //dlg.title = L"User Credentials";
+ //dlg.greating = L"Resource that you trying to access requires authentification.\nPlease enter credentials.";
+ //dlg.szUser = usr;
+ //dlg.cchUser = 64;
+ //dlg.szPassword = pwd;
+ //dlg.cchPassword = 64;
+ //dlg.hbmp = (HBITMAP)LoadImage(NULL, "C:\\cred_banner.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
+
+ //StringCchCopyW(usr, 64, L"testuser");
+ //StringCchCopyW(pwd, 64, L"12345");
+
+ //
+ //
+ //wchar_t buffer[256];
+
+ //switch(ShowCredentialDialog(&dlg))
+ //{
+ // case -1: StringCchCopyW(buffer, 256, L"Error duaring initialization."); break;
+ // case 0: StringCchCopyW(buffer, 256, L"Canceled by user."); break;
+ // default: StringCchPrintfW(buffer, 256, L"Userdata:\nUser name:\t\t%s\nPassword:\t\t%s", usr, pwd); break;
+ //
+ //}
+
+ //if (dlg.hbmp) DeleteObject(dlg.hbmp);
+// Example end
+
+
+
+#endif /*NULLSOFT_CREDAENTIAL_DIALOG_HEADER*/ \ No newline at end of file
diff --git a/Src/Winamp/credits.cpp b/Src/Winamp/credits.cpp
new file mode 100644
index 00000000..68f31083
--- /dev/null
+++ b/Src/Winamp/credits.cpp
@@ -0,0 +1,350 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description: Unused (left for reference)
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+
+#if 0
+#ifndef NETSCAPE
+#include <math.h>
+
+static void RenderInit(HWND hwnd);
+static void RenderQuit(HWND hwnd);
+static int RenderFrame(HWND hwnd);
+
+static int w_width, w_height,w_offs;
+static volatile int killsw;
+
+void About2_Kill()
+{
+ killsw=1;
+}
+
+void About2_Start(HWND hwndParent)
+{
+ RECT r;
+ killsw=0;
+ Sleep(100);
+ GetWindowRect(hwndParent,&r);
+ w_width =r.right-r.left;
+ w_height=((r.bottom-r.top)); // *3/4
+ w_offs=0;//((r.bottom-r.top)*1)/9;
+ w_width += 3;
+ w_width &= ~3;
+ RenderInit(hwndParent);
+ while (!killsw)
+ {
+ int rtime=GetTickCount();
+ RenderFrame(hwndParent);
+ rtime = GetTickCount()-rtime;
+ if (rtime > 16) rtime=16;
+ Sleep(16-rtime);
+ }
+ RenderQuit(hwndParent);
+}
+
+static HFONT hFont, hOldFont;
+static int th,linepos,fadepos,egg_pos;
+static HDC bm_hdc, egg_hdc;
+static HBITMAP bm_bitmap, bm_oldbm, egg_bm, egg_oldbm;
+
+static int egg_dobg=0, egg_hacko;
+
+static void RenderInit(HWND hwnd)
+{
+ RECT r = {0,0,w_width,w_height+40};
+ TEXTMETRIC tm;
+
+ egg_dobg=0;
+
+ egg_hacko=eggstat;
+ if (egg_hacko) egg_oldbm=(HBITMAP)SelectObject(egg_hdc=CreateCompatibleDC(NULL),egg_bm=LoadBitmap(hMainInstance,MAKEINTRESOURCE(IDB_CAT)));
+
+ bm_hdc=CreateCompatibleDC(egg_hacko?egg_hdc:NULL);
+ bm_bitmap=CreateCompatibleBitmap(egg_hacko?egg_hdc:bm_hdc,r.right,r.bottom);
+ bm_oldbm=(HBITMAP)SelectObject(bm_hdc,bm_bitmap);
+
+ BitBlt(bm_hdc,0,0,r.right,r.bottom,bm_hdc,0,0,BLACKNESS);
+ SetMapMode(bm_hdc,MM_TEXT);
+ hFont=CreateFont(16,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,
+ DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DRAFT_QUALITY,DEFAULT_PITCH|FF_DONTCARE,"Times New Roman");
+ hOldFont=(HFONT)SelectObject(bm_hdc,hFont);
+ GetTextMetrics(bm_hdc,&tm);
+ th=tm.tmHeight;
+ if (th > 39) th = 39;
+ SetTextColor(bm_hdc,RGB(255,255,255));
+ SetBkColor(bm_hdc,RGB(0,0,0));
+ linepos=6;
+ fadepos=256;
+}
+
+static void RenderQuit(HWND hwnd)
+{
+ SelectObject(bm_hdc,hOldFont);
+ SelectObject(bm_hdc,bm_oldbm);
+ DeleteObject(bm_bitmap);
+ DeleteDC(bm_hdc);
+ DeleteObject(hFont);
+ if (egg_oldbm || egg_hdc)
+ {
+ SelectObject(egg_hdc,egg_oldbm);
+ DeleteObject(egg_bm);
+ DeleteDC(egg_hdc);
+ egg_bm=NULL;
+ egg_hdc=NULL;
+ }
+}
+
+typedef struct
+{
+ char *col1,*col2;
+} t_line;
+
+
+#define BLINE {"",}
+static t_line text_lines[] =
+{
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ { APP_NAME " [tm]",},
+ { "———————————————",},
+ { "Copyright © 1997-2000 - Nullsoft",},
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ {"CREDITS",},
+ BLINE,
+ {"Unit One",},
+ {"——————",},
+ {"PRODUCTION AND DESIGN","Justin Frankel"},
+ BLINE,
+ {"CREW","Tom Pepper"},
+ {"","Robert Lord"},
+ {"","Ian Rogers"},
+ {"","Steve Gedikian"},
+ {"","Brennan Underwood"},
+ BLINE,
+ {"MIKMOD PLUG-IN","Jake Stine"},
+ BLINE,
+ {"SPLASH SCREEN","Christian Lundquist"},
+ BLINE,
+ BLINE,BLINE,BLINE,BLINE,
+ {"Unit Two",},
+ {"——————",},
+ {"STUNT COORDINATOR","Jean-Hugues Royer"},
+ BLINE,
+ {"STUNTS","Jay Downing"},
+ {"","Tim Russell"},
+ {"","Rob Markovic"},
+ {"","Peter A. DeNitto"},
+ {"","Colten Edwards"},
+ {"","Mike Wickenden"},
+ {"","Peter Hollandare"},
+ {"","Nicholas Head"},
+ {"","Craig Vallelunga"},
+ {"","Jason Reimer"},
+ {"","Kenric Tam"},
+ BLINE,
+ {"PUPPETEER","Rob 'Wonderful"},
+ {""," Wawb' Bresner"},
+ BLINE,
+ {"ICON TRAINERS", "Torsten Daeges"},
+ {"","Ben Lowery"},
+ BLINE,
+ {"LLAMA WRANGLER","Tom Pepper"},
+ BLINE,
+ {"ANIMAL TRAINER","Nova Hall"},
+ BLINE,
+ {"ASSISTANT TO FIFI","Robert Lord"},
+ BLINE,
+ {"WATCHING ANIME","Ted Cooper"},
+ BLINE,
+ {"NUDE SCENES","Charlie Hinz"},
+ BLINE,
+ {"KARATE SCENE","Dan Khamsing"},
+ {"COORDINATORS","Thanh Tran"},
+ BLINE,
+ {"TOPLESS DANCER","Jenn Spencer"},
+ BLINE,
+ {"HAIR AND MAKEUP DESIGN","Brennan Underwood"},
+ {"FOR MR. FRANKEL",""},
+ BLINE,
+ {"MYSTERY LADY","Al"},
+ BLINE,
+ {"COSTUME DESIGNER","Casey Scales"},
+ BLINE,
+ {"PRIME NUMBERS","Cap Petschulat"},
+ BLINE,
+ {"BIG BIZ EXPLOITER","Kenneth Chen"},
+ BLINE,
+ {"RESIDENT DENTIST","Meng"},
+ BLINE,
+ {"NITE FIEND","David Pui"},
+ BLINE,
+ {"PYROTECHNICS","Jaben Cargman"},
+ BLINE,
+ {"CATERING","Charles H. Frankel"},
+ {"","Kathleen Blake-Frankel"},
+ {"","Loretta Spinster"},
+ BLINE,
+ {"BEER","Peregrine Computing",},
+ BLINE,
+ {"ELEVATOR MUSIC","The Robies",},
+ BLINE,
+ {"GAFFER","Adara Frankel"},
+ BLINE,
+ {"BEST BOY","Paul Garcia"},
+ BLINE,
+ {"KEY GRIP","Josh Marso"},
+ BLINE,
+ {"GRIPS","Ryan Underwood"},
+ {"","Alex Derbes"},
+ {"","Mike Wickenden"},
+ BLINE,
+ {"OFTEN ANNOYING","Angelo Sotira"},
+ {"PUBLIC MANIPULATION","Andrew Smith"},
+ BLINE,
+ {"CRASH TEST DUMMY","Alun Wile"},
+ BLINE,
+ {"GENETIC ENGINEERING","Jawed Karim"},
+ BLINE,
+ {"BREAST EXAMINER","Shaun Curtis"},
+ BLINE,
+ {"TRANSLATOR","Alix Reyes"},
+ BLINE,
+ {"WARFARE TECH","Thanh Tran"},
+ BLINE,
+ {"SHIPBUILDING", "Gary Calpo"},
+ BLINE,
+ {"BAD HUMOR","Adara Blake"},
+ BLINE,
+ {"ANAL PROBER","Dave \"Lestat\" Wile"},
+ BLINE,
+ {"CLEARANCES","Franc Zijderveld"},
+ BLINE,
+ {"JANITORS","Ian Lyman"},
+ {"","Andrew McCann"},
+ BLINE,
+ {"PLASTERER","Dmitry Boldyrev"},
+ BLINE,
+ {"CARPENTRY","Marc Pirotte"},
+ {"","Dána M. Epp"},
+ {"","Graham Batty"},
+ {"","John Stephens"},
+ {"","Jon Lippincott"},
+ {"","Doug Mealing"},
+ {"","Jessica Wirna"},
+ {"","Chris Fitzpatrick"},
+ BLINE,
+ {"EXTRAS","Bill Harper"},
+ {"","Dana Dahlstrom"},
+ {"","Allen Anderson"},
+ {"","Diane Downard"},
+ {"","Tima Kunayev"},
+ BLINE,
+ {"STAND-INS","Ryan Houle"},
+ {"","Bryan Burton"},
+ {"","Justin Derbes"},
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ {"Special Thanks:",},
+ BLINE,
+ {"The City of Detroit, Michigan",},
+ {"US Department of Justice",},
+ {"Dallas Square-Dancing Hall of Fame",},
+ {"Lighthouse Communications",},
+ {"Samsung USA",},
+ {"Phoenix International Raceway",},
+ {"San Diego Zoo",},
+ {"Audi America",},
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ {"Filmed in Amazing Technicolor®",},
+ BLINE,BLINE,
+ {"Soundtrack available on Fuckit Records",},
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ {"—————————————————",},
+ {"No animals were harmed in the filming",},
+ {"and/or production of this product",},
+ {"—————————————————",},
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ {"© MM Nullsoft Inc.",},
+ {"http://www.nullsoft.com/",},
+ BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,BLINE,
+ {NULL,NULL}
+};
+
+static int RenderFrame(HWND hwnd)
+{
+ static int y;
+ if (fadepos < 256)
+ {
+ fadepos-=2;
+ if (fadepos <= 0)
+ {
+ fadepos=256;
+ y=0;
+ BitBlt(bm_hdc,0,0,w_width,w_height+th+1,bm_hdc,
+ 0,0,BLACKNESS);
+ }
+ }
+ else if (!y)
+ {
+ RECT r={0,w_height,w_width,w_height+th};
+ y=th;
+
+ if (!text_lines[linepos].col1)
+ {
+ egg_pos=0;
+ egg_dobg=0;
+ linepos=0;
+ fadepos=255;
+ }
+ else if (1)
+ {
+ if (egg_hacko) {
+ int h=(th*80)/w_width,h2,h3;
+ h2=h;
+ if (h2+egg_pos >= 60)
+ {
+ h2=60-egg_pos;
+ h-=h2;
+ h3=(h2*w_width)/80;
+ } else h=0;
+ if (h2) StretchBlt(bm_hdc,0,w_height,w_width,th+1,egg_hdc, 0,egg_pos,80, h2, egg_dobg?SRCCOPY:BLACKNESS);
+ egg_pos+=h2;
+ if (egg_pos>=60) { egg_pos=0; egg_dobg=!egg_dobg; }
+ if (h) StretchBlt(bm_hdc,0,w_height+h3,w_width,th+1,egg_hdc, 0,egg_pos,80, h, egg_dobg?SRCCOPY:BLACKNESS);
+ egg_pos+=h;
+ SetBkMode(bm_hdc,TRANSPARENT);
+ }
+ if (!text_lines[linepos].col2)
+ DrawText(bm_hdc,text_lines[linepos++].col1,-1,&r,DT_CENTER);
+ else
+ {
+ RECT r1={0,w_height,w_width/2 - 10,w_height+th};
+ RECT r2={w_width/2 + 10,w_height,w_width,w_height+th};
+ DrawText(bm_hdc,text_lines[linepos].col1,-1,&r1,DT_RIGHT);
+ DrawText(bm_hdc,text_lines[linepos++].col2,-1,&r2,DT_LEFT);
+ }
+ }
+ BitBlt(bm_hdc,0,0,w_width,w_height+th+1,bm_hdc,
+ 0,1,SRCCOPY);
+ }
+ else
+ {
+ y--;
+ BitBlt(bm_hdc,0,0,w_width,w_height+th+1,bm_hdc,
+ 0,1,SRCCOPY);
+ }
+
+ {
+ HDC hdc=GetDC(hwnd);
+ BitBlt(hdc,0,w_offs,w_width,w_height,bm_hdc,0,0,SRCCOPY);
+ ReleaseDC(hwnd,hdc);
+ }
+ return 0;
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/Src/Winamp/creditsrend.c b/Src/Winamp/creditsrend.c
new file mode 100644
index 00000000..7b8d176e
--- /dev/null
+++ b/Src/Winamp/creditsrend.c
@@ -0,0 +1,935 @@
+#include "main.h"
+
+#define LAND_SIZE 500
+#define LAND_DIV 12
+
+extern void plTextPutStrW(pl_Cam* cam, pl_sInt x, pl_sInt y, pl_Float z, pl_uChar color, const wchar_t* string);
+static void setup_materials(pl_Mat **mat, unsigned char *pal);
+static pl_Obj *setup_landscape(float size, int div, pl_Mat *m);
+static pl_Mat *mat[7];
+static pl_Cam *cam;
+static pl_Obj *land,*object[8], *lightobject,*lightobject2, *billboard, *teamobject;
+static pl_Spline spline;
+static pl_Float splineTime;
+static pl_Light *light;
+static unsigned int prevtime;
+static pl_Texture *grndtex, *watex, *walogotex, *teamtex;
+static char *teamtexbase;
+static int displaycredits=1;
+static float keys1[8*5];
+
+static void initspline(int i)
+{
+ spline.keys[i*5+0] = (pl_Float)(warand()%320)-160;
+ spline.keys[i*5+1] = (pl_Float)(warand()%110)+15;
+ spline.keys[i*5+2] = (pl_Float)(warand()%320)-160;
+ spline.keys[i*5+3] = (pl_Float)(warand()%32)/32.0f;
+ spline.keys[i*5+4] = (pl_Float)(warand()%32)/32.0f;
+}
+
+static unsigned int m_creditspos;
+static int m_creditspos_frames;
+static int m_lastpos;
+static int rpoo=1;
+
+void render_togglecredits()
+{
+ displaycredits=!displaycredits;
+}
+
+void render_init(int w, int h, char *pal)
+{
+ int i;
+ float wd;
+ int ishigh=!!(GetAsyncKeyState(VK_SHIFT)&GetAsyncKeyState(VK_MENU)&0x8000);
+ rpoo=1;
+ splineTime=0.0;
+ spline.tens = (pl_Float)-0.6;
+ spline.keyWidth = 5;
+ spline.numKeys = 8;
+
+ spline.keys = keys1;
+ for (i = 0; i < spline.numKeys; i ++)
+ {
+ initspline(i);
+ }
+
+ cam = plCamCreate(w,h,1.0,120.0,NULL,NULL);
+ cam->ScreenWidth=w;
+ cam->ScreenHeight=h;
+ cam->ClipTop = 1;
+ cam->ClipLeft = 1;
+ cam->ClipBottom = h-1;
+ cam->ClipRight = w-1;
+ cam->AspectRatio=1.0;
+ cam->CenterX=w/2;
+ cam->CenterY=h/2;
+
+ cam->Sort = 1;
+ cam->Z = -60;
+
+ light = plLightCreate();
+
+ setup_materials(mat,(unsigned char*)pal);
+ land = setup_landscape(LAND_SIZE,ishigh?LAND_DIV*2:LAND_DIV,mat[0]);
+
+ teamobject = plMakeBox(32,32,32,mat[5]);
+ teamobject->Yp=75;
+ teamobject->Xp=-LAND_SIZE/3;
+ teamobject->Za=-90;
+ teamobject->Ya=90;
+ teamobject->BackfaceCull=0;
+
+ billboard = plMakePlane(LAND_SIZE/3,90,1,mat[4]);
+ billboard->Yp=75;
+ billboard->Xp=LAND_SIZE/3;
+ billboard->Za=-90;
+ billboard->Ya=90;
+ billboard->BackfaceCull=0;
+
+ wd=9.8f;
+ for (i = 0; i < sizeof(object)/sizeof(object[0]); i++)
+ {
+ object[i]=plObjCreate(0,0);
+ object[i]->Xp=0;
+ object[i]->Yp=90;
+ object[i]->Zp=0;
+ object[i]->Children[0]=plMakeTorus(wd,wd+4.0f,ishigh?(64+i*4):(12+i*2),ishigh?12:6,mat[1+(i&1)]);
+ wd+=5.8f;
+ }
+ lightobject=plMakeSphere(17.0,ishigh?16:6,ishigh?24:8,mat[3]);
+ lightobject2=plMakeSphere(17.0,ishigh?16:6,ishigh?24:8,mat[3]);
+ m_creditspos=GetTickCount64();
+ m_creditspos_frames=0;
+ m_lastpos=-1;
+ prevtime=GetTickCount64();
+}
+
+// 128 frames:
+// 0-15, silence
+// 16-31, fadein
+// 32-111, display
+// 112-127, fadeout
+
+void render_quit(void)
+{
+ int x;
+
+ m_lastpos=-1;
+ m_creditspos=0;
+ m_creditspos_frames=0;
+ plObjDelete(land); land=0;
+ plObjDelete(billboard); billboard=0;
+ plObjDelete(teamobject); teamobject=0;
+
+ for (x = 0; x < sizeof(object)/sizeof(object[0]); x ++)
+ {
+ plObjDelete(object[x]); object[x]=0;
+ }
+ plObjDelete(lightobject);
+ plObjDelete(lightobject2);
+ for (x = 0; x < sizeof(mat)/sizeof(mat[0])-1; x ++)
+ {
+ plMatDelete(mat[x]); mat[x]=0;
+ }
+ plCamDelete(cam); cam=0;
+ plLightDelete(light); light=0;
+ plTexDelete(grndtex); grndtex=0;
+ plTexDelete(watex); watex = 0;
+ if (teamtex && teamtexbase) teamtex->Data = teamtexbase; teamtexbase=0;
+ plTexDelete(teamtex); teamtex=0;
+ plTexDelete(walogotex); walogotex=0;
+}
+
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+static wchar_t *creditslist[]=
+{
+ L"Winamp v" WIDEN(APP_VERSION) L"\n"
+ L" The Credits"
+ ,
+ L"Winamp v" WIDEN(APP_VERSION) L" Development:\n"
+ L" Quentin Hebette\n"
+ L" Thierry Honore\n"
+ L" Lionel Peeters\n"
+ L" Hakan Danisik\n"
+ L" Eddy Richman\n"
+ L" Jef Mauguit\n"
+// L" Mher Didaryan\n"
+// L" Siarhei Herasiuta\n"
+// L" Ben Allison\n"
+ ,
+ L"QA, Engineering & Support:\n"
+ L" DJ Egg\n"
+ ,
+ L"Freeform Skin Engine Updates:\n"
+ L" Linus Brolin"
+ ,
+ L"Bento Skin:\n"
+ L" Martin Pohlmann\n"
+ L" Taber Buhl\n"
+ L" Ben Allison\n"
+ L" Victor Brocaz\n"
+ ,
+ L"Language Packs:\n"
+// L" Dutch: Paul van Garderen\n"
+ L" French: Julien Victor, Benoit Hervier\n"
+ L" German: Christoph Grether\n"
+// L" Italian: Flocksoft, Riccardo Vianello\n"
+ L" Polish: Pawel Porwisz"
+ ,
+ L"Language Packs:\n"
+ L" Spanish: Manuel Fernando Gutierrez, Joel Almeida,\n"
+ L" Darwin Toledo Caceres aka Niwrad\n"
+// L" Swedish: Kenneth Chen, Amir Tehrani,\n"
+// L" Björn-Ole Antonsen\n"
+ L" Russian: Nureev Aleksandr, Eduard Galkin\n"
+ L" Turkish: Ali Sarioglu"
+ ,
+ L"Language Packs:\n"
+ L" Portuguese (Brazil): Anderson Silva\n"
+// L" Romanian: Catalin, Sebastian Alexandru\n"
+ L" Japanese: Toshiya Matsuo\n"
+ L" Hungarian: Laszlo Gardonyi\n"
+// L" Indonesian: Antony Kurniawan"
+ ,
+ L"Winamp Hall-of-Fame:\n"
+ L" Justin Frankel\n"
+ L" Christophe Thibault\n"
+ L" Francis Gastellu\n"
+ L" Brennan Underwood\n"
+ L" Peter Pawlowski\n"
+ L" Tom Pepper\n"
+ L" Ryan Geiss\n"
+ L" Will Fisher\n"
+ L" Maksim Tyrtyshny\n"
+ L" Darren Owen\n"
+ L" Ben Allison"
+ ,
+ L"Installer packaged with NSIS:\n"
+ L" http://nsis.sourceforge.net/\n"
+ L" thanklessly maintained by\n"
+ L" Amir Szekely\n"
+ L" Anders Kjersem\n"
+ L"Unicode NSIS port\n"
+ L" by Jim Park\n"
+ L" http://www.scratchpaper.com"
+ ,
+ L"Modern Skin:\n"
+ L" Sven Kistner\n"
+ L" http://www.metrix.de"
+ ,
+ /*L"Online Help: Jatin Billimoria\n"
+ L" with updates from DJ Egg"
+ ,*/
+ L"PCM EQ magic:\n"
+ L" 4Front Technologies/George Yohng\n"
+ L" http://www.yohng.com/\n"
+ L"\n"
+ L"EQ presets: Lars Holmberg"
+ /*
+ ,
+ L"MikMod plug-in:\n"
+ L" Jake Stine\n"
+ L" ...testing:\n"
+ L" Mathew Valente"
+ */
+ ,
+ L"Intro sound: JJ McKay"
+ ,
+ /*
+ L"Nullsoft Alumni (aka fun-haters):\n"
+ L" Rob Lord, Ian Rogers, Ryan Melcher\n"
+ L" Patrick Goddard, Jason Crawford\n"
+ L" Daniel Ruben, Kyle Yamamoto\n"
+ L" Susan Becker, Bill Thompson\n"
+ L" Josh Gerrish, Steven Blumenfeld\n"
+ L" Bonnie Burton, Rolf Hanson"
+ ,
+ L"Nullsoft Alumni (continued):\n"
+ L" Chris Amen, Keith Peters\n"
+ L" Konstantin Martynenko\n"
+ L" Justin Frankel, Christophe Thibault\n"
+ L" Steve Gedikian, David Biderman\n"
+ L" Tom Pepper, Ghislain 'Aus' Lacroix\n"
+ L" Jonathan Ward, Michael 'Mig' Gerard\n"
+ L" ...and DENNY!"
+ ,
+ L"Nullsoft Alumni (continued):\n"
+ L" Lloyd Given, Scott Brown\n"
+ L" Ben Sutherland, Wen Huang\n"
+ L" Ben Pontius, Brenda Chung\n"
+ L" Lauren Axelrod, Shaun Montgomery\n"
+ L" Chris Edwards, Matt Callaway\n"
+ L" Stephen 'Tag' Loomis, Jason Herskowitz"
+ ,
+ L"Nullsoft Alumni (continued):\n"
+ L" Ben London, Ying Chen, Rob Gould, Marcian Lytwyn\n"
+ L" Shawn Lavelle, Alex Petty, Chad Tempest\n"
+ L" Vanaja Nataraj, Ashok Bania, Venkatraman L\n"
+ L" Smita Roul, Shiva Virupaksha, Gautam Dayanidhi\n"
+ L" John Niranjan, Krishna Chaitanya, Chitra A, Rakesh G A\n"
+ L" Sumit Kumar, Vinay Sharma, Sudhindra Aithal\n"
+ L" Venkatesh Arya, Manoj Chourasia, Basavana Gowda\n"
+ L" Niharika Patro, Prasanna Revan, Mohan Balaji, Sasikumar R"
+ ,
+ L"Nullsoft Alumni (continued):\n"
+ L" Geno Yoham, Tarik Dahir, Tejas Mistry, Billy White, Bill Hicks\n"
+ L" Jonathan Chester, Gergo Spolarics, Maksim Tyrtyshny\n"
+ L" Taber Buhl, Shashikiran Reddy, Ryan Flynn, James Cready\n"
+ */
+ L"Credits rendered with Plush:\n"
+ L" http://www.cockos.com/wdl/\n"
+ L" (8bpp foreva)"
+ ,
+ L"Thanks:\n"
+ L" NS Beta Team & Craig Freer\n"
+ L" Our lowly forum moderators\n"
+ L" Our precious skin reviewers\n"
+ L" EFnet #mpeg3\n"
+ L" 4Front Technologies"
+ ,
+ /*
+ L"So long and ...\n"
+ L" thanks for all the fish"
+ ,
+ L"We really whipped the llama's ass!"
+ ,
+ L"Much <3 to all who have helped\n"
+ L"both directly and indirectly with\n"
+ L"Winamp over the many years!"
+ ,
+ L"At the going down of the sun\n"
+ L"and in the morning ...\n\n"
+ L"we will remember Winamp <3"
+ ,
+ */
+ L" Copyright © 1997-2023\n"
+ L" Winamp SA\n"
+ L" www.winamp.com"
+ ,
+ L""
+ ,
+ L"(you can double left click to toggle the credits\n"
+ L" for your viewing pleasure)"
+ ,
+ L"(you can also double right click to go into\n"
+ L" crappy fullscreen mode)"
+ ,
+ L""
+};
+
+static int creditslist_l=(sizeof(creditslist)/sizeof(creditslist[0]))*128;
+static unsigned int start_time;
+
+static int text_hW(const wchar_t *str)
+{
+ int nc=1;
+ while (str && *str)
+ {
+ if (*str==L'\n') nc++;
+ str++;
+ }
+ return ScaleY(nc*17);
+}
+
+static int text_hA(const char* str)
+{
+ int nc = 1;
+ while (str && *str)
+ {
+ if (*str == '\n') nc++;
+ str++;
+ }
+ return ScaleY(nc * 17);
+}
+
+static int text_w(const wchar_t *str)
+{
+ int maxc=0,nc=0;
+ while (str && *str)
+ {
+ if (*str==L'\n') nc=0;
+ else nc++;
+ str++;
+ if (nc > maxc) maxc=nc;
+ }
+ return ScaleX(maxc*9);
+}
+
+#ifndef STATICBALLTEXTURE
+#define FIRE_BITMAP_W 64
+#define FIRE_BITMAP_H 64
+void makeBallTexture(char *tx)
+{
+ int y;
+ unsigned char *p=(unsigned char *)tx;
+ int x;
+ unsigned char *t=p + FIRE_BITMAP_W*FIRE_BITMAP_H;
+ for (x = 0; x < FIRE_BITMAP_W; x ++)
+ {
+ int a=*t - 10;
+ if ((warand()&0x7) == 7) a+=130;
+ if (a < 0) a=0;
+ else if (a > 150) a=150;
+ *t++=a;//warand()&0xf0;
+ }
+ for (y = 0; y < FIRE_BITMAP_H; y ++)
+ {
+ *p++=p[0]/4 + p[FIRE_BITMAP_W]/2 + p[FIRE_BITMAP_W+1]/4;
+
+ for (x = 1; x < FIRE_BITMAP_W-1; x ++)
+ *p++=p[0]/4 + p[FIRE_BITMAP_W]/4 + p[FIRE_BITMAP_W-1]/4 + p[FIRE_BITMAP_W+1]/4;
+
+ *p++=p[0]/4 + p[FIRE_BITMAP_W]/2 + p[FIRE_BITMAP_W-1]/4;
+ }
+}
+
+void makeBallTextPal(char *pal)
+{
+ unsigned char *t=(unsigned char *)pal;
+ int x=255;
+ t[0]=t[1]=t[2]=0;
+ t+=3;
+ while (x)
+ {
+ if (x > 128)
+ {
+ int a=256-x;
+ a*=3;
+ if (a>255)a=255;
+ t[2]=0;
+ t[1]=a/2;
+ t[0]=a;
+ }
+ else
+ {
+ t[2]=256-x*2;
+ t[1]=255/3 + ((256-x)*2)/3;
+ t[0]=255;
+ }
+
+ t+=3;
+ x--;
+ }
+}
+
+#endif
+
+void render_render(unsigned char *framebuffer, HDC hdc)
+{
+ static float light_sc=0.2f+2*0.3f;
+ pl_Float curpos[5];
+ int i;
+ cam->frameBuffer=framebuffer;
+
+ {
+ unsigned int now = GetTickCount64();
+ unsigned int t = now - prevtime;
+ if (t < 0) t=0;
+ splineTime += (pl_Float)(t*(0.01/33.0));
+ prevtime=now;
+ }
+
+ if (splineTime > spline.numKeys)
+ {
+ for (i = 2; i < spline.numKeys-2; i ++)
+ {
+ initspline(i);
+ }
+ rpoo=0;
+ splineTime -= spline.numKeys;
+ }
+ if (!rpoo&&splineTime>3.0)
+ {
+ rpoo=1;
+ initspline(0);
+ initspline(1);
+ initspline(spline.numKeys-2);
+ initspline(spline.numKeys-1);
+ }
+ plSplineGetPoint(&spline,splineTime,curpos);
+
+ {
+ for (i = sizeof(object)/sizeof(object[0])-1; i > 0; i --)
+ {
+ object[i]->Xa=object[i-1]->Xa;
+ object[i]->Ya=object[i-1]->Ya;
+ object[i]->Za=object[i-1]->Za;
+ }
+ object[0]->Xa+=5*curpos[3];
+ object[0]->Ya+=5*curpos[4];
+ object[0]->Za-=5*(curpos[4]*curpos[3]);
+ }
+
+ cam->X = curpos[0];
+ cam->Y = curpos[1];
+ cam->Z = curpos[2];
+
+ teamobject->Xp=(pl_Float)(100.0*sin((splineTime-0.1)*3.14159));
+ teamobject->Yp=(pl_Float)(75+40.0*cos((splineTime-0.1)*3.14159));
+ teamobject->Zp=(pl_Float)(100.0*cos((splineTime-0.1)*3.14159*1.5));
+ teamobject->Ya+=1.1f;
+
+ lightobject->Xp=(pl_Float)(100.0*sin(splineTime*3.14159));
+ lightobject->Yp=(pl_Float)(75+40.0*cos(splineTime*3.14159));
+ lightobject->Zp=(pl_Float)(100.0*cos(splineTime*3.14159*1.5));
+ lightobject->Ya+=1.1f;
+ plLightSet(light,PL_LIGHT_POINT,lightobject->Xp,lightobject->Yp,lightobject->Zp,0.7f-0.2f/2+light_sc/2,LAND_SIZE/2);//(warand()%LAND_SIZE)-LAND_SIZE/2,12,(warand()%LAND_SIZE)-LAND_SIZE/2,1.0,LAND_SIZE/4);
+
+ plCamSetTarget(cam,lightobject->Xp/4,lightobject->Yp/4.0f+90*0.75f,lightobject->Zp/4);
+ cam->ClipBack = 1500.0;
+
+#ifndef STATICBALLTEXTURE
+ if (watex && watex->Data) { makeBallTexture(watex->Data); makeBallTexture(watex->Data);}
+#endif
+ plRenderBegin(cam);
+ plRenderLight(light);
+ plRenderObj(land);
+ plRenderEnd();
+ plRenderBegin(cam);
+ plRenderLight(light);
+
+ billboard->Za+=1.0;
+ billboard->Ya+=1.0;
+
+ {
+ light_sc=0.2f+2*0.3f;
+ plRenderObj(lightobject);
+ }
+
+ if (sa_curmode && playing)
+ {
+ char sadata[75*2+8] = {0};
+ unsigned char *data=(unsigned char *)sa_get(in_getouttime(),sa_curmode, sadata);
+ if (data)
+ {
+ if (sa_curmode == 2) data+=75;
+ for (i = 0; i < sizeof(object)/sizeof(object[0]); i ++)
+ {
+ int t=data[(7-i)*3];
+ int t2=data[(7-i)*3+1];
+ int t3=data[(7-i)*3+2];
+ float val;
+ if (t2 > t) t=t2;
+ if (t3 > t) t=t3;
+ if (sa_curmode==2) { t-=128; t/=4;}
+ val=t*1.3f;
+ if (object[i]->Children[0]->Yp < val) object[i]->Children[0]->Yp=val;
+ else object[i]->Children[0]->Yp=object[i]->Children[0]->Yp*0.9f;
+ if (i)
+ {
+ object[i]->Xa=object[0]->Xa;
+ object[i]->Ya=object[0]->Ya;
+ object[i]->Za=object[0]->Za;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof(object)/sizeof(object[0]); i ++)
+ {
+ object[i]->Children[0]->Yp=object[i]->Children[0]->Yp*0.9f;
+ }
+ }
+ for (i = 0; i < sizeof(object)/sizeof(object[0]); i ++) plRenderObj(object[i]);
+
+ plRenderObj(billboard);
+ plRenderObj(teamobject);
+
+ plRenderEnd();
+
+ if (displaycredits)
+ {
+ int alpha=0;
+ int creditspos=((GetTickCount64()-m_creditspos)/30)%creditslist_l;
+ int pos=creditspos&127;
+ const wchar_t *str=creditslist[creditspos/128];
+ static int g_ypos;
+ static int g_xpos;
+ if (creditspos/128 != m_lastpos)
+ {
+ m_lastpos=creditspos/128;
+ if (creditspos<128)
+ {
+ m_creditspos_frames=0;
+ start_time=GetTickCount64();
+ }
+ g_ypos=cam->ScreenHeight/4+(warand()%(cam->ScreenHeight/2-text_hW(str)/2));
+ g_xpos=10+(warand()%(cam->ClipRight-text_w(str)-20));
+ }
+ else if (pos>=112) alpha=(127-pos);
+ else if (pos >= 32) alpha=15;
+ else if (pos >= 16) alpha=(pos-16);
+
+ if (alpha&&str[0]) plTextPutStrW(cam,g_xpos,g_ypos,0, 1, str);
+ }
+
+ {
+ int t=(GetTickCount64()-start_time)/1000;
+ char nbuf[32] = {0};
+ StringCchPrintfA(nbuf, 32, "%dfps",t?(m_creditspos_frames/t):0);
+ plTextPutStr(cam,3,cam->ScreenHeight+1-text_hA(nbuf),0,1, nbuf);
+ }
+ m_creditspos_frames++;
+
+ #define TEAM_IMG_W 32
+ #define TEAM_IMG_H 32 //416
+ if (teamtex && (!(m_creditspos_frames & 127)))
+ {
+ int g_regver=2;
+
+ teamtex->Data += 32*32;
+
+ if (g_regver < 1 && teamtex->Data-teamtexbase >= TEAM_IMG_W*(TEAM_IMG_H-32))
+ teamtex->Data=teamtexbase;
+ else if (teamtex->Data-teamtexbase >= TEAM_IMG_W*TEAM_IMG_H)
+ teamtex->Data=teamtexbase;
+ }
+}
+
+#define SPLASH_IMG_W 400
+#define SPLASH_IMG_H 189
+
+static pl_Texture *mkWALogoTex(int which)
+{
+ //pl_Texture *p=(pl_Texture*)GlobalAlloc(GPTR,sizeof(pl_Texture));
+ pl_Texture* p = (pl_Texture*)malloc(sizeof(pl_Texture));
+ if (p)
+ {
+ //char *temp=(char *)GlobalAlloc(GPTR,SPLASH_IMG_W*SPLASH_IMG_H);
+ char* temp = (char*)malloc(SPLASH_IMG_W * SPLASH_IMG_H);
+ //p->Data=GlobalAlloc(GPTR,which ? TEAM_IMG_H*TEAM_IMG_W : 256*256);
+ p->Data = malloc(which ? TEAM_IMG_H * TEAM_IMG_W : 256 * 256);
+ //p->PaletteData=GlobalAlloc(GPTR,3*256);
+ p->PaletteData = malloc(3 * 256);
+ if (p->Data && p->PaletteData && temp)
+ {
+ HBITMAP m_imgbm, m_imgoldbm;
+ HDC m_imgdc;
+ struct
+ {
+ BITMAPINFO bmi;
+ RGBQUAD more_bmiColors[256];
+ LPVOID data;
+ } m_bitmap;
+
+ int c;
+ char *out=p->Data;
+
+ memset(&m_bitmap, 0, sizeof(m_bitmap));
+
+ m_imgdc = CreateCompatibleDC(NULL);
+ // TODO (load from PNG)
+ m_imgbm = LoadImage(hMainInstance,MAKEINTRESOURCE(which ? IDB_TEAM : IDB_SPLASH), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+ //m_imgbm = WALoadImage(hMainInstance, L"PNG", MAKEINTRESOURCEW(which ? IDR_TEAM : IDR_SPLASH), FALSE);
+ m_imgoldbm=SelectObject(m_imgdc,m_imgbm);
+ m_bitmap.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ m_bitmap.bmi.bmiHeader.biPlanes = 1;
+ m_bitmap.bmi.bmiHeader.biBitCount = 8;
+ m_bitmap.bmi.bmiHeader.biCompression = BI_RGB;
+ m_bitmap.bmi.bmiHeader.biSizeImage = 0;
+ m_bitmap.bmi.bmiHeader.biClrUsed = 256;
+ m_bitmap.bmi.bmiHeader.biClrImportant = 256;
+ m_bitmap.bmi.bmiHeader.biWidth = which ? TEAM_IMG_W : SPLASH_IMG_W;
+ m_bitmap.bmi.bmiHeader.biHeight = which ? -TEAM_IMG_H : -SPLASH_IMG_H;
+ m_bitmap.bmi.bmiHeader.biSizeImage = which ? TEAM_IMG_H * TEAM_IMG_W : SPLASH_IMG_W*SPLASH_IMG_H;
+
+ GetDIBits(m_imgdc,m_imgbm,0,which ? TEAM_IMG_H : SPLASH_IMG_H,temp,(BITMAPINFO *)&m_bitmap,DIB_RGB_COLORS);
+ GetDIBColorTable(m_imgdc,0,which ? 64 : 256,m_bitmap.bmi.bmiColors);
+
+ SelectObject(m_imgdc, m_imgoldbm);
+ DeleteDC(m_imgdc);
+ DeleteObject(m_imgbm);
+
+ for (c = 0; c < (which ? 64 : 256); c ++)
+ {
+ p->PaletteData[c*3] = m_bitmap.bmi.bmiColors[c].rgbRed;
+ p->PaletteData[c*3+1] = m_bitmap.bmi.bmiColors[c].rgbGreen;
+ p->PaletteData[c*3+2] = m_bitmap.bmi.bmiColors[c].rgbBlue;
+ }
+
+ if (which)
+ {
+ memcpy(out,temp,TEAM_IMG_W*TEAM_IMG_H);
+ p->Width=5;
+ p->Height=5;
+ p->iWidth=32;
+ p->iHeight=32;
+ p->uScale=-32;
+ p->vScale=32;
+ p->NumColors=64;
+ }
+ else
+ {
+ int dxp=(SPLASH_IMG_W<<16)/256;
+ int dyp=(SPLASH_IMG_H<<16)/256;
+ int y, yp = 0;
+ for (y = 0; y < 256; y ++)
+ {
+ char *in=temp+(yp>>16)*SPLASH_IMG_W;
+ int x, xp = 0;
+ for (x = 0; x < 256; x ++)
+ {
+ *out++=in[xp>>16];
+ xp+=dxp;
+ }
+ yp+=dyp;
+ }
+ p->Width=8;
+ p->Height=8;
+ p->iWidth=256;
+ p->iHeight=256;
+ p->uScale=-256;
+ p->vScale=256;
+ p->NumColors=256;
+ }
+ //GlobalFree(temp);
+ free(temp);
+ }
+ //else { if (p->Data) GlobalFree(p->Data); if (p->PaletteData) GlobalFree(p->PaletteData); GlobalFree(p); p=NULL; if (temp) GlobalFree(temp); }
+ else { if (p->Data) free(p->Data); if (p->PaletteData) free(p->PaletteData); free(p); p = NULL; if (temp) free(temp); }
+ }
+ return p;
+}
+
+static pl_Texture *mkWATex()
+{
+ //pl_Texture *p=(pl_Texture*)GlobalAlloc(GPTR,sizeof(pl_Texture));
+ pl_Texture* p = (pl_Texture*)malloc(sizeof(pl_Texture));
+ if (p)
+ {
+ //p->Data=GlobalAlloc(GPTR,64*65+2);
+ p->Data = malloc(64 * 65 + 2);
+ //p->PaletteData=GlobalAlloc(GPTR,3*256);
+ p->PaletteData = malloc(3 * 256);
+ if (p->Data && p->PaletteData)
+ {
+ makeBallTextPal(p->PaletteData);
+ p->Width=6;
+ p->Height=6;
+ p->iWidth=64;
+ p->iHeight=64;
+ p->uScale=128;
+ p->vScale=64;
+ p->NumColors=150;
+ }
+ //else { if (p->Data) GlobalFree(p->Data); if (p->PaletteData) GlobalFree(p->PaletteData); GlobalFree(p); p=NULL; }
+ else { if (p->Data) free(p->Data); if (p->PaletteData) free(p->PaletteData); free(p); p = NULL; }
+ }
+ return p;
+}
+
+static pl_Texture *mkGroundTex()
+{
+ //pl_Texture *p=(pl_Texture*)GlobalAlloc(GPTR,sizeof(pl_Texture));
+ pl_Texture* p = (pl_Texture*)malloc(sizeof(pl_Texture));
+ if (p)
+ {
+ //p->Data=GlobalAlloc(GPTR,16*16);
+ p->Data = malloc(16 * 16);
+ //p->PaletteData=GlobalAlloc(GPTR,3*16);
+ p->PaletteData = malloc(3 * 16);
+ if (p->Data && p->PaletteData)
+ {
+ int x,y;
+ p->Width=4;
+ p->Height=4;
+ p->iWidth=16;
+ p->iHeight=16;
+ p->uScale=16*3;
+ p->vScale=16*3;
+ p->NumColors=16;
+
+ for (y = 0; y < 16; y ++) for (x = 0; x < 16; x ++) p->Data[y*16+x]=x^y;
+
+ for (x = 0; x < 16; x ++)
+ {
+ p->PaletteData[x*3+0]=43+((93-43)*x)/16;
+ p->PaletteData[x*3+1]=25+((52-25)*x)/16;
+ p->PaletteData[x*3+2]=9+((23-9)*x)/16;
+ }
+ }
+ //else { if (p->Data) GlobalFree(p->Data); if (p->PaletteData) GlobalFree(p->PaletteData); GlobalFree(p); p=NULL; }
+ else { if (p->Data) free(p->Data); if (p->PaletteData) free(p->PaletteData); free(p); p = NULL; }
+ }
+ return p;
+}
+
+static void setup_materials(pl_Mat **mat, unsigned char *pal)
+{
+ int fuckomode=!(GetAsyncKeyState(VK_CONTROL) & GetAsyncKeyState(VK_SHIFT) & 0x8000 );
+ mat[0] = plMatCreate();
+ mat[1] = plMatCreate();
+ mat[2] = plMatCreate();
+ mat[3] = plMatCreate();
+ mat[4] = plMatCreate();
+ mat[5] = plMatCreate();
+ mat[6]=0;
+
+ watex = mkWATex();
+ grndtex=mkGroundTex();
+
+ mat[0]->ShadeType = PL_SHADE_GOURAUD;
+ mat[0]->Shininess = 16;
+ mat[0]->NumGradients = 1500;
+ mat[0]->Ambient[0] = -128;
+ mat[0]->Ambient[1] = -128;
+ mat[0]->Ambient[2] = -128;
+ mat[0]->Diffuse[0] = 170;
+ mat[0]->Diffuse[1] = 140;
+ mat[0]->Diffuse[2] = 140;
+ mat[0]->Specular[0] = 140;
+ mat[0]->Specular[1] = 90;
+ mat[0]->Specular[2] = 0;
+ mat[0]->FadeDist = 5000.0;
+ mat[0]->Texture = fuckomode ? watex : grndtex;
+ mat[0]->TexScaling = 8.0;
+ mat[0]->PerspectiveCorrect = 16;
+
+ mat[1]->ShadeType = PL_SHADE_GOURAUD;
+ mat[1]->Shininess = 8;
+ mat[1]->NumGradients = 150;
+ mat[1]->Ambient[0] = 0;
+ mat[1]->Ambient[1] = 0;
+ mat[1]->Ambient[2] = 0;
+ mat[1]->Diffuse[0] = 0;
+ mat[1]->Diffuse[1] = 0;
+ mat[1]->Diffuse[2] = 0;
+ mat[1]->Specular[0] = 450;
+ mat[1]->Specular[1] = 264;
+ mat[1]->Specular[2] = 150;
+
+ mat[2]->ShadeType = PL_SHADE_GOURAUD;
+ mat[2]->Shininess = 8;
+ mat[2]->NumGradients = 150;
+ mat[2]->Ambient[0] = 32;
+ mat[2]->Ambient[1] = 32;
+ mat[2]->Ambient[2] = 64;
+ mat[2]->Diffuse[0] = 120;
+ mat[2]->Diffuse[1] = 60;
+ mat[2]->Diffuse[2] = 60;
+ mat[2]->Specular[0] = 200;
+ mat[2]->Specular[1] = 80;
+ mat[2]->Specular[2] = 80;
+
+ mat[3]->ShadeType = PL_SHADE_GOURAUD;
+ mat[3]->Shininess = 1;
+ mat[3]->NumGradients = 1;
+ mat[3]->Ambient[0] = 0;
+ mat[3]->Ambient[1] = 0;
+ mat[3]->Ambient[2] = 0;
+ mat[3]->Diffuse[0] = 0;
+ mat[3]->Diffuse[1] = 0;
+ mat[3]->Diffuse[2] = 0;
+ mat[3]->Specular[0] = 0;
+ mat[3]->Specular[1] = 0;
+ mat[3]->Specular[2] = 0;
+ mat[3]->Texture = fuckomode ? grndtex : watex;
+ mat[3]->TexScaling = 1.4f;
+ mat[3]->PerspectiveCorrect = 16;
+
+ mat[4]->ShadeType = PL_SHADE_GOURAUD;
+ mat[4]->Shininess = 1;
+ mat[4]->NumGradients = 1;
+ mat[4]->Ambient[0] = 0;
+ mat[4]->Ambient[1] = 0;
+ mat[4]->Ambient[2] = 0;
+ mat[4]->Diffuse[0] = 0;
+ mat[4]->Diffuse[1] = 0;
+ mat[4]->Diffuse[2] = 0;
+ mat[4]->Specular[0] = 0;
+ mat[4]->Specular[1] = 0;
+ mat[4]->Specular[2] = 0;
+ mat[4]->Texture = walogotex = mkWALogoTex(0);
+ mat[4]->TexScaling = 1.0;
+ mat[4]->PerspectiveCorrect = 16;
+
+ mat[5]->ShadeType = PL_SHADE_GOURAUD;
+ mat[5]->Shininess = 1;
+ mat[5]->NumGradients = 1;
+ mat[5]->Ambient[0] = 0;
+ mat[5]->Ambient[1] = 0;
+ mat[5]->Ambient[2] = 0;
+ mat[5]->Diffuse[0] = 0;
+ mat[5]->Diffuse[1] = 0;
+ mat[5]->Diffuse[2] = 0;
+ mat[5]->Specular[0] = 0;
+ mat[5]->Specular[1] = 0;
+ mat[5]->Specular[2] = 0;
+ mat[5]->Texture = teamtex = mkWALogoTex(1);
+ mat[5]->TexScaling = 1.0;
+ mat[5]->PerspectiveCorrect = 16;
+ if (teamtex) teamtexbase=teamtex->Data;
+
+ plMatInit(mat[0]);
+ plMatInit(mat[1]);
+ plMatInit(mat[2]);
+ plMatInit(mat[3]);
+ plMatInit(mat[4]);
+ plMatInit(mat[5]);
+
+ memset(pal,0,768);
+ plMatMakeOptPal(pal,2,255,mat,1);
+
+ pal[0] = pal[1] = pal[2] = 0;
+ pal[3] = pal[4] = pal[5] = 255;
+
+ plMatMapToPal(mat[0],pal,0,255);
+ plMatMapToPal(mat[1],pal,0,255);
+ plMatMapToPal(mat[2],pal,0,255);
+ plMatMapToPal(mat[3],pal,0,255);
+ plMatMapToPal(mat[4],pal,0,255);
+ plMatMapToPal(mat[5],pal,0,255);
+}
+
+static void adjustmapping(pl_Obj *obj)
+{
+ int nf=obj->NumFaces;
+ int x;
+ pl_Face *f=obj->Faces;
+ for (x = 0; x < nf; x ++)
+ {
+ f->MappingV[0]=MulDiv(f->MappingV[0],(150<<16)/500,(1<<16));
+ f->MappingV[1]=MulDiv(f->MappingV[1],(150<<16)/500,(1<<16));
+ f->MappingV[2]=MulDiv(f->MappingV[2],(150<<16)/500,(1<<16));
+ f++;
+ }
+}
+
+static pl_Obj *setup_landscape(float size, int div, pl_Mat *m)
+{
+
+ pl_Obj *o = plMakePlane(size,size,div,m);
+ o->Children[0]= plMakePlane(size,size,div,m);
+ o->Children[0]->Yp=150;
+ o->Children[0]->Xa=-180;
+ div/=3;
+
+ o->Children[1]= plMakePlane(size,150,div,m);
+ o->Children[1]->Yp=75;
+ o->Children[1]->Zp=size/2;
+ o->Children[1]->Xa=90;
+ adjustmapping(o->Children[1]);
+ o->Children[2]= plMakePlane(size,150,div,m);
+ o->Children[2]->Yp=75;
+ o->Children[2]->Zp=-size/2;
+ o->Children[2]->Xa=-90;
+ adjustmapping(o->Children[2]);
+ o->Children[3]= plMakePlane(size,150,div,m);
+ o->Children[3]->Yp=75;
+ o->Children[3]->Xp=size/2;
+ o->Children[3]->Za=-90;
+ o->Children[3]->Ya=90;
+ adjustmapping(o->Children[3]);
+ o->Children[4]= plMakePlane(size,150,div,m);
+ o->Children[4]->Yp=75;
+ o->Children[4]->Xp=-size/2;
+ o->Children[4]->Za=90;
+ o->Children[4]->Ya=90;
+ adjustmapping(o->Children[4]);
+
+ o->Yp = 0;
+ return (o);
+} \ No newline at end of file
diff --git a/Src/Winamp/demo.mp3 b/Src/Winamp/demo.mp3
new file mode 100644
index 00000000..6925a244
--- /dev/null
+++ b/Src/Winamp/demo.mp3
Binary files differ
diff --git a/Src/Winamp/directdraw.h b/Src/Winamp/directdraw.h
new file mode 100644
index 00000000..916b27bd
--- /dev/null
+++ b/Src/Winamp/directdraw.h
@@ -0,0 +1,6 @@
+#ifndef NULLSOFT_DDRAWH
+#define NULLSOFT_DDRAWH
+#include <ddraw.h>
+ extern HRESULT (WINAPI *_DirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/dispatchCallback.cpp b/Src/Winamp/dispatchCallback.cpp
new file mode 100644
index 00000000..d14c5938
--- /dev/null
+++ b/Src/Winamp/dispatchCallback.cpp
@@ -0,0 +1,525 @@
+//#include "main.h"
+#include "./dispatchCallback.h"
+#include <new.h>
+
+DispatchCallback::DispatchCallback()
+ : ref(1), dispatch(NULL), threadId(0), threadHandle(NULL)
+{
+}
+
+DispatchCallback::~DispatchCallback()
+{
+ if (NULL != dispatch)
+ dispatch->Release();
+
+ if (NULL != threadHandle)
+ CloseHandle(threadHandle);
+}
+
+HRESULT DispatchCallback::CreateInstance(IDispatch *dispatch, DispatchCallback **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = NULL;
+
+ if (NULL == dispatch)
+ return E_INVALIDARG;
+
+ DispatchCallback *self = new DispatchCallback();
+ if (NULL == self)
+ return E_OUTOFMEMORY;
+
+ self->dispatch = dispatch;
+ self->dispatch->AddRef();
+ self->threadId = GetCurrentThreadId();
+
+ HANDLE processHandle = GetCurrentProcess();
+
+ if (FALSE == DuplicateHandle(processHandle,
+ GetCurrentThread(),
+ processHandle,
+ &self->threadHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ self->threadHandle = NULL;
+ delete(self);
+
+ return E_FAIL;
+ }
+
+ *instance = self;
+ return S_OK;
+}
+
+unsigned long DispatchCallback::AddRef()
+{
+ return InterlockedIncrement((long*)&ref);
+}
+
+unsigned long DispatchCallback::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((long*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+IDispatch *DispatchCallback::GetDispatch()
+{
+ return dispatch;
+}
+
+unsigned long DispatchCallback::GetThreadId()
+{
+ return threadId;
+}
+
+HANDLE DispatchCallback::GetThreadHandle()
+{
+ return threadHandle;
+}
+
+
+DispatchCallbackEnum::DispatchCallbackEnum()
+ : ref(1), buffer(NULL), size(0), cursor(0)
+{
+}
+
+DispatchCallbackEnum::~DispatchCallbackEnum()
+{
+ if (NULL != buffer)
+ {
+ while(size--)
+ {
+ buffer[size]->Release();
+ }
+ }
+}
+
+HRESULT DispatchCallbackEnum::CreateInstance(DispatchCallback **objects, size_t count, DispatchCallbackEnum **instance)
+{
+ DispatchCallback *callback = NULL;
+ DispatchCallbackEnum *enumerator = NULL;
+
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = NULL;
+
+ size_t size = sizeof(DispatchCallbackEnum) + (sizeof(DispatchCallback**) * count);
+ void *storage = calloc(size, 1);
+ if (NULL == storage)
+ return E_OUTOFMEMORY;
+
+ enumerator = new(storage) DispatchCallbackEnum();
+ if (NULL == enumerator)
+ {
+ free(storage);
+ return E_FAIL;
+ }
+
+ enumerator->buffer = (DispatchCallback**)(((BYTE*)enumerator) + sizeof(DispatchCallback));
+
+ for (size_t index = 0; index < count; index++)
+ {
+ callback = objects[index];
+ if (NULL != callback)
+ {
+ enumerator->buffer[enumerator->size] = callback;
+ callback->AddRef();
+ enumerator->size++;
+ }
+ }
+
+ *instance = enumerator;
+ return S_OK;
+}
+
+unsigned long DispatchCallbackEnum::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+unsigned long DispatchCallbackEnum::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+HRESULT DispatchCallbackEnum::Next(DispatchCallback **objects, size_t bufferMax, size_t *fetched)
+{
+ if (NULL == objects)
+ return E_POINTER;
+
+ if (0 == bufferMax)
+ return E_INVALIDARG;
+
+ if (cursor >= size)
+ {
+ if (NULL != fetched)
+ *fetched = 0;
+
+ return S_FALSE;
+ }
+
+ size_t available = size - cursor;
+ size_t copied = ((available > bufferMax) ? bufferMax : available);
+
+ DispatchCallback **source = buffer + cursor;
+ CopyMemory(objects, source, copied * sizeof(DispatchCallback*));
+
+ for(size_t index = 0; index < copied; index++)
+ objects[index]->AddRef();
+
+ cursor += copied;
+
+ if (NULL != fetched)
+ *fetched = copied;
+
+ return (bufferMax == copied) ? S_OK : S_FALSE;
+}
+
+HRESULT DispatchCallbackEnum::Reset(void)
+{
+ cursor = 0;
+ return S_OK;
+}
+
+HRESULT DispatchCallbackEnum::Skip(size_t count)
+{
+ cursor += count;
+ if (cursor > size)
+ cursor = size;
+
+ return (cursor < size) ? S_OK : S_FALSE;
+}
+
+HRESULT DispatchCallbackEnum::GetCount(size_t *count)
+{
+ if (NULL == count)
+ return E_POINTER;
+
+ *count = size;
+
+ return S_OK;
+}
+
+HRESULT DispatchCallbackEnum::Notify(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb, void *param)
+{
+ DispatchCallbackApc *apc = NULL;
+ unsigned long threadId = GetCurrentThreadId();
+
+ if (NULL == buffer)
+ return E_UNEXPECTED;
+
+ HRESULT hr = DispatchCallbackApc::CreateInstance(notifyCb, freeCb, param, &apc);
+ if (FAILED(hr) || apc == NULL)
+ return hr;
+
+ for (size_t index = 0; index < size; index++)
+ {
+ DispatchCallback *callback = buffer[index];
+ if (callback)
+ {
+ if (callback->GetThreadId() == threadId)
+ apc->Call(callback->GetDispatch());
+ else
+ apc->Queue(callback->GetThreadHandle(), callback->GetDispatch());
+ }
+ }
+
+ apc->Release();
+ return hr;
+}
+
+DispatchCallbackStore::DispatchCallbackStore()
+{
+ InitializeCriticalSection(&lock);
+}
+
+DispatchCallbackStore::~DispatchCallbackStore()
+{
+ UnregisterAll();
+ DeleteCriticalSection(&lock);
+}
+
+void DispatchCallbackStore::Lock()
+{
+ EnterCriticalSection(&lock);
+}
+
+void DispatchCallbackStore::Unlock()
+{
+ LeaveCriticalSection(&lock);
+}
+
+CRITICAL_SECTION *DispatchCallbackStore::GetLock()
+{
+ return &lock;
+}
+
+HRESULT DispatchCallbackStore::Register(IDispatch *dispatch)
+{
+ DispatchCallback *callback = NULL;
+
+ if (NULL == dispatch)
+ return E_INVALIDARG;
+
+ Lock();
+
+ HRESULT hr = S_OK;
+ size_t index = list.size();
+ while(index--)
+ {
+ callback = list[index];
+ if (callback->GetDispatch() == dispatch)
+ {
+ hr = S_FALSE;
+ break;
+ }
+ }
+
+ if (S_OK == hr)
+ {
+ hr = DispatchCallback::CreateInstance(dispatch, &callback);
+ if (SUCCEEDED(hr))
+ list.push_back(callback);
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DispatchCallbackStore::Unregister(IDispatch *dispatch)
+{
+ if (NULL == dispatch)
+ return E_INVALIDARG;
+
+ Lock();
+
+ HRESULT hr = S_FALSE;
+ size_t index = list.size();
+ while(index--)
+ {
+ DispatchCallback *callback = list[index];
+ if (callback->GetDispatch() == dispatch)
+ {
+ list.erase(list.begin() + index);
+ callback->Release();
+ hr = S_OK;
+ break;
+ }
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+void DispatchCallbackStore::UnregisterAll()
+{
+ Lock();
+
+ size_t index = list.size();
+ while(index--)
+ {
+ DispatchCallback *callback = list[index];
+ callback->Release();
+ }
+
+ list.clear();
+
+ Unlock();
+}
+
+HRESULT DispatchCallbackStore::Enumerate(DispatchCallbackEnum **enumerator)
+{
+ if (NULL == enumerator || !(list.size() > 0))
+ return E_POINTER;
+
+ Lock();
+ HRESULT hr = DispatchCallbackEnum::CreateInstance(&list[0], list.size(), enumerator);
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DispatchCallbackStore::RegisterFromDispParam(DISPPARAMS *pdispparams, unsigned int position,
+ unsigned int *puArgErr)
+{
+ VARIANTARG varg;
+ VariantInit(&varg);
+ HRESULT hr = DispGetParam(pdispparams, position, VT_DISPATCH, &varg, puArgErr);
+ if (SUCCEEDED(hr))
+ {
+ hr = Register(V_DISPATCH(&varg));
+ VariantClear(&varg);
+ }
+
+ return hr;
+}
+
+HRESULT DispatchCallbackStore::UnregisterFromDispParam(DISPPARAMS *pdispparams, unsigned int position,
+ unsigned int *puArgErr)
+{
+ VARIANTARG varg;
+ VariantInit(&varg);
+ HRESULT hr = DispGetParam(pdispparams, position, VT_DISPATCH, &varg, puArgErr);
+ if (SUCCEEDED(hr))
+ {
+ hr = Unregister(V_DISPATCH(&varg));
+ VariantClear(&varg);
+ }
+
+ return hr;
+}
+
+HRESULT DispatchCallbackStore::Notify(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb, void *param)
+{
+ DispatchCallbackEnum *enumerator = NULL;
+ HRESULT hr = Enumerate(&enumerator);
+ if (SUCCEEDED(hr))
+ {
+ hr = enumerator->Notify(notifyCb, freeCb, param);
+ enumerator->Release();
+ }
+
+ return hr;
+}
+
+DispatchCallbackApc::DispatchCallbackApc()
+ : ref(1), notifyCb(NULL), freeCb(NULL), param(NULL)
+{
+}
+
+DispatchCallbackApc::~DispatchCallbackApc()
+{
+ if (NULL != freeCb)
+ freeCb(param);
+}
+
+HRESULT DispatchCallbackApc::CreateInstance(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb,
+ void *param, DispatchCallbackApc **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = NULL;
+
+ if (NULL == notifyCb)
+ return E_INVALIDARG;
+
+ DispatchCallbackApc *self = new DispatchCallbackApc();
+ if (NULL == self)
+ return E_OUTOFMEMORY;
+
+ self->notifyCb = notifyCb;
+ self->freeCb = freeCb;
+ self->param = param;
+
+ *instance = self;
+
+ return S_OK;
+}
+
+unsigned long DispatchCallbackApc::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+unsigned long DispatchCallbackApc::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+HRESULT DispatchCallbackApc::Call(IDispatch *dispatch)
+{
+ if (NULL == notifyCb)
+ return E_UNEXPECTED;
+
+ notifyCb(dispatch, param);
+ return S_OK;
+}
+
+HRESULT DispatchCallbackApc::Queue(HANDLE threadHandle, IDispatch *dispatch)
+{
+ if (NULL == threadHandle || ((unsigned int)dispatch) < 65536)
+ return E_INVALIDARG;
+
+ DispatchCallbackApcParam *apcParam = new DispatchCallbackApcParam(dispatch, this);
+ if (NULL == apcParam || ((unsigned int)apcParam) < 65536)
+ return E_OUTOFMEMORY;
+
+ if (0 == QueueUserAPC(QueueApcCallback, threadHandle, (ULONG_PTR)apcParam))
+ {
+ unsigned long errorCode = GetLastError();
+ delete(apcParam);
+
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ return S_OK;
+}
+
+void CALLBACK DispatchCallbackApc::QueueApcCallback(ULONG_PTR user)
+{
+ DispatchCallbackApcParam *apcParam = (DispatchCallbackApcParam*)user;
+ if (NULL == apcParam)
+ return;
+
+ DispatchCallbackApc *apc = apcParam->GetApc();
+ if (NULL != apc)
+ apc->Call(apcParam->GetDispatch()),
+
+ delete(apcParam);
+}
+
+DispatchCallbackApcParam::DispatchCallbackApcParam(IDispatch *_dispatch, DispatchCallbackApc *_apc)
+ : dispatch(_dispatch), apc(_apc)
+{
+ if (NULL != dispatch && ((unsigned long)dispatch >= 65536))
+ dispatch->AddRef();
+
+ if (NULL != apc && ((unsigned long)apc >= 65536))
+ apc->AddRef();
+}
+
+DispatchCallbackApcParam::~DispatchCallbackApcParam()
+{
+ if (NULL != dispatch)
+ dispatch->Release();
+
+ if (NULL != apc)
+ apc->Release();
+}
+
+IDispatch *DispatchCallbackApcParam::GetDispatch()
+{
+ return dispatch;
+}
+
+DispatchCallbackApc *DispatchCallbackApcParam::GetApc()
+{
+ return apc;
+} \ No newline at end of file
diff --git a/Src/Winamp/dispatchCallback.h b/Src/Winamp/dispatchCallback.h
new file mode 100644
index 00000000..a5962988
--- /dev/null
+++ b/Src/Winamp/dispatchCallback.h
@@ -0,0 +1,150 @@
+#ifndef NULLSOFT_DISPATCHCALLBACK_H
+#define NULLSOFT_DISPATCHCALLBACK_H
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <windows.h>
+#include <oleauto.h>
+#include <vector>
+
+typedef void (*DispatchCallbackNotifyFunc)(IDispatch* /*dispatch*/, void* /*param*/);
+typedef void (*DispatchCallbackFreeFunc)(void* /*param*/);
+
+class DispatchCallback
+{
+protected:
+ DispatchCallback();
+ ~DispatchCallback();
+
+public:
+ static HRESULT CreateInstance(IDispatch *dispatch,
+ DispatchCallback **instance);
+
+public:
+ unsigned long AddRef();
+ unsigned long Release();
+
+ IDispatch *GetDispatch();
+ unsigned long GetThreadId();
+ HANDLE GetThreadHandle();
+
+protected:
+ unsigned long ref;
+ IDispatch *dispatch;
+ unsigned long threadId;
+ HANDLE threadHandle;
+
+};
+
+class DispatchCallbackEnum
+{
+protected:
+ DispatchCallbackEnum();
+ ~DispatchCallbackEnum();
+
+public:
+ static HRESULT CreateInstance(DispatchCallback **objects,
+ size_t count,
+ DispatchCallbackEnum **instance);
+
+public:
+ unsigned long AddRef();
+ unsigned long Release();
+
+public:
+ HRESULT Next(DispatchCallback **buffer, size_t bufferMax, size_t *fetched);
+ HRESULT Reset(void);
+ HRESULT Skip(size_t count);
+ HRESULT GetCount(size_t *count);
+
+ HRESULT Notify(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb, void *param);
+
+protected:
+ unsigned long ref;
+ DispatchCallback **buffer;
+ size_t size;
+ size_t cursor;
+};
+
+class DispatchCallbackStore
+{
+public:
+ DispatchCallbackStore();
+ ~DispatchCallbackStore();
+
+public:
+ void Lock();
+ void Unlock();
+ CRITICAL_SECTION *GetLock();
+
+ HRESULT Register(IDispatch *dispatch);
+ HRESULT Unregister(IDispatch *dispatch);
+ void UnregisterAll();
+ HRESULT Enumerate(DispatchCallbackEnum **enumerator);
+
+ /* Helpers*/
+ HRESULT RegisterFromDispParam(DISPPARAMS *pdispparams, unsigned int position, unsigned int *puArgErr);
+ HRESULT UnregisterFromDispParam(DISPPARAMS *pdispparams, unsigned int position, unsigned int *puArgErr);
+
+ HRESULT Notify(DispatchCallbackNotifyFunc notifyCb, DispatchCallbackFreeFunc freeCb, void *param);
+
+protected:
+ typedef std::vector<DispatchCallback*> CallbackList;
+
+protected:
+ CRITICAL_SECTION lock;
+ CallbackList list;
+
+};
+
+/* Internals */
+
+class DispatchCallbackApc
+{
+protected:
+ DispatchCallbackApc();
+ ~DispatchCallbackApc();
+
+public:
+ static HRESULT CreateInstance(DispatchCallbackNotifyFunc notifyCb,
+ DispatchCallbackFreeFunc freeCb,
+ void *param,
+ DispatchCallbackApc **instance);
+
+public:
+ unsigned long AddRef();
+ unsigned long Release();
+
+ HRESULT Call(IDispatch *dispatch);
+ HRESULT Queue(HANDLE threadHandle, IDispatch *dispatch);
+
+private:
+ static void CALLBACK QueueApcCallback(ULONG_PTR user);
+
+protected:
+ unsigned long ref;
+ DispatchCallbackNotifyFunc notifyCb;
+ DispatchCallbackFreeFunc freeCb;
+ void *param;
+
+};
+
+
+class DispatchCallbackApcParam
+{
+public:
+ DispatchCallbackApcParam(IDispatch *dispatch, DispatchCallbackApc *apc);
+ ~DispatchCallbackApcParam();
+
+public:
+ IDispatch *GetDispatch();
+ DispatchCallbackApc *GetApc();
+
+protected:
+ IDispatch *dispatch;
+ DispatchCallbackApc *apc;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/dpi.cpp b/Src/Winamp/dpi.cpp
new file mode 100644
index 00000000..a0ce3348
--- /dev/null
+++ b/Src/Winamp/dpi.cpp
@@ -0,0 +1,106 @@
+#include "main.h"
+#include "dpi.h"
+
+// DPI awareness based on http://msdn.microsoft.com/en-US/library/dd464660.aspx
+// Definition: relative pixel = 1 pixel at 96 DPI and scaled based on actual DPI.
+
+BOOL _fInitialized = FALSE;
+int _dpiX = 96, _dpiY = 96;
+
+void _Init()
+{
+ if (!_fInitialized)
+ {
+ HDC hdc = GetDC(NULL);
+ if (hdc)
+ {
+ _dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
+ _dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
+ ReleaseDC(NULL, hdc);
+ }
+ _fInitialized = TRUE;
+ }
+}
+
+// Get screen DPI.
+int GetDPIX()
+{
+ _Init();
+ return _dpiX;
+}
+
+int GetDPIY()
+{
+ _Init();
+ return _dpiY;
+}
+
+// Convert between raw pixels and relative pixels.
+int ScaleX(int x)
+{
+ _Init();
+ return MulDiv(x, _dpiX, 96);
+}
+
+int ScaleY(int y)
+{
+ _Init();
+ return MulDiv(y, _dpiY, 96);
+}
+
+int UnscaleX(int x)
+{
+ _Init();
+ return MulDiv(x, 96, _dpiX);
+}
+
+int UnscaleY(int y)
+{
+ _Init();
+ return MulDiv(y, 96, _dpiY);
+}
+
+int _ScaledSystemMetricX(int nIndex)
+{
+ _Init();
+ return MulDiv(GetSystemMetrics(nIndex), 96, _dpiX);
+}
+
+int _ScaledSystemMetricY(int nIndex)
+{
+ _Init();
+ return MulDiv(GetSystemMetrics(nIndex), 96, _dpiY);
+}
+
+// Determine the screen dimensions in relative pixels.
+int ScaledScreenWidth()
+{
+ return _ScaledSystemMetricX(SM_CXSCREEN);
+}
+
+int ScaledScreenHeight()
+{
+ return _ScaledSystemMetricY(SM_CYSCREEN);
+}
+
+// Scale rectangle from raw pixels to relative pixels.
+void ScaleRect(__inout RECT *pRect)
+{
+ pRect->left = ScaleX(pRect->left);
+ pRect->right = ScaleX(pRect->right);
+ pRect->top = ScaleY(pRect->top);
+ pRect->bottom = ScaleY(pRect->bottom);
+}
+
+// Determine if screen resolution meets minimum requirements in relative pixels.
+BOOL IsResolutionAtLeast(int cxMin, int cyMin)
+{
+ return (ScaledScreenWidth() >= cxMin) && (ScaledScreenHeight() >= cyMin);
+}
+
+// Convert a point size (1/72 of an inch) to raw pixels.
+int PointsToPixels(int pt)
+{
+ _Init();
+ return MulDiv(pt, _dpiY, 72);
+} \ No newline at end of file
diff --git a/Src/Winamp/dpi.h b/Src/Winamp/dpi.h
new file mode 100644
index 00000000..e657240d
--- /dev/null
+++ b/Src/Winamp/dpi.h
@@ -0,0 +1,46 @@
+#pragma once
+/*#ifndef _WA_DPI_H
+#define _WA_DPI_H*/
+
+#ifdef __cplusplus
+
+extern "C"
+{
+#endif
+
+#include <windows.h>
+
+// DPI awareness based on http://msdn.microsoft.com/en-US/library/dd464660.aspx
+// Definition: relative pixel = 1 pixel at 96 DPI and scaled based on actual DPI.
+
+// Get screen DPI.
+int GetDPIX();
+int GetDPIY();
+
+// Convert between raw pixels and relative pixels.
+int ScaleX(int x);
+int ScaleY(int y);
+int UnscaleX(int x);
+int UnscaleY(int y);
+
+int _ScaledSystemMetricX(int nIndex);
+int _ScaledSystemMetricY(int nIndex);
+
+// Determine the screen dimensions in relative pixels.
+int ScaledScreenWidth();
+int ScaledScreenHeight();
+
+// Scale rectangle from raw pixels to relative pixels.
+void ScaleRect(__inout RECT *pRect);
+
+// Determine if screen resolution meets minimum requirements in relative pixels.
+BOOL IsResolutionAtLeast(int cxMin, int cyMin);
+
+// Convert a point size (1/72 of an inch) to raw pixels.
+int PointsToPixels(int pt);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+//#endif \ No newline at end of file
diff --git a/Src/Winamp/draw.cpp b/Src/Winamp/draw.cpp
new file mode 100644
index 00000000..f47c22d9
--- /dev/null
+++ b/Src/Winamp/draw.cpp
@@ -0,0 +1,699 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include <stdio.h>
+#include "resource.h"
+#include "draw.h"
+#include "WADrawDC.h"
+
+//#define DEBUG_DRAW
+// time to fix reloading of main.bmp and just save a copy to restore with
+
+COLORREF mfont_bgcolor=RGB(0,0,0), mfont_fgcolor=RGB(0,255,0);
+int pe_fontheight=8;
+int mfont_height=6;
+HFONT font=0, mfont=0, shadefont=0, osdFontText=0;
+HBRUSH selbrush, normbrush, mfont_bgbrush;
+
+volatile int draw_initted;
+HDC mainDC, bmDC, specDC,mainDC2;
+HBITMAP mainBM_save, mainBM,shufflerepeatBM,
+ fontBM, specBM, oldMainBM, oldSpecBM;
+extern int sa_kill;
+static int palmode;
+HPALETTE draw_hpal=0;
+
+#ifdef DEBUG_DRAW
+static DWORD main_thread_id;
+#endif
+
+CRITICAL_SECTION g_mainwndcs, g_srcdccs;
+
+void draw_firstinit()
+{
+ InitializeCriticalSection(&g_srcdccs);
+ InitializeCriticalSection(&g_mainwndcs);
+#ifdef DEBUG_DRAW
+ main_thread_id=GetCurrentThreadId();
+#endif
+}
+
+void draw_finalquit()
+{
+ DeleteCriticalSection(&g_mainwndcs);
+ DeleteCriticalSection(&g_srcdccs);
+}
+
+HDC draw_GetWindowDC(HWND hwnd)
+{
+#ifdef DRAW_DEBUG
+ if (!hwnd)
+ {
+ MessageBox(NULL,"GWDC: hwnd=0","DRAW_DEBUG",0);
+ }
+#endif
+ HDC hdc;
+ EnterCriticalSection(&g_mainwndcs);
+ hdc = GetWindowDC(hwnd);
+#ifdef DRAW_DEBUG
+ if (!hdc)
+ {
+ MessageBox(NULL,"GWDC: hdc=0","DRAW_DEBUG",0);
+ }
+#endif
+ return hdc;
+}
+
+int draw_ReleaseDC(HWND hwnd, HDC hdc)
+{
+ int t=ReleaseDC(hwnd,hdc);
+#ifdef DRAW_DEBUG
+ if (!hwnd)
+ {
+ MessageBox(NULL,"RDC: hwnd=0","DRAW_DEBUG",0);
+ }
+ if (!hdc)
+ {
+ MessageBox(NULL,"RDC: hdc=0","DRAW_DEBUG",0);
+ }
+#endif
+ LeaveCriticalSection(&g_mainwndcs);
+ return t;
+}
+
+HBITMAP draw_LBitmap(LPCTSTR bmname, const wchar_t *filename)
+{
+ if (skin_directory[0] && filename) {
+ HBITMAP bm;
+ wchar_t bitmapfilename[MAX_PATH] = {0};
+ PathCombineW(bitmapfilename, skin_directory, filename);
+ bm = (HBITMAP)LoadImageW(hMainInstance, bitmapfilename, IMAGE_BITMAP, 0, 0, (palmode?LR_CREATEDIBSECTION:0)|LR_LOADFROMFILE);
+ if (bm) return bm;
+ }
+ if (bmname) return (HBITMAP)LoadImage(hMainInstance, bmname, IMAGE_BITMAP, 0, 0, (palmode?LR_CREATEDIBSECTION:0));
+ else return 0;
+}
+
+void do_palmode(HDC hdc)
+{
+ if (palmode)
+ {
+ SelectPalette(hdc,draw_hpal,FALSE);
+ RealizePalette(hdc);
+ }
+}
+
+int updateen=1;
+void update_area(int x1, int y1, int w, int h);
+
+void _setSrcBM(HBITMAP hbm
+#ifdef DEBUG_DRAW
+ , char *a
+#endif
+ )
+{
+ static HBITMAP old;
+#ifdef DEBUG_DRAW
+ if (!hbm && a)
+ {
+ char s[156] = {0};
+ wsprintf(s,"Invalid bitmap: %s",a);
+ DebugBreak();
+ MessageBox(NULL,s,"DRAW_DEBUG error",MB_OK);
+ }
+ if (main_thread_id != GetCurrentThreadId())
+ DebugBreak();//MessageBox(NULL,"Not in mainthread","DRAW_DEBUG error",MB_OK);
+ if (hbm && old)
+ {
+ char s[156] = {0};
+ StringCchPrintf(s,156,"Tried to set bitmap when bitmap already set: %s",a);
+ DebugBreak();
+ MessageBox(NULL,s,"DRAW_DEBUG error",MB_OK);
+ }
+ if (!hbm && !old)
+ {
+ DebugBreak();
+ MessageBox(NULL,"Tried to unset bitmap when bitmap not set","DRAW_DEBUG error",MB_OK);
+ }
+#endif
+ if (hbm)
+ {
+ EnterCriticalSection(&g_srcdccs);
+ old = (HBITMAP)SelectObject(bmDC,hbm);
+ }
+ else
+ {
+ SelectObject(bmDC,old); old=0;
+ LeaveCriticalSection(&g_srcdccs);
+ }
+}
+
+void draw_setnoupdate(int v)
+{
+ updateen=!v;
+ if (!v)
+ update_area(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
+}
+
+void draw_reinit_plfont(int update)
+{
+ EnterCriticalSection(&g_srcdccs);
+ {
+ HWND plw=hPLWindow;
+ wchar_t font_name[MAX_PATH] = {0};
+ int font_charset=DEFAULT_CHARSET;
+ TEXTMETRIC tm;
+ WADrawDC hdc(plw?plw:hMainWindow);
+ HANDLE holdf;
+
+ if (font) DeleteObject(font);
+ if (mfont) DeleteObject(mfont);
+ if (shadefont) DeleteObject(shadefont);
+ if (osdFontText) DeleteObject(osdFontText);
+ if (selbrush) DeleteObject(selbrush);
+ if (mfont_bgbrush) DeleteObject(mfont_bgbrush);
+ if (normbrush) DeleteObject(normbrush);
+ mfont_bgbrush=selbrush=normbrush=0;
+ font=0;
+ mfont=0;
+ shadefont=0;
+ osdFontText = NULL;
+
+ if (config_custom_plfont && *playlist_custom_fontW)
+ StringCchCopyW(font_name, sizeof(font_name), playlist_custom_fontW);
+ else
+ {
+ if (!Skin_PLFontW[0]) getStringW(IDS_PLFONT,font_name,sizeof(font_name)/sizeof(*font_name));
+ else StringCbCopyW(font_name,sizeof(font_name), Skin_PLFontW);
+ }
+
+ // TODO: verify the existance of the font and fall back to Arial if it doesn't exist
+ font_charset=atoi(getString(IDS_PLFONT_CHARSET,NULL,0));
+
+ font=CreateFontW(ScaleY(-config_pe_fontsize), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
+ font_charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY,
+ DEFAULT_PITCH | FF_DONTCARE, font_name);
+
+ mfont=CreateFontW(-10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
+ font_charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ (config_dsize && !config_bifont && config_bifont_alt ? ANTIALIASED_QUALITY : DRAFT_QUALITY),
+ DEFAULT_PITCH | FF_DONTCARE, font_name);
+
+ shadefont=CreateFontW(-8, 5, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
+ font_charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY,
+ DEFAULT_PITCH | FF_DONTCARE, font_name);
+
+ osdFontText = CreateFontW(OSD_TEXT_SIZE, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
+ font_charset, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, GetFontNameW());
+
+ holdf=SelectObject(hdc,font);
+ GetTextMetrics(hdc,&tm);
+ if (!plw) SelectObject(hdc,holdf);
+ pe_fontheight=tm.tmHeight;
+ if (pe_fontheight < 1) pe_fontheight=1;
+
+ holdf=SelectObject(hdc,mfont);
+ GetTextMetrics(hdc,&tm);
+ mfont_height=tm.tmHeight;
+ SelectObject(hdc,holdf);
+
+ {
+ int ld=0,y;
+ setSrcBM(fontBM);
+ mfont_fgcolor=mfont_bgcolor=GetPixel(bmDC,150,4);
+ for (y = 0; y < 6; y ++)
+ {
+ for (int x = 0; x < 20; x ++)
+ {
+ int d,a,b,c;
+ COLORREF r=GetPixel(bmDC,x,y);
+ a=(r&0xff)-(mfont_bgcolor&0xff);
+ b=(((r&0xff00)>>8)-((mfont_bgcolor&0xff00)>>8));
+ c=(((r&0xff0000)>>16)-((mfont_bgcolor&0xff0000)>>16));
+ d=(a*a+b*b+c*c);
+ if (d > ld) { ld=d; mfont_fgcolor=r; }
+ }
+ }
+ unsetSrcBM();
+ //mfont_fgcolor
+ }
+
+ {
+ LOGBRUSH lb={BS_SOLID};
+ lb.lbColor=GetNearestColor(hdc,Skin_PLColors[3]);
+ selbrush = CreateBrushIndirect(&lb);
+ lb.lbColor=GetNearestColor(hdc,Skin_PLColors[2]);
+ normbrush = CreateBrushIndirect(&lb);
+ lb.lbColor=mfont_bgcolor;
+ mfont_bgbrush = CreateBrushIndirect(&lb);
+ }
+ }
+ LeaveCriticalSection(&g_srcdccs);
+
+ if (update) PostMessageW(hMainWindow, WM_WA_IPC, 0, IPC_CB_RESETFONT);
+}
+
+static struct
+{
+ BITMAPINFO bmi;
+ RGBQUAD more_bm7iColors[256];
+} bitmap;
+
+static void CopyToMainBM()
+{
+ HDC hdc = CreateCompatibleDC(mainDC);
+ HBITMAP oldbm = (HBITMAP)SelectObject(hdc,mainBM_save);
+ BitBlt(mainDC,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,hdc,0,0,SRCCOPY);
+ SelectObject(hdc,oldbm);
+ DeleteDC(hdc);
+}
+
+void draw_init()
+{
+ HDC screenHdc;
+ EnterCriticalSection(&g_srcdccs);
+ if (draw_initted) draw_kill();
+ screenHdc = draw_GetWindowDC(hMainWindow);
+ palmode = GetDeviceCaps(screenHdc,RASTERCAPS)&RC_PALETTE?1:0;
+ mainDC = CreateCompatibleDC(screenHdc);
+ mainDC2 = CreateCompatibleDC(screenHdc);
+
+ bmDC = CreateCompatibleDC(screenHdc);
+ specDC = CreateCompatibleDC(screenHdc);
+ mainBM_save = draw_LBitmap(MAKEINTRESOURCE(IDB_MAINBITMAP),L"main.bmp");
+ oldMainBM = (HBITMAP)SelectObject(mainDC,mainBM_save);
+ mainBM = CreateCompatibleBitmap(mainDC,WINDOW_WIDTH,WINDOW_HEIGHT);
+ SelectObject(mainDC,mainBM);
+ CopyToMainBM();
+
+ embedBM = draw_LBitmap(MAKEINTRESOURCE(IDB_EMBEDWND),L"gen.bmp");
+ {
+ COLORREF start;
+ int x;
+ int pos=0;
+ setSrcBM(embedBM);
+ if ((start = GetPixel(bmDC,0,90)) != CLR_INVALID)
+ {
+
+ for (x = 0; x < 26; x ++)
+ {
+ int cnt=0;
+ while (GetPixel(bmDC,pos,90) == start) pos++;
+
+ titlebar_font_offsets[x]=pos;
+ for (;;)
+ {
+ COLORREF t=GetPixel(bmDC,pos,90);
+ if (t == CLR_INVALID) break;
+ pos++;
+ if (t == start)
+ {
+ titlebar_font_widths[x]=cnt;
+ break;
+ }
+ else cnt++;
+ }
+ }
+ }
+
+ if ((start = GetPixel(bmDC,0,74)) != CLR_INVALID)
+ {
+ pos = 0;
+ for (x = 0; x < 12; x ++)
+ {
+ int cnt=0;
+ while (GetPixel(bmDC,pos,74) == start) pos++;
+
+ titlebar_font_num_offsets[x]=pos;
+ for (;;)
+ {
+ COLORREF t=GetPixel(bmDC,pos,74);
+ if (t == CLR_INVALID) break;
+ pos++;
+ if (t == start)
+ {
+ titlebar_font_num_widths[x]=cnt;
+ break;
+ }
+ else cnt++;
+ }
+ }
+ }
+ unsetSrcBM();
+ }
+
+ cbuttonsBM = draw_LBitmap(MAKEINTRESOURCE(IDB_CBUTTONS),L"cbuttons.bmp");
+ monostereoBM = draw_LBitmap(MAKEINTRESOURCE(IDB_MONOSTEREO),L"monoster.bmp");
+ playpauseBM = draw_LBitmap(MAKEINTRESOURCE(IDB_PLAYPAUSE),L"playpaus.bmp");
+ shufflerepeatBM = draw_LBitmap(MAKEINTRESOURCE(IDB_SHUFFLEREP),L"shufrep.bmp");
+ numbersBM_ex = draw_LBitmap(NULL,L"nums_ex.bmp");
+ if (!numbersBM_ex) numbersBM = draw_LBitmap(MAKEINTRESOURCE(IDB_NUMBERS1),L"numbers.bmp");
+ else numbersBM=NULL;
+ volBM = draw_LBitmap(MAKEINTRESOURCE(IDB_VOLBAR),L"volume.bmp");
+ if (skin_directory[0])
+ panBM = draw_LBitmap(NULL,L"balance.bmp");
+ else
+ panBM = draw_LBitmap(MAKEINTRESOURCE(IDB_PANBAR),NULL);
+ if (!panBM) panBM=volBM;
+ fontBM = draw_LBitmap(MAKEINTRESOURCE(IDB_FONT1),L"text.bmp");
+ posbarBM = draw_LBitmap(MAKEINTRESOURCE(IDB_POSBAR),L"posbar.bmp");
+ tbBM = draw_LBitmap(MAKEINTRESOURCE(IDB_TB),L"titlebar.bmp");
+
+ {
+ int c;
+ static unsigned char ppal2[] = {
+ 0,0,0, // color 0 = black
+ 24,24,41, // color 1 = grey for dots
+ 239,49,16, // color 2 = top of spec
+ 206,41,16, // 3
+ 214,90,0, // 4
+ 214,102,0, // 5
+ 214,115,0, // 6
+ 198,123,8, // 7
+ 222,165,24, // 8
+ 214,181,33, // 9
+ 189,222,41, // 10
+ 148,222,33, // 11
+ 41,206,16, // 12
+ 50,190,16, // 13
+ 57,181,16, // 14
+ 49,156,8, // 15
+ 41,148,0, // 16
+ 24,132,8, // 17
+ 255,255,255, // 18 = osc 1
+ 214,214,222, // 19 = osc 2 (slightly dimmer)
+ 181,189,189, // 20 = osc 3
+ 160,170,175, // 21 = osc 4
+ 148,156,165, // 22 = osc 4
+ 150, 150, 150, // 23 = analyzer peak
+ };
+ unsigned char ppal[sizeof(ppal2)];
+ memcpy(ppal,ppal2,sizeof(ppal2));
+ if (skin_directory[0])
+ {
+ FILE *fp;
+ wchar_t bitmapfilename[MAX_PATH] = {0};
+ PathCombineW(bitmapfilename, skin_directory, L"viscolor.txt");
+ fp = _wfopen(bitmapfilename,L"rt");
+ if (fp)
+ {
+ int x;
+ for (x = 0; x < 24; x ++)
+ {
+ int t;
+ char progdir[91],*p=progdir;
+ fgets(progdir,90,fp);
+ if (feof(fp)) break;
+ for (t=0; t<3; t ++)
+ {
+ int b=0,s=0;
+ while (p && (*p == ' ' || *p == ',' || *p == '\t')) p++;
+ while (p && *p >= '0' && *p <= '9') {s=1;b=b*10+*p++-'0';}
+ if (!s) { x=24; break; }
+ ppal[x*3+t]=b;
+ }
+ }
+ fclose(fp);
+ }
+ }
+ for (c = 0; c < sizeof(ppal)/(3); c ++) {
+ bitmap.bmi.bmiColors[c].rgbRed = ppal[c*3];
+ bitmap.bmi.bmiColors[c].rgbGreen = ppal[c*3+1];
+ bitmap.bmi.bmiColors[c].rgbBlue = ppal[c*3+2];
+ bitmap.bmi.bmiColors[c].rgbReserved = 0;
+ }
+ bitmap.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmap.bmi.bmiHeader.biPlanes = 1;
+ bitmap.bmi.bmiHeader.biBitCount = 8;
+ bitmap.bmi.bmiHeader.biCompression = BI_RGB;
+ bitmap.bmi.bmiHeader.biClrUsed = sizeof(ppal)/(3);
+ bitmap.bmi.bmiHeader.biClrImportant = sizeof(ppal)/(3);
+ bitmap.bmi.bmiHeader.biWidth = 76*2;
+ bitmap.bmi.bmiHeader.biHeight = 16*2;
+ bitmap.bmi.bmiHeader.biSizeImage = 76*16*4;
+ specBM = CreateDIBSection(specDC,&bitmap.bmi,DIB_RGB_COLORS, (LPVOID*)&specData, NULL, 0);
+ oldSpecBM = (HBITMAP)SelectObject(specDC,specBM);
+ memset(specData,0,76*16*4);
+ }
+
+ if (palmode)
+ {
+ RGBQUAD rgb[256] = {0};
+ int x;
+ struct {
+ LOGPALETTE lpal;
+ PALETTEENTRY pal[256];
+ } lPal;
+ GetDIBColorTable(mainDC,0,256,rgb);
+ lPal.lpal.palVersion = 0x300;
+ lPal.lpal.palNumEntries = 256;
+ for (x = 0; x < 256; x ++)
+ {
+ lPal.lpal.palPalEntry[x].peRed = rgb[x].rgbRed;
+ lPal.lpal.palPalEntry[x].peGreen = rgb[x].rgbGreen;
+ lPal.lpal.palPalEntry[x].peBlue = rgb[x].rgbBlue;
+ lPal.lpal.palPalEntry[x].peFlags = 0;
+ }
+
+ draw_hpal = CreatePalette((LPLOGPALETTE)&lPal);
+ }
+ else draw_hpal = 0;
+ draw_ReleaseDC(hMainWindow,screenHdc);
+
+ draw_initted=1;
+
+ draw_reinit_plfont(1);
+ sa_kill = 0;
+ draw_pe_init();
+ draw_eq_init();
+ draw_vw_init();
+ LeaveCriticalSection(&g_srcdccs);
+}
+
+void draw_kill()
+{
+ int old_sa_mode = sa_curmode;
+ sa_setthread(-1);
+ sa_kill = 1;
+ while (sa_safe>0)
+ Sleep(50);
+ sa_setthread(old_sa_mode);
+ if (!draw_initted) return;
+ EnterCriticalSection(&g_srcdccs);
+ sa_safe=0;
+ draw_initted=0;
+ specData=0;
+ DeleteObject(mainBM_save);
+ SelectObject(mainDC,oldMainBM);
+
+ SelectObject(specDC,oldSpecBM);
+
+ if (mainBM2)
+ {
+ SelectObject(mainDC2,oldmainBM2);
+ DeleteObject(mainBM2);
+ mainBM2=NULL;
+ }
+
+ DeleteObject(embedBM);
+
+ DeleteDC(mainDC);
+ DeleteDC(specDC);
+ DeleteDC(mainDC2);
+ DeleteDC(bmDC);
+
+ DeleteObject(mainBM);
+ DeleteObject(cbuttonsBM);
+ DeleteObject(monostereoBM);
+ DeleteObject(shufflerepeatBM);
+ DeleteObject(playpauseBM);
+ if (numbersBM) DeleteObject(numbersBM);
+ if (numbersBM_ex) DeleteObject(numbersBM_ex);
+ if (panBM != volBM) DeleteObject(panBM);
+
+ DeleteObject(volBM);
+ DeleteObject(fontBM);
+ DeleteObject(posbarBM);
+ DeleteObject(specBM);
+ DeleteObject(tbBM);
+ if (draw_hpal) DeleteObject(draw_hpal);
+ draw_hpal = 0;
+ if (font) DeleteObject(font);
+ if (mfont) DeleteObject(mfont);
+ if (shadefont) DeleteObject(shadefont);
+ if (osdFontText) DeleteObject(osdFontText);
+ if (selbrush) DeleteObject(selbrush);
+ if (mfont_bgbrush) DeleteObject(mfont_bgbrush);
+ if (normbrush) DeleteObject(normbrush);
+ mfont_bgbrush=selbrush=normbrush=0;
+ shadefont=mfont=font=0;
+ LeaveCriticalSection(&g_srcdccs);
+}
+
+void draw_clear()
+{
+ RECT r;
+ if (!draw_initted) return;
+ CopyToMainBM();
+ draw_playicon(2);
+ GetClientRect(hMainWindow,&r);
+ draw_tbar(config_hilite?(GetForegroundWindow() == hMainWindow?1:0):1, config_windowshade,0);
+ update_area(0,0,r.right,r.bottom);
+}
+
+void draw_clutterbar(int enable)
+{
+ int x,y;
+ if (!draw_initted) return;
+ if (config_ascb_new && !enable) enable=1;
+ if (!enable)
+ {
+ x=8;
+ y=0;
+ }
+ else if (enable == 1)
+ {
+ x=0;
+ y=0;
+ }
+ else
+ {
+ y=44;
+ x=(enable-2)*8;
+ }
+ setSrcBM(tbBM);
+ BitBlt(mainDC,10,22,18-10,65-22,bmDC,304+x,y,SRCCOPY);
+ if (enable != 3 && (config_ascb_new||enable))
+ {
+ if (config_aot)
+ {
+ BitBlt(mainDC,11,22+11,18-10-1,65-22-34-1,bmDC,312+1,44+11,SRCCOPY);
+ }
+ else
+ BitBlt(mainDC,11,22+11,18-10-1,65-22-34-1,bmDC,304+1,11,SRCCOPY);
+ }
+ if (enable != 5 && (config_ascb_new||enable))
+ {
+ if (config_dsize)
+ {
+ BitBlt(mainDC,11,22+27,18-10-1,6,bmDC,328+1,44+27,SRCCOPY);
+ }
+ else
+ BitBlt(mainDC,11,22+27,18-10-1,6,bmDC,304+1,27,SRCCOPY);
+ }
+ unsetSrcBM();
+ update_area(10,22,8,65-22);
+}
+
+void update_area(int x1, int y1, int w, int h)
+{
+ if (updateen && hMainWindow)
+ {
+ WADrawDC tDC(hMainWindow);
+ if (tDC)
+ {
+ do_palmode(tDC);
+ if (!config_dsize)
+ {
+ BitBlt(tDC,x1,y1,w,h,mainDC,x1,y1,SRCCOPY);
+ if (mainBM2)
+ {
+ SelectObject(mainDC2,oldmainBM2);
+ DeleteObject(mainBM2);
+ mainBM2=NULL;
+ }
+ }
+ else
+ {
+ if (!mainBM2)
+ {
+ mainBM2 = CreateCompatibleBitmap(mainDC,WINDOW_WIDTH*2,WINDOW_HEIGHT*2);
+ oldmainBM2 = (HBITMAP)SelectObject(mainDC2,mainBM2);
+ x1=y1=0;
+ w=WINDOW_WIDTH;
+ h=WINDOW_HEIGHT;
+ }
+ StretchBlt(mainDC2,x1*2,y1*2,w*2,h*2,mainDC,x1,y1,w,h,SRCCOPY);
+ BitBlt(tDC,x1*2,y1*2,w*2,h*2,mainDC2,x1*2,y1*2,SRCCOPY);
+ }
+ }
+ }
+}
+
+void getXYfromChar(wchar_t ic, int *x, int *y)
+{
+ int c,c2=0;
+ switch (ic)
+ {
+ case L'°': ic = L'0'; break;
+ case L'Ç': ic = L'C'; break;
+ case L'ü': ic = L'u'; break;
+ case L'è': case L'ë': case L'ê': case L'é': ic = L'e'; break;
+ case L'á': case L'à': case L'â': ic = L'a'; break;
+ case L'ç': ic = L'c'; break;
+ case L'í': case L'ì': case L'î': case L'ï': ic = L'i'; break;
+ case L'É': ic = L'E'; break;
+ case L'æ': ic = L'a'; break;
+ case L'Æ': ic = L'A'; break;
+ case L'ó': case L'ò': case L'ô': ic = L'o'; break;
+ case L'ú': case L'ù': case L'û': ic = L'u'; break;
+ case L'ÿ': ic = L'y'; break;
+ case L'Ü': ic = L'U'; break;
+ case L'ƒ': ic = L'f'; break;
+ case L'Ñ': case L'ñ': ic = L'n'; break;
+ default: break;
+ } // quick relocations
+ if (ic <= L'Z' && ic >= L'A') c = (ic-'A');
+ else if (ic <= L'z' && ic >= L'a') c = (ic-'a');
+ else
+ {
+ c2 = 6;
+ if (ic == L'\1') c=10;
+ else if (ic == L'.') c = 11;
+ else if (ic <= L'9' && ic >= L'0') c = ic - '0';
+ else if (ic == L':') c = 12;
+ else if (ic == L'(') c = 13;
+ else if (ic == L')') c = 14;
+ else if (ic == L'-') c = 15;
+ else if (ic == L'\'' || ic=='`') c = 16;
+ else if (ic == L'!') c = 17;
+ else if (ic == L'_') c = 18;
+ else if (ic == L'+') c = 19;
+ else if (ic == L'\\') c = 20;
+ else if (ic == L'/') c = 21;
+ else if (ic == L'[' || ic == L'{' || ic == L'<') c = 22;
+ else if (ic == L']' || ic == L'}' || ic == L'>') c = 23;
+ else if (ic == L'~' || ic == L'^') c = 24;
+ else if (ic == L'&') c = 25;
+ else if (ic == L'%') c = 26;
+ else if (ic == L',') c = 27;
+ else if (ic == L'=') c = 28;
+ else if (ic == L'$') c = 29;
+ else if (ic == L'#') c = 30;
+ else
+ {
+ c2=12;
+ if (ic == L'Å' || ic == L'å') c = 0;
+ else if (ic == L'Ö' || ic == L'ö') c = 1;
+ else if (ic == L'Ä' || ic == L'ä') c = 2;
+ else if (ic == L'?') c = 3;
+ else if (ic == L'*') c = 4;
+ else
+ {
+ c2 = 0;
+ if (ic == L'"') c = 26;
+ else if (ic == L'@') c = 27;
+ else c = 30;
+ }
+ }
+ }
+ c*=5;
+ *x=c;
+ *y=c2;
+} \ No newline at end of file
diff --git a/Src/Winamp/draw.h b/Src/Winamp/draw.h
new file mode 100644
index 00000000..da124636
--- /dev/null
+++ b/Src/Winamp/draw.h
@@ -0,0 +1,60 @@
+#ifndef NULLSOFT_DRAWH
+#define NULLSOFT_DRAWH
+
+#include <windows.h>
+#include "Main.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef DEBUG_DRAW
+#define setSrcBM(x) _setSrcBM(x,#x)
+#define unsetSrcBM() _setSrcBM(0, 0)
+#else
+#define setSrcBM(x) _setSrcBM(x)
+#define unsetSrcBM() _setSrcBM(0)
+#endif
+
+#define OSD_TEXT_SIZE 28
+
+#ifdef DEBUG_DRAW
+void _setSrcBM(HBITMAP hbm, char *a);
+#else
+void _setSrcBM(HBITMAP hbm);
+#endif
+
+#define update_rect(r) update_area((r).left,(r).top,(r).right-(r).left,(r).bottom-(r).top)
+void update_area(int x1, int y1, int w, int h);
+
+HBITMAP draw_LBitmap(LPCTSTR bmname, const wchar_t *filename);
+HDC draw_GetWindowDC(HWND hwnd);
+int draw_ReleaseDC(HWND hwnd, HDC hdc);
+void getXYfromChar(wchar_t ic, int *x, int *y);
+void do_palmode(HDC hdc);
+
+extern COLORREF mfont_bgcolor, mfont_fgcolor;
+extern unsigned char *specData;
+extern int sa_safe;
+extern int disable_skin_borders;
+extern int mfont_height;
+extern int g_has_deleted_current;
+extern volatile int draw_initted;
+
+extern HFONT font, mfont, shadefont, osdFontText;
+extern HBRUSH selbrush, normbrush, mfont_bgbrush;
+extern HBITMAP fontBM, embedBM, panBM, shufflerepeatBM, tbBM,
+ cbuttonsBM, volBM,mainBM2, oldmainBM2, numbersBM,
+ numbersBM_ex, playpauseBM, posbarBM, monostereoBM;
+extern HDC bmDC, mainDC, specDC, mainDC2;
+extern CRITICAL_SECTION g_mainwndcs, g_srcdccs;
+extern int titlebar_font_offsets[26];
+extern int titlebar_font_widths[26];
+extern int titlebar_font_num_offsets[12];
+extern int titlebar_font_num_widths[12];
+extern int titlebar_font_unknown_width;
+extern int updateen;
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/draw_embed.cpp b/Src/Winamp/draw_embed.cpp
new file mode 100644
index 00000000..345ae7ce
--- /dev/null
+++ b/Src/Winamp/draw_embed.cpp
@@ -0,0 +1,243 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "draw.h"
+
+HBITMAP embedBM;
+
+int titlebar_font_widths[26] = {0};
+int titlebar_font_offsets[26] = {0};
+int titlebar_font_num_widths[12] = {0};
+int titlebar_font_num_offsets[12] = {0};
+int titlebar_font_unknown_width = 5;
+
+static int calcTBFontTextWidth(char *text)
+{
+ int w=0;
+ while (text && *text)
+ {
+ char c=*text++;
+ if (c >= 'a' && c <= 'z') c+='A'-'a';
+
+ if (c >= 'A' && c <= 'Z' && titlebar_font_widths[c-'A'])
+ w+=titlebar_font_widths[c-'A'];
+ else if (c >= '0' && c <= '9' && titlebar_font_widths[c-'0'] && Skin_UseGenNums)
+ w+=titlebar_font_num_widths[c-'0'];
+ else if (c == '-' && titlebar_font_widths[10] && Skin_UseGenNums)
+ w+=titlebar_font_num_widths[10];
+ else if (c == ':' && titlebar_font_widths[11] && Skin_UseGenNums)
+ w+=titlebar_font_num_widths[11];
+ else w+=titlebar_font_unknown_width;
+ }
+ return w;
+}
+
+static void drawTBText(HDC hdcout,int xp, int yp, char *buf, int maxw, int sel)
+{
+ while (buf && *buf)
+ {
+ char c=*buf++;
+ int w=titlebar_font_unknown_width;
+ if (c >= 'a' && c <= 'z') c+='A'-'a';
+
+ if (c >= 'A' && c <= 'Z' && titlebar_font_widths[c-'A'])
+ {
+ w=titlebar_font_widths[c-'A'];
+ if (w > maxw) break;
+ BitBlt(hdcout,xp,yp,w,7,bmDC,titlebar_font_offsets[c-'A'],88+(sel?8:0),SRCCOPY);
+ }
+ else if (c >= '0' && c <= '9' && titlebar_font_num_widths[c-'0'] && Skin_UseGenNums)
+ {
+ w=titlebar_font_num_widths[c-'0'];
+ if (w > maxw) break;
+ BitBlt(hdcout,xp,yp,w,7,bmDC,titlebar_font_num_offsets[c-'0'],72+(sel?8:0),SRCCOPY);
+ }
+ else if (c == '-' && titlebar_font_num_widths[10] && Skin_UseGenNums)
+ {
+ w=titlebar_font_num_widths[10];
+ if (w > maxw) break;
+ BitBlt(hdcout,xp,yp,w,7,bmDC,titlebar_font_num_offsets[10],72+(sel?8:0),SRCCOPY);
+ }
+ else if (c == ':' && titlebar_font_num_widths[11] && Skin_UseGenNums)
+ {
+ w=titlebar_font_num_widths[11];
+ if (w > maxw) break;
+ BitBlt(hdcout,xp,yp,w,7,bmDC,titlebar_font_num_offsets[11],72+(sel?8:0),SRCCOPY);
+ }
+ xp+=w;
+ maxw-=w;
+ }
+}
+
+void draw_embed_tbar(HWND hwnd, int state, int w)
+{
+ if (!disable_skin_borders)
+ {
+ HDC hdcout=GetWindowDC(hwnd);
+ char buf[32] = {0};
+ state = state?0:21;
+ do_palmode(hdcout);
+ setSrcBM(embedBM);
+ GetWindowTextA(hwnd,buf,sizeof(buf)/sizeof(char)-1);
+ buf[31]=0;
+ {
+ int textw_exact=calcTBFontTextWidth(buf);
+ int nt;
+ int xp=0;
+
+ int textw=textw_exact + 24;
+ textw -= textw % 25;
+
+ if (textw > w-100) textw=w-100;
+
+ BitBlt(hdcout,xp,0,25,20,bmDC,0,state,SRCCOPY);
+ xp+=25;
+ nt = (w - 100 - textw)/25;
+ if (nt)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdcout,xp,0,12,20,bmDC,104,state,SRCCOPY);
+ xp+=12;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdcout,xp,0,25,20,bmDC,104,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+
+ BitBlt(hdcout,xp,0,25,20,bmDC,26,state,SRCCOPY);
+ xp+=25;
+
+ nt = textw/25;
+ if (nt)
+ {
+ int xstart=xp + (textw - textw_exact)/2;
+ if (textw != textw_exact) xstart++;
+ while (nt-->0)
+ {
+ BitBlt(hdcout,xp,0,25,20,bmDC,52,state,SRCCOPY);
+ xp+=25;
+ }
+ drawTBText(hdcout,xstart,4,buf,textw,state);
+ }
+
+ BitBlt(hdcout,xp,0,25,20,bmDC,78,state,SRCCOPY);
+ xp+=25;
+
+ nt = (w - 100 - textw)/25;
+ if (nt)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdcout,xp,0,13,20,bmDC,104,state,SRCCOPY);
+ xp+=13;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdcout,xp,0,25,20,bmDC,104,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+ nt = (w - 100 - textw) % 25;
+ if (nt>0)
+ {
+ StretchBlt(hdcout,xp,0,nt,20,bmDC,104,state,25,20,SRCCOPY);
+ xp+=nt;
+ }
+ BitBlt(hdcout,xp,0,25,20,bmDC,130,state,SRCCOPY);
+ }
+ unsetSrcBM();
+ ReleaseDC(hwnd,hdcout);
+ }
+}
+
+void draw_embed(HWND hwnd, HDC hdcout, int w, int h, int flags)
+{
+ if (!disable_skin_borders)
+ {
+ do_palmode(hdcout);
+ {
+ // fg>this is here in case a child temporarily unparents itself from the embedwnd, like avs when it docks to its editor.
+ // when the child is there, fillrect is clipped
+ RECT r={11,20,w-8, h-14};
+ FillRect(hdcout, &r, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ }
+ draw_embed_tbar(hwnd,GetForegroundWindow()==hwnd?1:(config_hilite?0:1),w);
+ setSrcBM(embedBM);
+ {
+ int y=(h-20-38)/29;
+ int yp=20,x,xp;
+ while (y-->0)
+ {
+ BitBlt(hdcout,0,yp,11,29,bmDC,127,42,SRCCOPY);
+ BitBlt(hdcout,w-8,yp,8,29,bmDC,139,42,SRCCOPY);
+ yp += 29;
+ }
+ y=(h-20-38)%29;
+ if (y)
+ {
+ StretchBlt(hdcout,0,yp,11,y,bmDC,127,42,11,29,SRCCOPY);
+ StretchBlt(hdcout,w-8,yp,8,y,bmDC,139,42,8,29,SRCCOPY);
+ yp += y;
+ }
+
+ // 24 pixel lamity
+ BitBlt(hdcout,0,yp,11,24,bmDC,158,42,SRCCOPY);
+ BitBlt(hdcout,w-8,yp,8,24,bmDC,170,42,SRCCOPY);
+ yp += 24;
+
+ BitBlt(hdcout,0,yp,125,14,bmDC,0,42,SRCCOPY);
+ x=(w-125-125)/25;
+ xp=125;
+ while (x-->0)
+ {
+ BitBlt(hdcout,xp,yp,25,14,bmDC,127,72,SRCCOPY);
+ xp+=25;
+ }
+ x=(w-125-125)%25;
+ if (x)
+ {
+ StretchBlt(hdcout,xp,yp,x,14,bmDC,127,72,25,14,SRCCOPY);
+ xp+=x;
+ }
+ BitBlt(hdcout,xp,yp,125,14,bmDC,0,57,SRCCOPY);
+ if (flags & EMBED_FLAGS_NORESIZE)
+ {
+ BitBlt(hdcout,xp+112,yp+2,7,7,bmDC,118,72,SRCCOPY);
+ }
+ }
+ unsetSrcBM();
+ }
+}
+
+void draw_paint_emb(HWND hwnd, int w, int h, int flags)
+{
+ PAINTSTRUCT ps;
+ draw_embed(hwnd,BeginPaint(hwnd,&ps),w,h,flags);
+ EndPaint(hwnd,&ps);
+}
+
+void draw_embed_tbutton(HWND hwnd, int b3, int w)
+{
+ if (!disable_skin_borders)
+ {
+ HDC hdcout=GetWindowDC(hwnd);
+ do_palmode(hdcout);
+ setSrcBM(embedBM);
+ if (!b3)
+ BitBlt(hdcout,w-11,3,9,9,bmDC,144,3,SRCCOPY);
+ else
+ BitBlt(hdcout,w-11,3,9,9,bmDC,148,42,SRCCOPY);
+ unsetSrcBM();
+ ReleaseDC(hwnd,hdcout);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/draw_eq.cpp b/Src/Winamp/draw_eq.cpp
new file mode 100644
index 00000000..4d89e44e
--- /dev/null
+++ b/Src/Winamp/draw_eq.cpp
@@ -0,0 +1,329 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "draw.h"
+#include "plush/plush.h"
+#include "WinampAttributes.h"
+#include "resource.h"
+#include "WADrawDC.h"
+
+HDC eqMainDC, eqMainDC2;
+int enable_eq_windowshade_button;
+HBITMAP eqMainBM = NULL, eqMainBM2 = NULL, eqExBM = NULL, eqOldmainBM2 = NULL, eqOldmainBM = NULL;
+
+extern "C" int eq_init = 0;
+void draw_eq_init()
+{
+ EnterCriticalSection(&g_srcdccs);
+ if (eq_init)
+ draw_eq_kill();
+
+ eq_init=1;
+ HDC screenHdc = draw_GetWindowDC(hMainWindow);
+
+ eqMainDC = CreateCompatibleDC(screenHdc);
+ eqMainDC2 = CreateCompatibleDC(screenHdc);
+
+ enable_eq_windowshade_button = 2;
+
+ // attempt to use the ISO eq image (if present)
+ if(config_eq_frequencies!=EQ_FREQUENCIES_WINAMP)
+ eqMainBM = draw_LBitmap(NULL, L"eqmain_iso.bmp");
+ // otherwise we revert to the normal eq image
+ if (!eqMainBM)
+ eqMainBM = draw_LBitmap(NULL, L"eqmain.bmp");
+ if (eqMainBM)
+ enable_eq_windowshade_button = 0;
+ // and if that fails then we revert to the built in classic skin resources
+ else
+ eqMainBM = draw_LBitmap(MAKEINTRESOURCE((config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?IDB_EQMAIN:IDB_EQMAIN_ISO), NULL);
+ eqOldmainBM = (HBITMAP)SelectObject(eqMainDC, eqMainBM);
+
+ eqExBM = draw_LBitmap(NULL, L"eq_ex.bmp");
+ if (!eqExBM)
+ {
+ if (!skin_directory[0])
+ enable_eq_windowshade_button = 1;
+ eqExBM = draw_LBitmap(MAKEINTRESOURCE(IDB_EQEX), NULL);
+ }
+ else
+ enable_eq_windowshade_button = 1;
+
+ draw_ReleaseDC(hMainWindow, screenHdc);
+
+ int x;
+ draw_eq_slid(0,config_preamp,0);
+ for (x = 1; x <= 10; x ++)
+ draw_eq_slid(x,eq_tab[x-1],0);
+ draw_eq_graphthingy();
+ draw_eq_onauto(config_use_eq, config_autoload_eq, 0,0);
+ draw_eq_tbar(GetForegroundWindow()==hEQWindow?1:(config_hilite?0:1));
+ draw_eq_presets(0);
+
+ LeaveCriticalSection(&g_srcdccs);
+}
+
+void draw_eq_kill()
+{
+ if (!eq_init)
+ return ;
+ EnterCriticalSection(&g_srcdccs);
+ SelectObject(eqMainDC, eqOldmainBM);
+ DeleteObject(eqMainBM);
+ eqMainBM = NULL;
+
+ if (eqMainBM2)
+ {
+ SelectObject(eqMainDC2, eqOldmainBM2);
+ DeleteObject(eqMainBM2);
+ eqMainBM2 = NULL;
+ }
+
+ DeleteDC(eqMainDC);
+ DeleteDC(eqMainDC2);
+
+ if (eqExBM)
+ DeleteObject(eqExBM);
+ eqExBM=NULL;
+ LeaveCriticalSection(&g_srcdccs);
+}
+
+static void update_area_eq(int x1, int y1, int w, int h)
+{
+ if (updateen && hEQWindow)
+ {
+ WADrawDC tDC(hEQWindow);
+ if (tDC && hEQWindow)
+ {
+ do_palmode(tDC);
+ if (!(config_dsize && config_eqdsize))
+ {
+ BitBlt(tDC, x1, y1, w, h, eqMainDC, x1, y1, SRCCOPY);
+ if (eqMainBM2)
+ {
+ SelectObject(eqMainDC2, eqOldmainBM2);
+ DeleteObject(eqMainBM2);
+ eqMainBM2 = NULL;
+ }
+ }
+ else
+ {
+ if (!eqMainBM2)
+ {
+ eqMainBM2 = CreateCompatibleBitmap(mainDC, WINDOW_WIDTH * 2, WINDOW_HEIGHT * 2);
+ eqOldmainBM2 = (HBITMAP)SelectObject(eqMainDC2, eqMainBM2);
+ x1 = y1 = 0;
+ w = WINDOW_WIDTH;
+ h = WINDOW_HEIGHT;
+ }
+ StretchBlt(eqMainDC2, x1*2, y1*2, w*2, h*2, eqMainDC, x1, y1, w, h, SRCCOPY);
+ BitBlt(tDC, x1*2, y1*2, w*2, h*2, eqMainDC2, x1*2, y1*2, SRCCOPY);
+ }
+ }
+ }
+}
+
+void draw_eq_presets(int pressed)
+{
+ int top = 18, left = 217;
+ int w = 44;
+ int h = 12;
+ BitBlt(eqMainDC, left, top, w, h, eqMainDC, 224, pressed ? 176 : 164, SRCCOPY);
+ update_area_eq(left, top, w, h);
+}
+
+void draw_eq_tbar(int active)
+{
+ int l = active ? 134 : 149;
+ if (!eq_init) return ;
+ if (config_eq_ws)
+ {
+ int xo = 63;
+ int p = 94;
+ int r;
+ int xx = config_volume * 3 / 256;
+ setSrcBM(eqExBM);
+ BitBlt(eqMainDC, 0, 0, WINDOW_WIDTH, 14, bmDC, 0, active ? 0 : 15, SRCCOPY);
+ r = xo + (p * config_volume) / 255;
+ BitBlt(eqMainDC, r - 2, 4, 3, 7, bmDC, xx*3 + 1, 30, SRCCOPY);
+ r = 166 + (39 * (config_pan + 128)) / 255;
+ xx = (config_pan + 128) * 3 / 256;
+ BitBlt(eqMainDC, r - 2, 4, 3, 7, bmDC, xx*3 + 11, 30, SRCCOPY);
+ unsetSrcBM();
+ }
+ else
+ {
+ BitBlt(eqMainDC, 0, 0, WINDOW_WIDTH, 14, eqMainDC, 0, l, SRCCOPY);
+ }
+ update_area_eq(0, 0, WINDOW_WIDTH, 14);
+}
+
+void draw_eq_slid(int which, int pos, int pressed) // left to right, 0-64
+{
+ int top = 38, h = 63;
+ int num_pos = 63 - 11;
+ int w = 14;
+ int xp;
+ int n = 0;
+ if (!which)
+ xp = 21;
+ else xp = 78 + (96 - 78) * (which - 1);
+ if (!eq_init) return ;
+ n = 27 - ((pos * 28) / 64);
+ if (n < 14)
+ BitBlt(eqMainDC, xp, top, w, h, eqMainDC, 13 + n*15, 164, SRCCOPY);
+ else
+ BitBlt(eqMainDC, xp, top, w, h, eqMainDC, 13 + (n - 14)*15, 229, SRCCOPY);
+ BitBlt(eqMainDC, xp + 1, top + h - 12 - ((63 - pos)*num_pos) / 64, 11, 11, eqMainDC, 0, pressed ? 176 : 164, SRCCOPY);
+ update_area_eq(xp, top, w, h);
+}
+
+void draw_eq_onauto(int on, int autoon, int onpressed, int autopressed)
+{
+ int top = 18, left = 14;
+ int w1 = 25, w2 = 33;
+ int h = 12;
+ BitBlt(eqMainDC, left, top, w1, h, eqMainDC, 10 + (onpressed ? 118 : 0) + (on ? 59 : 0), 119, SRCCOPY);
+ BitBlt(eqMainDC, left + w1, top, w2, h, eqMainDC, 35 + (autopressed ? 118 : 0) + (autoon ? 59 : 0), 119, SRCCOPY);
+ update_area_eq(left, top, w1 + w2, h);
+}
+
+void draw_eq_graphthingy()
+{
+ int top = 17, left = 86;
+ int src_top = 294;
+ int w = 113, h = 19;
+ float keys[12] = {0};
+ pl_Spline spline = {keys, 1, 12, 0.0f, 0.0f, 0.1f};
+ BitBlt(eqMainDC, left, top, w, h, eqMainDC, 0, src_top, SRCCOPY);
+ BitBlt(eqMainDC, left, top - 1 + h - (int)(config_preamp*19.0f / 64.0f), w, 1, eqMainDC, 0, 314, SRCCOPY);
+ {
+ int x;
+ int last_p = -1;
+ for (x = 0; x < 10; x ++)
+ keys[x + 1] = eq_tab[x] * 19.0f / 64.0f;
+ keys[0] = keys[1];
+ keys[11] = keys[10];
+
+ for (x = 0; x < 109; x ++)
+ {
+ float p;
+ int this_p;
+ int lin_offs = 115;
+ plSplineGetPoint(&spline, 1.0f + x / 12.0f, &p);
+ this_p = (int)p;
+ if (this_p < 0) this_p = 0;
+ if (this_p > 18) this_p = 18;
+ if (last_p == -1 || this_p == last_p)
+ BitBlt(eqMainDC, left + 2 + x, top + this_p, 1, 1, eqMainDC, lin_offs, src_top + this_p, SRCCOPY);
+ else
+ {
+ if (this_p < last_p)
+ BitBlt(eqMainDC, left + 2 + x, top + this_p, 1, last_p - this_p + 1, eqMainDC, lin_offs, src_top + this_p, SRCCOPY);
+ else if (this_p > last_p)
+ BitBlt(eqMainDC, left + 2 + x, top + last_p, 1, this_p - last_p + 1, eqMainDC, lin_offs, src_top + last_p, SRCCOPY);
+ }
+ last_p = this_p;
+ }
+ }
+ update_area_eq(left, top, w, h);
+}
+
+void draw_eq_tbutton(int b3, int wsb)
+{
+ setSrcBM(eqExBM);
+ if (config_eq_ws)
+ {
+ if (wsb)
+ BitBlt(eqMainDC, 254, 3, 9, 9, bmDC, 1, 47, SRCCOPY);
+ else
+ BitBlt(eqMainDC, 254, 3, 9, 9, bmDC, 254, 3, SRCCOPY);
+ BitBlt(eqMainDC, 264, 3, 9, 9, bmDC, 11, 38 + b3*9, SRCCOPY);
+ }
+ else
+ {
+ if (wsb && enable_eq_windowshade_button)
+ BitBlt(eqMainDC, 254, 3, 9, 9, bmDC, 1, 38, SRCCOPY);
+ else
+ BitBlt(eqMainDC, 254, 3, 9, 9, eqMainDC, 254, 137, SRCCOPY);
+ BitBlt(eqMainDC, 264, 3, 9, 9, eqMainDC, 0, 116 + b3*9, SRCCOPY);
+ }
+ unsetSrcBM();
+ update_area_eq(253, 3, 20, 9);
+}
+
+static void draw_paintDC_eq(HDC screenHdc, const RECT &r)
+{
+ int dsize = (config_dsize && config_eqdsize);
+
+ do_palmode(screenHdc);
+
+ if (!dsize)
+ {
+ BitBlt(screenHdc, r.left, r.top, r.right - r.left, r.bottom - r.top, eqMainDC, r.left, r.top, SRCCOPY);
+ if (eqMainBM2)
+ {
+ SelectObject(eqMainDC2, eqOldmainBM2);
+ DeleteObject(eqMainBM2);
+ eqMainBM2 = NULL;
+ }
+ }
+ else
+ {
+ if (!eqMainBM2)
+ {
+ eqMainBM2 = CreateCompatibleBitmap(mainDC, WINDOW_WIDTH * 2, WINDOW_HEIGHT * 2);
+ eqOldmainBM2 = (HBITMAP)SelectObject(eqMainDC2, eqMainBM2);
+ StretchBlt(eqMainDC2, 0, 0, WINDOW_WIDTH*2, WINDOW_HEIGHT*2, eqMainDC, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, SRCCOPY);
+ }
+ BitBlt(screenHdc, r.left, r.top, r.right - r.left, r.bottom - r.top, eqMainDC2, r.left, r.top, SRCCOPY);
+ }
+
+}
+
+void draw_printclient_eq(HDC hdc, LPARAM /*drawingOptions*/)
+{
+ RECT r;
+ GetClientRect(hEQWindow,&r);
+ draw_paintDC_eq(hdc, r);
+}
+
+void draw_paint_eq(HWND hwnd)
+{
+ if (hwnd || hEQWindow)
+ {
+ HDC screenHdc;
+ PAINTSTRUCT ps;
+ RECT r;
+
+ if (!eq_init) return ;
+
+ if (hwnd)
+ {
+ GetUpdateRect(hwnd, &ps.rcPaint, 0);
+ EnterCriticalSection(&g_mainwndcs);
+ screenHdc = BeginPaint(hwnd, &ps);
+ memcpy(&r, &ps.rcPaint, sizeof(r));
+ }
+ else
+ {
+ screenHdc = draw_GetWindowDC(hEQWindow);
+ GetClientRect(hEQWindow, &r);
+ }
+
+ draw_paintDC_eq(screenHdc, r);
+
+ if (hwnd)
+ {
+ EndPaint(hwnd, &ps);
+ LeaveCriticalSection(&g_mainwndcs);
+ }
+ else
+ draw_ReleaseDC(hEQWindow, screenHdc);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/draw_main.cpp b/Src/Winamp/draw_main.cpp
new file mode 100644
index 00000000..6e73fe93
--- /dev/null
+++ b/Src/Winamp/draw_main.cpp
@@ -0,0 +1,696 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "draw.h"
+#include "../nu/AutoWide.h"
+
+HBITMAP tbBM, cbuttonsBM, mainBM2,oldmainBM2, numbersBM, numbersBM_ex,
+playpauseBM, posbarBM, monostereoBM, volBM,panBM;
+
+void draw_tbuttons(int b1, int b2, int b3, int b4)
+{
+ setSrcBM(tbBM);
+ if (b1 != -1) BitBlt(mainDC,6,3,9,9,bmDC,0,b1*9,SRCCOPY);
+ if (b2 != -1) BitBlt(mainDC,244,3,9,9,bmDC,9,b2*9,SRCCOPY);
+ if (b3 != -1) BitBlt(mainDC,264,3,9,9,bmDC,18,b3*9,SRCCOPY);
+ if (b4 != -1) BitBlt(mainDC,254,3,9,9,bmDC,b4*9,config_windowshade?27:18,SRCCOPY);
+ unsetSrcBM();
+ update_area(6,3,9,9);
+ update_area(243,3,274-243,9);
+}
+
+void draw_eject(int pressed)
+{
+ RECT r;
+ if (!draw_initted) return;
+ r.left = 132+7-4+1;
+ r.top = 60+14+15;
+ r.right = r.left+22;
+ r.bottom = r.top+16;
+ setSrcBM(cbuttonsBM);
+ BitBlt(mainDC,r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,114,(pressed?16:0),SRCCOPY);
+ unsetSrcBM();
+ update_rect(r);
+}
+
+static void draw_paintDC(HDC hdc, const RECT &r)
+{
+ if (!draw_initted) return;
+
+ //int dsize=(config_dsize && config_eqdsize);
+ int dsize = config_dsize;
+
+ do_palmode(hdc);
+
+ if (!dsize)
+ {
+ BitBlt(hdc,r.left,r.top,r.right-r.left,r.bottom-r.top,mainDC,r.left,r.top,SRCCOPY);
+
+ if (mainBM2)
+ {
+ SelectObject(mainDC2,oldmainBM2);
+ DeleteObject(mainBM2);
+ mainBM2=NULL;
+ }
+ }
+ else
+ {
+ if (!mainBM2)
+ {
+ mainBM2 = CreateCompatibleBitmap(mainDC,WINDOW_WIDTH*2,WINDOW_HEIGHT*2);
+ oldmainBM2 = (HBITMAP)SelectObject(mainDC2,mainBM2);
+ StretchBlt(mainDC2,0,0,WINDOW_WIDTH*2,WINDOW_HEIGHT*2,mainDC,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,SRCCOPY);
+ }
+ BitBlt(hdc,r.left,r.top,r.right-r.left,r.bottom-r.top,mainDC2,r.left,r.top,SRCCOPY);
+ }
+}
+
+void draw_printclient(HDC hdc, LPARAM /*drawingOptions*/)
+{
+ RECT r;
+ GetClientRect(hMainWindow,&r);
+ draw_paintDC(hdc, r);
+}
+
+void draw_paint(HWND hwnd)
+{
+ HDC screenHdc;
+ PAINTSTRUCT ps;
+ RECT r;
+ if (!draw_initted) return;
+
+ if (hwnd)
+ {
+ GetUpdateRect(hwnd,&ps.rcPaint,0);
+ EnterCriticalSection(&g_mainwndcs);
+ screenHdc = BeginPaint(hwnd,&ps);
+ memcpy(&r,&ps.rcPaint,sizeof(r));
+ }
+ else
+ {
+ screenHdc = draw_GetWindowDC(hMainWindow);
+ GetClientRect(hMainWindow,&r);
+ }
+
+ draw_paintDC(screenHdc, r);
+
+ if (hwnd)
+ {
+ EndPaint(hwnd,&ps);
+ LeaveCriticalSection(&g_mainwndcs);
+ }
+ else
+ draw_ReleaseDC(hMainWindow,screenHdc);
+}
+
+void draw_tbar( int active, int windowshade, int egg )
+{
+ int t[ 4 ] = { 0, 15, 29, 42 };
+ int l = t[ ( ( active ? 0 : 1 ) + ( windowshade ? 2 : 0 ) ) ];
+
+ if ( egg && !windowshade )
+ l = active ? 57 : 72;
+
+ if ( !draw_initted )
+ return;
+
+ setSrcBM( tbBM );
+
+ BitBlt( mainDC, 0, 0, WINDOW_WIDTH, 14, bmDC, 27, l, SRCCOPY );
+
+ unsetSrcBM();
+
+ if ( windowshade && config_windowshade )
+ {
+ int pos = 0;
+ draw_songname( L"", &pos, 0 );
+ }
+
+ update_area( 0, 0, WINDOW_WIDTH, 14 );
+}
+
+static int g_need_erase=0;
+
+static int _draw_songname(const wchar_t *str, int startpos, int offs_in_first)
+{
+ int xp;
+ int o = offs_in_first;
+ str += startpos;
+ xp = 111;
+ if (g_need_erase)
+ {
+ IntersectClipRect(mainDC,111,12+13,264,12+15+8);
+ HGDIOBJ oldBrush=SelectObject(mainDC,mfont_bgbrush);
+ Rectangle(mainDC,108,12+12,267,12+15+10);
+ SelectObject(mainDC,oldBrush);
+ ExtSelectClipRgn(mainDC,NULL,RGN_COPY);
+ g_need_erase=0;
+ }
+
+ setSrcBM(fontBM);
+ while (xp < 265 && *str)
+ {
+ int c2=0,c=0;
+ getXYfromChar(*str++,&c,&c2);
+ if (xp >= 265-5)
+ {
+ BitBlt(mainDC,xp,12+15,265-xp,6,bmDC,c,c2,SRCCOPY);
+ xp = 265;
+ }
+ else
+ {
+ BitBlt(mainDC,xp,12+15,5-o,6,bmDC,c+o,c2,SRCCOPY);
+ xp += 5-o;
+ o = 0;
+ }
+ }
+ while (xp < 265) BitBlt(mainDC,xp++,12+15,1,6,bmDC,4,0,SRCCOPY);
+ update_area(111,10+15,265-111,10);
+ unsetSrcBM();
+ return 0;
+}
+
+static int _draw_songname_winfont(const wchar_t *str, int start_pix)
+{
+ RECT r={111-start_pix,12+11,265,12+16+mfont_height};
+ HGDIOBJ oldBrush;
+ g_need_erase=1;
+ IntersectClipRect(mainDC,111,12+12,265,12+16+8);
+ SetTextColor(mainDC,mfont_fgcolor);
+ SetBkColor(mainDC,mfont_bgcolor);
+ oldBrush=SelectObject(mainDC,mfont_bgbrush);
+ Rectangle(mainDC,108,12+11,268,12+16+10);
+ SelectObject(mainDC,oldBrush);
+ DrawTextW(mainDC,str,-1,&r, DT_LEFT | DT_SINGLELINE |DT_NOPREFIX);
+ ExtSelectClipRgn(mainDC,NULL,RGN_COPY);
+ update_area(111,12+11,265-111,4+9);
+ return 0;
+}
+
+void draw_time(int minutes, int seconds, int clear) {
+ int ex=0;
+ int tlm;
+ if (!draw_initted) return;
+
+ tlm=config_timeleftmode && in_mod && in_mod->is_seekable;
+ if (tlm)
+ {
+ int s;
+ int tmp=in_getlength();
+ s = minutes*60+seconds;
+ s = tmp - s;
+ if (tmp>0)
+ {
+ minutes = s/60;
+ seconds = -(s%60);
+ }
+ else
+ minutes=seconds=tlm=0;
+ }
+ if (config_windowshade)
+ setSrcBM(fontBM);
+ else
+ {
+ if (numbersBM) setSrcBM(numbersBM);
+ else
+ {
+ setSrcBM(numbersBM_ex);
+ ex=1;
+ }
+ }
+ if (clear)
+ {
+ if (config_windowshade)
+ {
+ BitBlt(mainDC,126,4,3,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,130,4,3,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,130+4,4,5,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,130+4+5,4,5,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,130+4+5+4+4,4,5,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,130+4+5+4+5+4,4,5,6,bmDC,142,0,SRCCOPY);
+ }
+ else
+ {
+ BitBlt(mainDC,23+7+6,11+15,9,13,bmDC,90,0,SRCCOPY);
+ if (ex)
+ BitBlt(mainDC,36+4-2,11+15,9,13,bmDC,90,0,SRCCOPY);
+ else
+ BitBlt(mainDC,36+4,32,5,1,bmDC,9,6,SRCCOPY);
+ BitBlt(mainDC,35+7+6,11+15,9,13,bmDC,90,0,SRCCOPY);
+ BitBlt(mainDC,47+7+6,11+15,9,13,bmDC,90,0,SRCCOPY);
+ BitBlt(mainDC,65+7+6,11+15,9,13,bmDC,90,0,SRCCOPY);
+ BitBlt(mainDC,77+7+6,11+15,9,13,bmDC,90,0,SRCCOPY);
+ }
+ }
+ else
+ {
+ if (config_windowshade)
+ {
+ if (tlm)
+ {
+ if (minutes < 0) minutes=-minutes;
+ if (seconds < 0) seconds=-seconds;
+ if (minutes/100)
+ BitBlt(mainDC,130-4,4,3,6,bmDC,75,6,SRCCOPY);
+ else
+ BitBlt(mainDC,130,4,3,6,bmDC,75,6,SRCCOPY);
+ }
+ else
+ {
+ if (!(minutes/100))
+ {
+ BitBlt(mainDC,130,4,3,6,bmDC,142,0,SRCCOPY);
+ }
+ BitBlt(mainDC,130-4,4,3,6,bmDC,142,0,SRCCOPY);
+ }
+ if (minutes / 100)
+ BitBlt(mainDC,130-1,4,5,6,bmDC,5*((minutes/100)%10),6,SRCCOPY);
+ BitBlt(mainDC,130+4,4,5,6,bmDC,5*((minutes/10)%10),6,SRCCOPY);
+ BitBlt(mainDC,130+4+5,4,5,6,bmDC,5*((minutes)%10),6,SRCCOPY);
+ BitBlt(mainDC,130+4+5+4+4,4,5,6,bmDC,5*((seconds/10)%10),6,SRCCOPY);
+ BitBlt(mainDC,130+4+5+4+5+4,4,5,6,bmDC,5*((seconds)%10),6,SRCCOPY);
+ }
+ else
+ {
+ BitBlt(mainDC,23+7+6,11+15,9,13,bmDC,90,0,SRCCOPY);
+ if (tlm)
+ {
+ int t= 36+4-2;
+ if (minutes < 0) minutes=-minutes;
+ if (seconds < 0) seconds=-seconds;
+ if (minutes/100)
+ {
+ BitBlt(mainDC,23+7+6,11+15,9,13,bmDC,((minutes/100)%10)*9,0,SRCCOPY);
+ // t-=4;
+ }
+ if (ex)
+ BitBlt(mainDC,t-2,11+15,9,13,bmDC,99,0,SRCCOPY);
+ else
+ BitBlt(mainDC,t,32,5,1,bmDC,20,6,SRCCOPY);
+ }
+ else
+ {
+ if (minutes/100)
+ BitBlt(mainDC,23+7+6,11+15,9,13,bmDC,((minutes/100)%10)*9,0,SRCCOPY);
+ }
+
+ BitBlt(mainDC,35+7+6,11+15,9,13,bmDC,((minutes/10)%10)*9,0,SRCCOPY);
+ BitBlt(mainDC,47+7+6,11+15,9,13,bmDC,((minutes)%10)*9,0,SRCCOPY);
+ BitBlt(mainDC,65+7+6,11+15,9,13,bmDC,((seconds/10)%10)*9,0,SRCCOPY);
+ BitBlt(mainDC,77+7+6,11+15,9,13,bmDC,((seconds)%10)*9,0,SRCCOPY);
+ }
+ }
+ unsetSrcBM();
+
+ if (config_pe_open && config_pe_height != 14)
+ {
+ draw_pe_timedisp(NULL, minutes,seconds,tlm,clear);
+ }
+ if (config_windowshade) update_area(125,4,32,6);
+ else update_area(36,11+15,96-36+4,13);
+}
+
+void draw_playicon(int whichicon) // 0 = none, 1 = play, 2 = stop, 4 = pause, 8 = lost sync play
+{
+ int offset;
+ RECT r;
+ if (!draw_initted) return;
+ r.left = 19+7;
+ r.top = 13+15;
+ r.right = r.left+9;
+ r.bottom = r.top+9;
+ switch (whichicon)
+ {
+ case 0: offset = 27; break;
+ case 1: offset = 0; break;
+ case 2: offset = 18; break;
+ case 4: offset = 9; break;
+ case 8: offset = 0; break;
+ default: return;
+ }
+ setSrcBM(playpauseBM);
+ BitBlt(mainDC,r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,offset,0,SRCCOPY);
+ r.left -= 2;
+ r.right = r.left+3;
+ if (whichicon == 1 || whichicon == 8)
+ {
+ offset = (whichicon==1?36:39);
+ BitBlt(mainDC,r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,offset,0,SRCCOPY);
+ }
+ else
+ {
+ r.right = r.left+2;
+ offset = 27;
+ BitBlt(mainDC,r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,offset,0,SRCCOPY);
+ }
+ r.right = r.left + 11;
+ unsetSrcBM();
+ update_rect(r);
+}
+
+void draw_buttonbar(int buttonpressed) // starts at 0 with leftmost, -1 = no button
+{
+ if (!draw_initted) return;
+ setSrcBM(cbuttonsBM);
+ if (buttonpressed == -1)
+ {
+ BitBlt(mainDC,8+8,58+14+15+1,114,18,bmDC,0,0,SRCCOPY);
+ }
+ else
+ {
+ int d1[5] = { 0, 23, 46, 69, 92 }; // width of first section
+ int d2[5] = { 23, 46, 69, 92, 114 }; // start of next button
+ if (buttonpressed)
+ BitBlt(mainDC,8+8,58+14+15+1,d1[buttonpressed],18,bmDC,0,0,SRCCOPY);
+ BitBlt(mainDC,8+8+d1[buttonpressed],58+14+15+1,d2[buttonpressed]-d1[buttonpressed],
+ 18,bmDC,d1[buttonpressed],18,SRCCOPY);
+ if (buttonpressed != 4)
+ BitBlt(mainDC,8+8+d2[buttonpressed],58+14+15+1,114-d2[buttonpressed],18,
+ bmDC,d2[buttonpressed],0,SRCCOPY);
+ }
+ unsetSrcBM();
+ update_area(8+7,58+14+15,116,20);
+}
+
+void draw_bitmixrate(int bitrate, int mixrate)
+{
+ static int l1=-1, l2=-1;
+ if (bitrate < 0) bitrate= l1;
+ if (mixrate < 0) mixrate = l2;
+ if (bitrate < 0) return;
+ if (!draw_initted) return;
+ setSrcBM(fontBM);
+ if (bitrate/10000)
+ {
+ if (bitrate/100000) BitBlt(mainDC,111,28+15,5,6,bmDC,(((bitrate/100000)%10))*5,6,SRCCOPY);
+ else BitBlt(mainDC,111,28+15,5,6,bmDC,100,12,SRCCOPY); // blank
+ BitBlt(mainDC,111+5,28+15,5,6,bmDC,(((bitrate/10000)%10))*5,6,SRCCOPY);
+ {
+ int x,y;
+ getXYfromChar(L'C',&x,&y);
+ BitBlt(mainDC,111+5*2,28+15,5,6,bmDC,x,y,SRCCOPY);
+ }
+ }
+ else if (bitrate/1000)
+ {
+ BitBlt(mainDC,111,28+15,5,6,bmDC,(((bitrate/1000)%10))*5,6,SRCCOPY);
+ BitBlt(mainDC,111+5,28+15,5,6,bmDC,(((bitrate/100)%10))*5,6,SRCCOPY);
+ {
+ int x,y;
+ getXYfromChar(L'H',&x,&y);
+ BitBlt(mainDC,111+5*2,28+15,5,6,bmDC,x,y,SRCCOPY);
+ }
+ }
+ else
+ {
+ if (bitrate/100)
+ BitBlt(mainDC,111,28+15,5,6,bmDC,(((bitrate/100)%10))*5,6,SRCCOPY);
+ else
+ BitBlt(mainDC,111,28+15,5,6,bmDC,100,12,SRCCOPY); // blank
+ if (bitrate/10)
+ BitBlt(mainDC,111+5,28+15,5,6,bmDC,(((bitrate/10)%10))*5,6,SRCCOPY);
+ else
+ BitBlt(mainDC,111+5,28+15,5,6,bmDC,100,12,SRCCOPY);
+ BitBlt(mainDC,111+5*2,28+15,5,6,bmDC,((bitrate%10))*5,6,SRCCOPY);
+ }
+
+ if (mixrate/10) BitBlt(mainDC,156,28+15,5,6,bmDC,(((mixrate/10)%10))*5,6,SRCCOPY);
+ else BitBlt(mainDC,156,28+15,5,6,bmDC,100,12,SRCCOPY);
+ BitBlt(mainDC,156+5,28+15,5,6,bmDC,((mixrate%10))*5,6,SRCCOPY);
+ unsetSrcBM();
+ update_area(111,28+15,176-111,6);
+ l1 = bitrate;
+ l2 = mixrate;
+}
+
+void draw_positionbar(int position, int pressed) // position is 0-256
+{
+ RECT r;
+ int op=position;
+ if (!draw_initted) return;
+ position = (position * (248-29)) / 256;
+ if (position < 0) position = 0;
+ if (position > (248-29)) position = 248-29;
+ r.left = 9+7;
+ r.top = 57+15;
+ r.right = r.left+248;
+ r.bottom = r.top+10;
+ setSrcBM(posbarBM);
+ if (position)
+ BitBlt(mainDC,r.left,r.top,position,r.bottom-r.top,bmDC,0,0,SRCCOPY);
+ BitBlt(mainDC,r.left+position,r.top,29,10,bmDC,pressed?278:248,0,SRCCOPY);
+ if (position != 248-29)
+ BitBlt(mainDC,r.left+position+29,r.top,248-29-position,r.bottom-r.top,
+ bmDC,position+29,0,SRCCOPY);
+ unsetSrcBM();
+ update_rect(r);
+ if (config_windowshade)
+ {
+ int a;
+ r.left = 226;
+ r.top=4;
+ r.right=243;
+ r.bottom=11;
+ op = (op * 12) / 256;
+ if (++op < 1) op = 1;
+ if (op > 13) op = 13;
+ if (op < 6) a=0;
+ else if (op < 9) a=1;
+ else a=2;
+ setSrcBM(tbBM);
+ BitBlt(mainDC,r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,0,36,SRCCOPY);
+ BitBlt(mainDC,r.left+op,r.top,3,r.bottom-r.top,bmDC,17+a*3,36,SRCCOPY);
+ unsetSrcBM();
+ update_rect(r);
+ }
+}
+
+void draw_monostereo(int value) // 0 is clear, 1 is mono, 2 is stereo, 3 is downmixed stereo
+{
+ static int l = -1;
+ if (!draw_initted) return;
+ if (value < 0) value = l;
+ if (value < 0) return;
+ setSrcBM(monostereoBM);
+ BitBlt(mainDC,7+205,41,28,12,bmDC,29,value==1?0:12,SRCCOPY);
+ BitBlt(mainDC,7+232,41,29,12,bmDC,0,value==2?0:12,SRCCOPY);
+ unsetSrcBM();
+ update_area(199,41,7+232+29-199,12);
+ l = value;
+}
+
+void draw_songname(const wchar_t *name, int *out_position, int songlen) // position is the number of chars over it is
+{
+ int position = *out_position;
+ wchar_t buf[2048];
+ const wchar_t *draw_buf = buf;
+ int len_of_str, len_of_spacer;
+ int mode=!config_bifont;
+
+ HGDIOBJ hOldFont;
+
+ if (!draw_initted || !name)
+ return;
+
+ if (*name)
+ {
+ static int hold;
+ if (songlen >= 0)
+ {
+ if (hold > 0)
+ {
+ hold--;
+ return;
+ }
+
+ if(config_dotitlenum)
+ StringCchPrintfW(buf,2048, L"%d. %s (%d:%02d)",PlayList_getPosition()+1, name,songlen/60,songlen%60);
+ else
+ StringCchPrintfW(buf,2048, L"%s (%d:%02d)",name,songlen/60,songlen%60);
+ }
+ else if (name == FileTitle) // benski> ok, ok, ok, this is a big hack
+ {
+ if (hold > 0)
+ {
+ hold--;
+ return;
+ }
+ StringCchPrintfW(buf,2048, L"%d. %s", PlayList_getPosition()+1, name);
+ }
+ else
+ {
+ KillTimer(hMainWindow, UPDATE_DISPLAY_TIMER + 2);
+ SetTimer(hMainWindow, UPDATE_DISPLAY_TIMER + 2, 1000, NULL);
+ hold = (config_autoscrollname&1 ? ((songlen == -2) ? 5 : 1) : 0);
+ StringCchCopyW(buf, 2048, name);
+ }
+ }
+ else
+ StringCchPrintfW(buf,2048, L"%S %S", app_name, app_version_string);
+
+ if (!mode)
+ {
+ len_of_str = lstrlenW(buf)*5;
+ len_of_spacer=lstrlenW(L" *** ")*5;
+ }
+ else
+ {
+ RECT r;
+ hOldFont=SelectObject(mainDC,mfont);
+ DrawTextW(mainDC,buf,-1,&r, DT_CALCRECT | DT_SINGLELINE | DT_NOPREFIX);
+ len_of_str=r.right-r.left;
+ DrawTextW(mainDC,L" *** ",-1,&r, DT_CALCRECT | DT_SINGLELINE |DT_NOPREFIX);
+ len_of_spacer=r.right-r.left;
+ }
+
+ const int textAreaWidth = 258-112;
+ wchar_t obuf[4096];
+ if (len_of_str > textAreaWidth)
+ {
+ StringCchPrintfW(obuf, 4096, L"%s *** %s", buf, buf);
+ while (position < 0) position += len_of_str+len_of_spacer;
+ if (position >= len_of_str+len_of_spacer) position -= len_of_str+len_of_spacer;
+ draw_buf = obuf;
+ }
+ else
+ position=0;
+
+ if (!mode)
+ _draw_songname(draw_buf,position/5,position%5);
+ else
+ {
+ _draw_songname_winfont(draw_buf, position);
+ SelectObject(mainDC,hOldFont);
+ }
+ *out_position = position;
+}
+
+#define PANBAR_WIDTH 38
+#define PANBAR_SLIDER_WIDTH 14
+#define PANBAR_LENGTH (PANBAR_WIDTH-PANBAR_SLIDER_WIDTH)
+#define ABS(x) (( x ) > 0 ? ( x ) : - ( x ))
+void draw_panbar(int volume, int pressed) // volume is 0-256
+{
+ int ypos = ((ABS(volume) * 27) / 127)*15;
+ RECT r;
+ if (!draw_initted) return;
+ if (ypos < 0) ypos=0; else if (ypos > 27*15) ypos=27*15;
+ r.left = 177;
+ r.top = 42+15;
+ r.right = r.left + PANBAR_WIDTH;
+ r.bottom = r.top + 13;
+ setSrcBM(panBM);
+ BitBlt(mainDC, r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,9,ypos,SRCCOPY);
+ {
+ int xpos = ((volume*12)/127)+12;
+ if (xpos > PANBAR_LENGTH)
+ xpos = PANBAR_LENGTH;
+ else if (xpos < 0)
+ xpos = 0;
+ BitBlt(mainDC,r.left+xpos,r.top+1,14,11,bmDC,pressed?0:15,422,SRCCOPY);
+ }
+ unsetSrcBM();
+ update_rect(r);
+}
+
+void draw_shuffle(int on, int pressed)
+{
+ RECT r;
+ if (!draw_initted) return;
+ r.left = 164;
+ r.top = 89;
+ r.right = r.left+79-28-4;
+ r.bottom = r.top+15;
+ setSrcBM(shufflerepeatBM);
+ BitBlt(mainDC,r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,28,(on?30:0) + (pressed?15:0),SRCCOPY);
+ unsetSrcBM();
+ update_rect(r);
+}
+
+void draw_repeat(int on, int pressed)
+{
+ RECT r;
+ if (!draw_initted) return;
+ r.left = 182+7-4-4+29;
+ r.top = 60+14+15;
+ r.right = r.left+28;
+ r.bottom = r.top+15;
+ setSrcBM(shufflerepeatBM);
+ BitBlt(mainDC,r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,0,(on?30:0) + (pressed?15:0),SRCCOPY);
+ unsetSrcBM();
+ update_rect(r);
+}
+
+void update_panning_text(int songlen)
+{
+ wchar_t buf[128] = {0};
+ int v=config_pan;
+ v *= 100;
+ v/=127;
+ if (v)
+ {
+ wchar_t lorrStr[32] = {0}, balanceStr[64] = {0};
+ StringCchPrintfW(buf, 128, L"%s: %d%% %s",getStringW(IDS_BALANCE,balanceStr,64),v<0?-v:v,v<0?getStringW(IDS_BALANCE_LEFT,lorrStr,32):getStringW(IDS_BALANCE_RIGHT,lorrStr,32));
+ }
+ else
+ getStringW(IDS_BALANCE_CENTRE,buf,128);
+ v=0;
+ draw_songname(buf,&v,songlen);
+}
+
+void update_volume_text(int songlen)
+{
+ wchar_t buf[128] = {0}, volStr[64] = {0};
+ int v = config_volume;
+ v *= 100;
+ v/=255;
+ StringCchPrintfW(buf, 128,L"%s: %d%%",getStringW(IDS_VOLUME,volStr,64),v);
+ draw_songname(buf,&v,songlen);
+}
+
+#define VOLBAR_WIDTH 68
+#define VOLBAR_SLIDER_WIDTH 14
+#define VOLBAR_LENGTH (VOLBAR_WIDTH-VOLBAR_SLIDER_WIDTH)
+void draw_volumebar(int volume, int pressed) // volume is 0-256
+{
+ int ypos = ((volume * 27) / 255)*15;
+ RECT r;
+ if (!draw_initted) return;
+ if (ypos < 0) ypos=0; else if (ypos > 27*15) ypos=27*15;
+ r.left = 107;
+ r.top = 42+15;
+ r.right = r.left + VOLBAR_WIDTH;
+ r.bottom = r.top + 13;
+ setSrcBM(volBM);
+ BitBlt(mainDC, r.left,r.top,r.right-r.left,r.bottom-r.top,bmDC,0,ypos,SRCCOPY);
+ {
+ int xpos = (volume*51)/255;
+ if (xpos > VOLBAR_LENGTH) xpos = VOLBAR_LENGTH; else if (xpos < 0) xpos = 0;
+ BitBlt(mainDC,r.left+xpos,r.top+1,14,11,bmDC,pressed?0:15,422,SRCCOPY);
+ }
+ unsetSrcBM();
+ update_rect(r);
+}
+
+void draw_eqplbut(int eqon, int eqpressed, int plon, int plpressed)
+{
+ RECT urect = { 219, 58, 265, 70 };
+ int x, y;
+ if (!draw_initted) return ;
+ x = eqpressed ? 46 : 0;
+ y = eqon ? 12 : 0;
+ setSrcBM(shufflerepeatBM);
+ BitBlt(mainDC, urect.left, urect.top, (urect.right - urect.left) / 2, urect.bottom - urect.top,
+ bmDC, x, y + 61, SRCCOPY);
+ x = plpressed ? 46 : 0;
+ y = plon ? 12 : 0;
+ BitBlt(mainDC, urect.left + (urect.right - urect.left) / 2, urect.top, (urect.right - urect.left) / 2, urect.bottom - urect.top,
+ bmDC, x + 23, y + 61, SRCCOPY);
+ unsetSrcBM();
+ update_rect(urect);
+} \ No newline at end of file
diff --git a/Src/Winamp/draw_mb.cpp b/Src/Winamp/draw_mb.cpp
new file mode 100644
index 00000000..2fe366f7
--- /dev/null
+++ b/Src/Winamp/draw_mb.cpp
@@ -0,0 +1,10 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "draw.h"
+
diff --git a/Src/Winamp/draw_pe.cpp b/Src/Winamp/draw_pe.cpp
new file mode 100644
index 00000000..c4570c4b
--- /dev/null
+++ b/Src/Winamp/draw_pe.cpp
@@ -0,0 +1,822 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "draw.h"
+#include "api.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "resource.h"
+#include <bfc/platform/minmax.h>
+#include "WADrawDC.h"
+
+HBITMAP plMainBM=0;
+extern "C" int pe_init = 0;
+wchar_t playlistStr[19] = {0};
+int (WINAPI *jtf_drawtext)(HDC, LPCWSTR, int, LPRECT, UINT) = 0;
+
+void draw_pe_init()
+{
+ EnterCriticalSection(&g_srcdccs);
+ if (pe_init)
+ draw_pe_kill();
+ pe_init=1;
+ if (!plMainBM)
+ plMainBM = draw_LBitmap(MAKEINTRESOURCE(IDB_PLEDIT), L"pledit.bmp");
+ LeaveCriticalSection(&g_srcdccs);
+}
+
+void draw_pe_kill()
+{
+ if (!pe_init)
+ return;
+ EnterCriticalSection(&g_srcdccs);
+ DeleteObject(plMainBM);
+ plMainBM=0;
+ pe_init=0;
+ LeaveCriticalSection(&g_srcdccs);
+}
+
+void draw_set_plbm(HBITMAP bm)
+{
+ EnterCriticalSection(&g_srcdccs);
+ if (plMainBM)
+ DeleteObject(plMainBM);
+ plMainBM=bm;
+ LeaveCriticalSection(&g_srcdccs);
+}
+
+void draw_pe_iobut(int which) // -1 = none, 0 = load, 1=save, 2=clear
+{
+ if (!pe_init || disable_skin_borders) // if we're not init'd (shouldn't happen) or gen_ff is active
+ return;
+
+ int offs=config_pe_width-44;
+
+ WADrawDC hdcout(hPLWindow);
+ do_palmode(hdcout);
+
+ setSrcBM(plMainBM);
+
+ BitBlt(hdcout, offs-3, config_pe_height-30-18*2, 3, 18*3, bmDC, 250, 111, SRCCOPY);
+ BitBlt(hdcout, offs, config_pe_height-30-18*2, 22, 18, bmDC, (which==2)?227:204, 111, SRCCOPY);
+ BitBlt(hdcout, offs, config_pe_height-30-18, 22, 18, bmDC, (which==1)?227:204, 130, SRCCOPY);
+ BitBlt(hdcout, offs, config_pe_height-30, 22, 18, bmDC, (which==0)?227:204, 149, SRCCOPY);
+
+ unsetSrcBM();
+}
+
+static void draw_pe_infostr(HDC hdcout, wchar_t *str)
+{
+ StringCchCopyW(playlistStr, 18, str); // use 18 instead of 19 to keep the last byte null terminated
+ AutoChar narrowStr(str);
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)(char *)narrowStr, IPC_CB_PEINFOTEXT);
+ playlistTextFeed->UpdateText(playlistStr, 19);
+
+ if (!pe_init)
+ return;
+ wchar_t data[19] = {0};
+ int x,xp=config_pe_width-143,yp=config_pe_height-28;
+
+ if (disable_skin_borders) return;
+
+ if (lstrlenW(str) < 18)
+ {
+ StringCchCopyW(data,19, str);
+ for (x = lstrlenW(str); x < 18; x ++) data[x]=L' ';
+ }
+ else memcpy(data,str,18*sizeof(wchar_t));
+ do_palmode(hdcout);
+ setSrcBM(fontBM);
+ for (x = 0; x < 18; x ++)
+ {
+ int c=0,c2=0;
+ getXYfromChar(data[x],&c,&c2);
+ BitBlt(hdcout,xp,yp,5,6,bmDC,c,c2,SRCCOPY);
+ xp+=5;
+ }
+ unsetSrcBM();
+}
+
+/* if we ever want to use a font rather than the skin bitmap, we can uncomment this
+void draw_pe_infostr_font(char *str)
+{
+ if (!pe_init)
+ return;
+ int xp=config_pe_width-145,yp=config_pe_height-30;
+ HDC hdcout;
+
+ SendMessageW(hMainWindow, WM_WA_IPC, reinterpret_cast<WPARAM>(str), IPC_CB_PEINFOTEXT);
+
+ if (disable_skin_borders) return;
+
+ hdcout=draw_GetWindowDC(hPLWindow);
+ do_palmode(hdcout);
+ HFONT oldfont = (HFONT) SelectObject(hdcout,mfont);
+ SetTextColor(hdcout,Skin_PLColors[0]);
+ SetBkColor(hdcout,Skin_PLColors[2]);
+
+ RECT r={xp, yp, xp+92, yp+10};
+ DrawText(hdcout, str, min(18, lstrlen(str)), &r, DT_CENTER| DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
+
+ SelectObject(hdcout,oldfont);
+ draw_ReleaseDC(hPLWindow,hdcout);
+}
+*/
+
+void draw_pe_miscbut(int which) // -1 = none, 0 = inf, 1 = sort, 2=misc
+{
+ if (!pe_init || disable_skin_borders) // if we're not init'd (shouldn't happen) or gen_ff is active
+ return;
+
+ WADrawDC hdcout(hPLWindow);
+ do_palmode(hdcout);
+ setSrcBM(plMainBM);
+
+ BitBlt(hdcout, 98, config_pe_height-30-18*2, 3, 18*3, bmDC, 200, 111, SRCCOPY);
+ BitBlt(hdcout, 101, config_pe_height-30-18*2, 22, 18, bmDC, (which==2)?177:154, 111, SRCCOPY);
+ BitBlt(hdcout, 101, config_pe_height-30-18, 22, 18, bmDC, (which==1)?177:154, 130, SRCCOPY);
+ BitBlt(hdcout, 101, config_pe_height-30, 22, 18, bmDC, (which==0)?177:154, 149, SRCCOPY);
+
+ unsetSrcBM();
+}
+
+void draw_pe_selbut(int which) // -1 = none, 0 = all, 1 = none, 2=inv
+{
+ if (!pe_init)
+ return;
+
+ if (disable_skin_borders) return;
+
+ WADrawDC hdcout(hPLWindow);
+ do_palmode(hdcout);
+ setSrcBM(plMainBM);
+
+ BitBlt(hdcout,69,config_pe_height-30-18*2,3,18*3,bmDC,150,111,SRCCOPY);
+ BitBlt(hdcout,72,config_pe_height-30-18*2,22,18,bmDC,(which==2)?127:104,111,SRCCOPY);
+ BitBlt(hdcout,72,config_pe_height-30-18,22,18,bmDC,(which==1)?127:104,130,SRCCOPY);
+ BitBlt(hdcout,72,config_pe_height-30,22,18,bmDC,(which==0)?127:104,149,SRCCOPY);
+
+ unsetSrcBM();
+}
+
+void draw_pe_rembut(int which) // -1 = none, 0 = sel, 1 = crop, 2 = all
+{
+ if (!pe_init)
+ return;
+
+ if (disable_skin_borders) return;
+
+
+ WADrawDC hdcout(hPLWindow);
+ do_palmode(hdcout);
+ setSrcBM(plMainBM);
+
+ BitBlt(hdcout,40,config_pe_height-30-18*3,3,18*4,bmDC,100,111,SRCCOPY);
+ BitBlt(hdcout,43,config_pe_height-30-18*3,22,18,bmDC,(which==3)?77:54,168,SRCCOPY);
+ BitBlt(hdcout,43,config_pe_height-30-18*2,22,18,bmDC,(which==2)?77:54,111,SRCCOPY);
+ BitBlt(hdcout,43,config_pe_height-30-18,22,18,bmDC,(which==1)?77:54,130,SRCCOPY);
+ BitBlt(hdcout,43,config_pe_height-30,22,18,bmDC,(which==0)?77:54,149,SRCCOPY);
+
+ unsetSrcBM();
+}
+
+void draw_pe_addbut(int which) // -1 = none, 0 = file, 1 = dir, 2 = loc
+{
+ if (!pe_init)
+ return;
+
+ if (disable_skin_borders) return;
+
+ WADrawDC hdcout(hPLWindow);
+ do_palmode(hdcout);
+ setSrcBM(plMainBM);
+
+ BitBlt(hdcout,11,config_pe_height-30-18*2,3,18*3,bmDC,48,111,SRCCOPY);
+ BitBlt(hdcout,14,config_pe_height-30-18*2,22,18,bmDC,(which==2)?23:0,111,SRCCOPY);
+ BitBlt(hdcout,14,config_pe_height-30-18,22,18,bmDC,(which==1)?23:0,130,SRCCOPY);
+ BitBlt(hdcout,14,config_pe_height-30,22,18,bmDC,(which==0)?23:0,149,SRCCOPY);
+
+ unsetSrcBM();
+}
+
+void draw_pe_vslide(HWND hwnd, HDC hdc, int pushed, int pos) // pos 0..playlist_getlength()-num_songs
+{
+ if (!pe_init)
+ return;
+ int track_h = config_pe_height-20-38;
+ int slid_h = 18;
+ //int w = 25;
+ int yp,y,oy;
+
+ WADrawDC hdcout(hdc, hwnd);
+ do_palmode(hdcout);
+
+ setSrcBM(plMainBM);
+ {
+ int num_songs=(config_pe_height-38-20-2)/pe_fontheight;
+ int t=PlayList_getlength()-num_songs;
+ if (t < 1) yp = 0;
+ else {
+ if (pos > t) pos=t;
+ yp = ((track_h-slid_h)*pos)/t;
+ if (yp < 0) yp = 0;
+ }
+ }
+ for (y = 0; y < yp-28; y += 29)
+ BitBlt(hdcout,config_pe_width-15,20+y,8,29,bmDC,36,42,SRCCOPY);
+ oy=y+29;
+ if (slid_h + yp > oy) oy+=29;
+ if (y < yp) BitBlt(hdcout,config_pe_width-15,20+y,8,yp-y,bmDC,36,42,SRCCOPY);
+ BitBlt(hdcout,config_pe_width-15,20+yp,8,slid_h,bmDC,pushed?61:52,53,SRCCOPY);
+ y=yp+slid_h;
+ if (y < oy && y < track_h) BitBlt(hdcout,config_pe_width-15,20+y,8,((y<track_h-29)?oy-y:track_h-y),bmDC,36,42+29-(oy-y),SRCCOPY);
+ y = oy;
+ for (y = oy; y < track_h; y += 29)
+ {
+ BitBlt(hdcout,config_pe_width-15,20+y,8,(y<track_h-29)?29:track_h-y,bmDC,36,42,SRCCOPY);
+ }
+
+ unsetSrcBM();
+}
+
+static void draw_pe_song(HDC hdcout, int pos, wchar_t *name, int time, int sel)
+{
+ if (!pe_init)
+ return;
+
+ int ypos, left, right, num_songs, fontHeight;
+ HFONT useFont;
+ COLORREF foreground, background;
+ HBRUSH useBrush;
+ if (pos < 0)
+ {
+ // if (config_pe_height != 14) return;
+ right = config_pe_width-29;
+ ypos = config_bifont?4:2;
+ left = 4;
+ num_songs = 1;
+ useFont=mfont;//shadefont;
+ fontHeight=10;
+ sel=0;
+ foreground=mfont_fgcolor;
+ background=mfont_bgcolor;
+ useBrush=mfont_bgbrush;
+ }
+ else
+ {
+ fontHeight=pe_fontheight;
+ right=config_pe_width-20;
+ ypos=22+pos*fontHeight,
+ left=12;
+ num_songs=(config_pe_height-38-20-2)/pe_fontheight;
+ useFont=font;
+ if (sel&2) foreground=Skin_PLColors[1];
+ else foreground= Skin_PLColors[0];
+ if (!(sel&1)) background= Skin_PLColors[2];
+ else background=Skin_PLColors[3];
+ useBrush=(sel&1)?selbrush:normbrush;
+ }
+ if (pos >= num_songs) return;
+
+ int xpos=left;
+ int endp=right;
+ int num_chars=(endp-xpos)/5;
+ if (pos>=0 || !config_bifont)
+ {
+ RECT r={xpos,ypos,endp, ypos+fontHeight};
+
+ SetTextColor(hdcout,foreground);
+ SetBkColor(hdcout,background);
+
+ do_palmode(hdcout);
+ HFONT oldfont = (HFONT) SelectObject(hdcout,useFont);
+
+ int rightToLeft = (config_pe_direction == PE_DIRECTION_RTL) || (config_pe_direction == PE_DIRECTION_AUTO && (GetFontLanguageInfo(hdcout) & GCP_REORDER));
+ if (time >= 0)
+ {
+ char str[123];
+ StringCchPrintfA(str,123," %d:%02d ",time/60,(time)%60); // format the time string
+
+ RECT r2=r;
+ if (pos == -1)
+ {
+ r2.top--;
+ r2.bottom--;
+ }
+
+ SIZE timeSize;
+#ifdef BENSKI_NEW_MODE_THAT_BREAKS_GEN_JUMPEX_STUPID_API_HIJACKING
+ // compute width of the string
+ GetTextExtentPoint32(hdcout, str, lstrlen(str), &timeSize);
+#else
+ DrawTextA(hdcout,str,lstrlenA(str),&r2,DT_VCENTER|DT_CALCRECT|DT_SINGLELINE/*|DT_NOCLIP*/|DT_NOPREFIX);
+ timeSize.cx = r2.right-r2.left;
+ r2.top = r.top;
+ r2.bottom = r.bottom;
+#endif
+ if (timeSize.cx < endp-xpos)
+ {
+ UINT alignment;
+
+ if (rightToLeft)
+ {
+ r2.left=xpos;
+ r2.right=xpos+timeSize.cx;
+
+ r.left+=timeSize.cx;
+ xpos+=timeSize.cx;
+ alignment=DT_LEFT|DT_RTLREADING;
+ }
+ else
+ {
+ r2.left=endp-timeSize.cx;
+ r2.right=endp;
+
+ r.right-=timeSize.cx;
+ endp-=timeSize.cx;
+ alignment=DT_RIGHT;
+ }
+
+ DrawTextA(hdcout,str,lstrlenA(str),&r2,DT_VCENTER|DT_SINGLELINE|alignment/*|DT_NOCLIP*/|DT_NOPREFIX); // fg: removed DT_NOCLIP to fix xp's cleartype from painting too far
+ }
+ }
+
+ UINT alignment;
+ if (rightToLeft)
+ {
+ alignment=DT_RIGHT|DT_RTLREADING;
+ }
+ else
+ {
+ alignment=DT_LEFT;
+ }
+
+ if (pos==-1)
+ CharUpperW(name);
+
+ int nameLen = lstrlenW(name);
+ int jtf_result = 0;
+ if (jtf_drawtext)
+ jtf_result=jtf_drawtext(hdcout,name,nameLen,&r,alignment|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOPREFIX);
+
+ if (!jtf_result)
+ DrawTextW(hdcout,name,nameLen,&r,alignment|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOPREFIX);
+
+ if (jtf_result != 2)
+ DrawTextW(hdcout,name,nameLen,&r,alignment|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOPREFIX|DT_CALCRECT);
+
+ HBRUSH oldbrush=(HBRUSH)SelectObject(hdcout,useBrush);
+ HPEN oldpen=(HPEN)SelectObject(hdcout,GetStockObject(NULL_PEN));
+ if (rightToLeft)
+ Rectangle(hdcout, xpos, r.top, 1+(endp-r.right)+r.left, 1+ypos+fontHeight);
+ else
+ Rectangle(hdcout,r.right,r.top,1+endp,1+ypos+fontHeight);
+ if (!pos || pos == num_songs-1)
+ {
+ SelectObject(hdcout,normbrush);
+ if (!pos)
+ Rectangle(hdcout, left, 20, 1+right, 1+23);
+ if (pos == num_songs-1)
+ Rectangle(hdcout, left, ypos+fontHeight, 1+right, config_pe_height-38+1);
+ }
+
+ SelectObject(hdcout,oldfont);
+ SelectObject(hdcout,oldpen);
+ SelectObject(hdcout,oldbrush);
+ }
+ else
+ {
+ int x;
+ char str[10]="";
+ setSrcBM(fontBM);
+ do_palmode(hdcout);
+ if (time >= 0)
+ {
+ StringCchPrintfA(str,10,"%d:%02d",time/60,(time)%60);
+ num_chars -= lstrlenA(str)+1;
+ }
+
+ for (x = 0; x < num_chars && name[x]; x ++)
+ {
+ int c2=0,c=0;
+ wchar_t oc;
+ oc=name[x];
+ if (x==num_chars-1 && name[x+1]) oc=L'\1';
+ getXYfromChar(oc,&c,&c2);
+ BitBlt(hdcout,xpos,ypos,5,6,bmDC,c,c2,SRCCOPY);
+ xpos += 5;
+ }
+
+ if (!name[x])
+ {
+ int c2=0,c=0;
+ getXYfromChar(L' ',&c,&c2);
+ if (time >= 0) num_chars++;
+ while (x++ < num_chars)
+ {
+ BitBlt(hdcout,xpos,ypos,5,6,bmDC,c,c2,SRCCOPY);
+ xpos += 5;
+ }
+ }
+
+ if (time >= 0)
+ {
+ int c2=0,c=0;
+ getXYfromChar(' ',&c,&c2);
+ BitBlt(hdcout,xpos,ypos,5,6,bmDC,c,c2,SRCCOPY);
+ xpos += 5;
+ if (pos < 0)
+ xpos = config_pe_width-29-5*lstrlenA(str);
+ else
+ xpos = config_pe_width-24-5*lstrlenA(str);
+ for (x = 0; str[x]; x ++)
+ {
+ getXYfromChar(str[x],&c,&c2);
+ BitBlt(hdcout,xpos,ypos,5,6,bmDC,c,c2,SRCCOPY);
+ xpos += 5;
+ }
+ }
+
+ if (xpos < config_pe_width-(pos<0?30:20))
+ {
+ int c2=0,c=0;
+ getXYfromChar(' ',&c,&c2);
+ BitBlt(hdcout,xpos,ypos,config_pe_width-(pos<0?30:20)-xpos,6,bmDC,c,c2,SRCCOPY);
+ }
+
+ unsetSrcBM();
+ }
+}
+
+void draw_pe_tbar(HWND hwnd, HDC hdc, int state)
+{
+ if (!pe_init)
+ return;
+ if (!disable_skin_borders)
+ {
+ WADrawDC hdcout(hdc, hwnd);
+ state = state?0:21;
+ do_palmode(hdcout);
+ setSrcBM(plMainBM);
+ if (config_pe_height != 14)
+ {
+ int nt;
+ int xp=0;
+ BitBlt(hdcout,xp,0,25,20,bmDC,0,state,SRCCOPY);
+ xp+=25;
+ nt = (config_pe_width - 25 - 25 - 100)/25;
+ if (nt)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdcout,xp,0,12,20,bmDC,127,state,SRCCOPY);
+ xp+=12;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdcout,xp,0,25,20,bmDC,127,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+
+ BitBlt(hdcout,xp,0,100,20,bmDC,26,state,SRCCOPY);
+ xp+=100;
+ nt = (config_pe_width - 25 - 25 - 100)/25;
+ if (nt)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdcout,xp,0,13,20,bmDC,127,state,SRCCOPY);
+ xp+=13;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdcout,xp,0,25,20,bmDC,127,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+ nt = (config_pe_width - 25 - 25 - 100)%25;
+ if (nt)
+ {
+ StretchBlt(hdcout,xp,0,nt,20,bmDC,127,state,25,20,SRCCOPY);
+ xp+=nt;
+ }
+ BitBlt(hdcout,xp,0,25,20,bmDC,153,state,SRCCOPY);
+ }
+ else
+ {
+ int xpos=0;
+ int n = (config_pe_width - 50)/25;
+ BitBlt(hdcout,xpos,0,25,14,bmDC,72,42,SRCCOPY);
+ xpos+=25;
+ n--;
+ while (n--)
+ {
+ BitBlt(hdcout,xpos,0,25,14,bmDC,72,57,SRCCOPY);
+ xpos+=25;
+ }
+ n = (config_pe_width - 50)%25;
+ if (n)
+ {
+ StretchBlt(hdcout,xpos,0,n,14,bmDC,72,57,24,14,SRCCOPY);
+ xpos+=n;
+ }
+ BitBlt(hdcout,xpos,0,50,14,bmDC,99,state?57:42,SRCCOPY);
+ }
+ unsetSrcBM();
+
+ if (config_pe_height == 14)
+ {
+ wchar_t ft[FILETITLE_SIZE] = {0};
+ int q=PlayList_getPosition();
+ if (q >= 0 && q < PlayList_getlength())
+ {
+ if (!g_has_deleted_current)
+ {
+ PlayList_getitem_pl(PlayList_getPosition(),ft);
+ q=PlayList_getsonglength(PlayList_getPosition());
+ }
+ else
+ {
+ StringCchCopyW(ft,FILETITLE_SIZE, FileTitle);
+ q=in_getlength();
+ }
+ }
+ else
+ {
+ getStringW(IDS_PLEDIT_NOFILE_WSHADE,ft,FILETITLE_SIZE);
+ q=-1;
+ }
+ draw_pe_song(hdcout, -1,ft,q,state?0:2);
+ }
+ }
+}
+
+void draw_pe_timedisp(HDC hdc, int minutes, int seconds, int tlm, int clear)
+{
+ if (!pe_init)
+ return;
+ static int lastm, lasts, lastc=1,lasttlm;
+ int x=config_pe_width-94+8;
+ int y=config_pe_height-15;
+ if (!hPLWindow) return;
+ if (disable_skin_borders) return;
+
+ WADrawDC mainDC(hdc, hPLWindow);
+ if (minutes == -666) { minutes=lastm; seconds=lasts; clear=lastc; tlm=lasttlm; }
+
+ lastm=minutes; lasts=seconds; lastc=clear; lasttlm=tlm;
+
+ do_palmode(mainDC);
+
+ setSrcBM(fontBM);
+ if (clear)
+ {
+ BitBlt(mainDC,x,y,4,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,x+4,y,5,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,x+5+4,y,5,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,x+5+4+5,y,5,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,x+5+4+5+4+4,y,5,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,x+5+4+5+4+5+4,y,5,6,bmDC,142,0,SRCCOPY);
+ }
+ else
+ {
+ if (tlm)
+ {
+ if (minutes < 0) minutes=-minutes;
+ if (seconds < 0) seconds=-seconds;
+ if (!(minutes/100)) BitBlt(mainDC,x,y,4,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,x+((minutes/100)?0:4),y,3,6,bmDC,75,6,SRCCOPY);
+ }
+ else
+ {
+ if (!(minutes/100)) BitBlt(mainDC,x,y,4,6,bmDC,142,0,SRCCOPY);
+ BitBlt(mainDC,x+((minutes/100)?0:4),y,3,6,bmDC,142,0,SRCCOPY);
+ }
+
+ if (minutes/100) BitBlt(mainDC,x+4,y,5,6,bmDC,5*((minutes/100)%10),6,SRCCOPY);
+ BitBlt(mainDC,x+5+4,y,5,6,bmDC,5*((minutes/10)%10),6,SRCCOPY);
+ BitBlt(mainDC,x+5+4+5,y,5,6,bmDC,5*((minutes)%10),6,SRCCOPY);
+ BitBlt(mainDC,x+5+4+5+4+4,y,5,6,bmDC,5*((seconds/10)%10),6,SRCCOPY);
+ BitBlt(mainDC,x+5+4+5+4+5+4,y,5,6,bmDC,5*((seconds)%10),6,SRCCOPY);
+ }
+ unsetSrcBM();
+}
+
+void draw_pe_tbutton(int b2, int b3, int b2_ws)
+{
+ if (!pe_init)
+ return;
+ if (disable_skin_borders) return;
+ {
+ WADrawDC hdcout(hPLWindow);
+ do_palmode(hdcout);
+ setSrcBM(plMainBM);
+ if (!b3)
+ BitBlt(hdcout,config_pe_width-11,3,9,9,bmDC,167,3,SRCCOPY);
+ else
+ BitBlt(hdcout,config_pe_width-11,3,9,9,bmDC,52,42,SRCCOPY);
+ if (!b2)
+ {
+ if (!b2_ws) BitBlt(hdcout,config_pe_width-20,3,9,9,bmDC,158,3,SRCCOPY);
+ else BitBlt(hdcout,config_pe_width-20,3,9,9,bmDC,128,45,SRCCOPY);
+ }
+ else
+ BitBlt(hdcout,config_pe_width-20,3,9,9,bmDC,b2_ws?150:62,42,SRCCOPY);
+ unsetSrcBM();
+ }
+}
+
+static bool IntersectY(int top1, int bottom1, int top2, int bottom2)
+{
+ int top = MAX(top1, top2);
+ int bottom = MIN(bottom1, bottom2);
+ return top <= bottom;
+}
+
+static void draw_pl(HWND hwnd, HDC hdcout)
+{
+ if (!pe_init)
+ return;
+ do_palmode(hdcout);
+ draw_pe_tbar(hwnd, hdcout, GetForegroundWindow()==hwnd?1:(config_hilite?0:1));
+ setSrcBM(plMainBM);
+ if (config_pe_height != 14)
+ {
+ int y;
+ int yp=20;
+ y=(config_pe_height-20-38)/29;
+ while (y-->0)
+ {
+ BitBlt(hdcout,0,yp,12,29,bmDC,0,42,SRCCOPY);
+ BitBlt(hdcout,config_pe_width-20,yp,5,29,bmDC,31,42,SRCCOPY);
+ BitBlt(hdcout,config_pe_width-7,yp,7,29,bmDC,31+13,42,SRCCOPY);
+ yp += 29;
+ }
+ y=(config_pe_height-20-38)%29;
+ if (y)
+ {
+ StretchBlt(hdcout,0,yp,12,y,bmDC,0,42,12,29,SRCCOPY);
+ StretchBlt(hdcout,config_pe_width-20,yp,5,y,bmDC,31,42,5,29,SRCCOPY);
+ StretchBlt(hdcout,config_pe_width-7,yp,7,y,bmDC,31+13,42,7,29,SRCCOPY);
+ yp += y;
+ }
+
+ if (!disable_skin_borders)
+ {
+ BitBlt(hdcout,0,yp,125,38,bmDC,0,72,SRCCOPY);
+ int x=(config_pe_width-125-150)/25;
+
+ int xp=125, s=0;
+ if (x >= 3) { x-=3; s=1;}
+ while (x-->0)
+ {
+ BitBlt(hdcout,xp,yp,25,38,bmDC,179,0,SRCCOPY);
+ xp+=25;
+ }
+ x = (config_pe_width-125-150)%25;
+ if (x)
+ {
+ StretchBlt(hdcout,xp,yp,x,38,bmDC,179,0,25,38,SRCCOPY);
+ xp+=x;
+ }
+ if (s)
+ {
+ BitBlt(hdcout,xp,yp,75,38,bmDC,205,0,SRCCOPY);
+ xp+=75;
+ }
+ BitBlt(hdcout,xp,yp,150,38,bmDC,126,72,SRCCOPY);
+ }
+ }
+ unsetSrcBM();
+}
+
+static void draw_pl2(HWND hwnd, HDC hdc, RECT &r)
+{
+ if (config_pe_height != 14)
+ {
+ {
+ int x,t;
+ int num_songs=(config_pe_height-38-20-2)/pe_fontheight;
+ if (pledit_disp_offs < 0) pledit_disp_offs=0;
+ t=PlayList_getlength()-pledit_disp_offs;
+ if (t < 1)
+ {
+ pledit_disp_offs=0;
+ t=PlayList_getlength();
+ }
+ if (t > num_songs) t = num_songs;
+ //LeaveCriticalSection(&g_mainwndcs);
+ for (x = 0; x < t; x ++)
+ {
+ int qt,b;
+
+ qt=22+x*pe_fontheight;
+ b=qt+pe_fontheight-1;
+ if (IntersectY(qt, b, r.top, r.bottom)
+ || (x == t-1 && config_pe_height-38 >= r.top))
+ {
+ wchar_t ft[FILETITLE_SIZE] = {0};
+ PlayList_getitem_pl(x+pledit_disp_offs,ft);
+
+ extern int g_has_deleted_current;
+ // EnterCriticalSection(&g_mainwndcs);
+ draw_pe_song(hdc, x,ft,PlayList_getsonglength(x+pledit_disp_offs),(PlayList_getselect(x+pledit_disp_offs) ? 1 : 0) + ((!g_has_deleted_current && PlayList_getPosition() == x+pledit_disp_offs) ? 2 : 0));
+ //LeaveCriticalSection(&g_mainwndcs);
+ }
+ }
+ //EnterCriticalSection(&g_mainwndcs);
+ wchar_t blank[] = L" ";
+ for (; x < num_songs; x ++)
+ {
+ draw_pe_song(hdc, x,blank ,-1,0);
+ }
+ if (r.right > config_pe_width-18 )
+ {
+ draw_pe_vslide(hwnd, hdc, 0, pledit_disp_offs);
+ }
+ }
+ draw_pe_timedisp(hdc, -666,0,0,0);
+ {
+ wchar_t str[64]=L"", str2[32]=L"";
+ {
+ int /*x=0,*/v,t,p=0;
+ int seltime=0,st2=0,st1=0, ttime=0;
+ v = PlayList_getlength();
+ for (t = 0; t < v; t ++)
+ {
+ int a = PlayList_getsonglength(t);
+ if (PlayList_getselect(t))
+ {
+ p++;
+ if (a<0)
+ st2=2;
+ else seltime += a;
+ }
+ if (a<0) st1=1;
+ //else x += a;
+ if (a > 0) ttime += a;
+ }
+ if (!seltime && !st2) StringCchCopyW(str,64, L"0:00");
+ else if (seltime)
+ {
+ if (seltime < 60*60)
+ StringCchPrintfW(str, 64, L"%d:%02d",seltime/60,seltime%60);
+ else
+ StringCchPrintfW(str,64, L"%d:%02d:%02d",seltime/60/60,(seltime/60)%60,seltime%60);
+ if (st2) StringCchCatW(str,64,L"+");
+ } else if (st2) StringCchCatW(str,64,L"?");
+
+ if (!ttime && !st1) StringCchCopyW(str2,32, L"0:00");
+ else if (ttime)
+ {
+ if (ttime < 60*60)
+ StringCchPrintfW(str2,32, L"%d:%02d",ttime/60,ttime%60);
+ else
+ StringCchPrintfW(str2,32,L"%d:%02d:%02d",ttime/60/60,(ttime/60)%60,ttime%60);
+ if (st1) StringCchCatW(str2,32,L"+");
+ } else if (st1) StringCchCatW(str2,32,L"?");
+ }
+ StringCchCatW(str,64,L"/");
+ StringCchCatW(str,64,str2);
+
+ draw_pe_infostr(hdc, str);
+ }
+ }
+}
+
+static void draw_paintDC_pe(HWND hwnd, HDC hdc, RECT &r)
+{
+ draw_pl(hwnd, hdc);
+}
+
+void draw_printclient_pe(HWND hwnd, HDC hdc, LPARAM /*drawingOptions*/)
+{
+ RECT r;
+ GetClientRect(hwnd,&r);
+ draw_paintDC_pe(hwnd, hdc, r);
+ draw_pl2(hwnd, hdc, r);
+}
+
+void draw_paint_pe(HWND hwnd)
+{
+ if (!pe_init)
+ return;
+ PAINTSTRUCT ps;
+ RECT r;
+ HDC hdc=BeginPaint(hwnd,&ps);
+ EnterCriticalSection(&g_mainwndcs);
+ r=ps.rcPaint;
+ draw_paintDC_pe(hwnd, hdc, r);
+ WADrawDC windowDC(0, hwnd);
+ draw_pl2(hwnd, windowDC, r);
+ LeaveCriticalSection(&g_mainwndcs);
+ EndPaint(hwnd,&ps);
+} \ No newline at end of file
diff --git a/Src/Winamp/draw_sa.cpp b/Src/Winamp/draw_sa.cpp
new file mode 100644
index 00000000..e7f8ce05
--- /dev/null
+++ b/Src/Winamp/draw_sa.cpp
@@ -0,0 +1,517 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "draw.h"
+#include "WADrawDC.h"
+
+unsigned char *specData;
+int sa_safe=0;
+int sa_kill=1;
+
+void draw_sa(unsigned char *values, int draw)
+{
+ static int bx[75];
+ static int t_bx[75];
+ static float t_vx[75];
+ int x;
+ int fo[5] = {3, 6, 12, 16, 32 };
+ float pfo[5]={1.05f,1.1f,1.2f,1.4f,1.6f};
+ int dbx;
+ float spfo;
+
+ int ws=(config_windowshade&&config_mw_open);
+ int s = (config_dsize&&config_mw_open)?1:0;
+ unsigned char *gmem;
+
+ dbx = fo[max(min(config_safalloff,4),0)];
+ spfo=pfo[max(min(config_sa_peak_falloff,4),0)];
+ sa_safe++;
+ if (sa_kill || !draw_initted || !specData)
+ {
+ sa_safe--;
+ return ;
+ }
+
+ if (s && draw)
+ {
+ int y;
+ gmem = specData;
+ if (!ws)
+ {
+ for (y = 0; y < 8; y++)
+ {
+ int *smem = (int *) gmem;
+ for (int x = 0; x < 76; x ++)
+ *smem++ = 0x0101;
+ gmem += 76*2*2;
+ memset(gmem,0,76*2*2);
+ gmem += 76*2*2;
+ }
+ }
+ else
+ {
+ gmem += 76*2*(32-10);
+ for (y = 0; y < 10; y++)
+ {
+ memset(gmem,0,76);
+ gmem += 76*2;
+ }
+ }
+ }
+ else if (draw)
+ {
+ int y;
+ gmem = specData+76*2*16;
+ if (!ws)
+ {
+ for (y = 0; y < 8; y++)
+ {
+ int *smem = (int *) gmem;
+ for (int x = 0; x < 76/4; x ++)
+ *smem++ = 0x10001;
+ gmem += 76*2;
+ memset(gmem,0,76);
+ gmem += 76*2;
+ }
+ }
+ else
+ {
+ gmem += 76*2*(16-5);
+ for (y = 0; y < 5; y++)
+ {
+ memset(gmem,0,76/2);
+ gmem += 76*2;
+ }
+ }
+ }
+
+ if (!values)
+ {
+ memset(bx,0,75*sizeof(int));
+ }
+ else if (!s) // singlesize
+ {
+ if (!ws) // non windowshade singlesize
+ {
+ if (config_sa == 2) // non windowshade singlesize oscilliscope
+ {
+ gmem = specData + 76*2*14;
+ if (draw)
+ {
+ int lv=-1;
+ if (((config_safire>>2)&3)==0) for (x = 0; x < 75; x ++)
+ {
+ register int v; register char c;
+ v = (((int) ((signed char *)values)[x])) + 8;
+ if (v < 0) v = 0 ; if (v > 15) v = 15; c = v/2-4; if (c < 0) c = -c; c += 18;
+ gmem[v*76*2] = c;
+ gmem++;
+ }
+ else if (((config_safire>>2)&3)==1) for (x = 0; x < 75; x ++)
+ {
+ register int v,t; register char c;
+ v = (((int) ((signed char *)values)[x])) + 8;
+ if (v < 0) v = 0 ; if (v > 15) v = 15; c = v/2-4; if (c < 0) c = -c; c += 18;
+ if (lv == -1) lv=v;
+ t=lv;
+ lv=v;
+ if (v >= t) while (v >= t) gmem[v--*76*2] = c;
+ else while (v < t) gmem[v++*76*2] = c;
+ gmem++;
+ }
+ else if (((config_safire>>2)&3)==2) for (x = 0; x < 75; x ++) // solid
+ {
+ register int v; register char c;
+ v = (((int) ((signed char *)values)[x])) + 8;
+ if (v < 0) v = 0 ; if (v > 15) v = 15; c = v/2-4; if (c < 0) c = -c; c += 18;
+ if (v > 7) while (v > 7) gmem[v--*76*2] = c;
+ else while (v <= 7) gmem[v++*76*2] = c;
+ gmem++;
+ }
+ }
+ }
+ else // non windowshade singlesize spectrum analyzer
+ {
+ for (x = 0; x < 75; x ++)
+ {
+ register int y,v,t;
+ t=x&~3;
+ if (!(config_safire&32))
+ {
+ int a=values[t],b=values[t+1],c=values[t+2],d=values[t+3];
+ v = a+b+c+d;//-min(a,min(b,min(c,d)));
+ v/=4;
+ }
+ else v = (((int)values[x]));
+ if (v > 15) v = 15;
+ if ((v<<4) < bx[x]) v = (bx[x]-=dbx)>>4;
+ else bx[x] = v<<4;
+ if (bx[x] < 0) bx[x] = 0;
+ if (v < 0) v = 0;
+ gmem = specData + 76*2*14 + x;
+ if ((config_safire&3)==1) t = v+2;
+ else if ((config_safire&3)==2) t=17-(v);
+ else t = 17;
+
+ if (t_bx[x] <= v*256) {
+ t_bx[x]=v*256;
+ t_vx[x]=3.0f;
+ }
+ if (draw && (config_safire&32 || (x&3)!=3))
+ {
+ if ((config_safire&3)!=2) for (y = 0; y < v; y ++)
+ {
+ *gmem = t-y;
+ gmem += 76*2;
+ }
+ else for (y = 0; y < v; y ++)
+ {
+ *gmem = t;
+ gmem += 76*2;
+ }
+ if (config_sa_peaks && t_bx[x]/256 >= 0 && t_bx[x]/256 <= 15)
+ {
+ specData[76*2*14 + (t_bx[x]/256)*76*2 + x]=23;
+ }
+ }
+ t_bx[x] -= (int)t_vx[x];
+ t_vx[x] *= spfo;
+ if (t_bx[x] < 0) t_bx[x]=0;
+ }
+ }
+ }
+ else // windowshade singlesize
+ {
+ if (config_sa==1) // windowshade singlesize spectrum analyzer
+ {
+ gmem = specData+76*2*(32-5);
+ for (x = 0; x < 37; x ++)
+ {
+ register int y,v,t;
+ t=((x)&~3)*2;
+ if (!(config_safire&32))
+ {
+ int a=values[t],b=values[t+1],c=values[t+2],d=values[t+3];
+ v = a+b+c+d;//-min(a,min(b,min(c,d)));
+ v/=4;
+ }
+ else v = (((int)values[x*2])+((int)values[x*2+1]))/2;
+ if (v > 15) v = 15;
+ if ((v<<4) < bx[x*2]) v = (bx[x*2]-=dbx)>>4;
+ else bx[x*2] = v<<4;
+ if (bx[x*2] < 0) bx[x*2] = 0;
+ if (v < 0) v = 0;
+ gmem = specData + 76*2*(32-5) + x;
+ if ((config_safire&3)==1) t = v+2;
+ else if ((config_safire&3)==2) t=17-(v);
+ else t = 17;
+
+ if (t_bx[x*2] <= v*256) {
+ t_bx[x*2]=v*256;
+ t_vx[x*2]=3.0f;
+ }
+ v = (v * 5)/15;
+ if (v > 5) v=5;
+ if (draw && (config_safire&32 || (x&3)!=3))
+ {
+ int poo=(t_bx[x*2]*5)/15/256;
+ if ((config_safire&3)!=2) for (y = 0; y < v; y ++)
+ {
+ *gmem = t-(y*15)/5;
+ gmem += 76*2;
+ }
+ else for (y = 0; y < v; y ++)
+ {
+ *gmem = t;
+ gmem += 76*2;
+ }
+ if (config_sa_peaks && poo >= 0 && poo <= 4)
+ {
+ specData[76*2*(32-5) + poo*76*2 + x]=23;
+ }
+ }
+ t_bx[x*2] -= (int)t_vx[x*2];
+ t_vx[x*2] *= spfo;
+ if (t_bx[x*2] < 0) t_bx[x*2]=0;
+ }
+ }
+ else if (config_sa == 2) // windowshade singlesize oscilliscope
+ {
+ int wm=((config_safire>>2)&3);
+ int lastv=-5;
+ gmem = specData+76*2*(32-5);
+ for (x = 0; x < 38; x ++)
+ {
+ int v = (((int) ((signed char *)values)[x])) + 8;
+ v *= 5;
+ v /= 16;
+ if (v < 0) v = 0 ; if (v > 4) v = 4;
+ if (wm==0 || lastv==-5)
+ {
+ lastv=v;
+ gmem[x+v*76*2] = 18;
+ }
+ else if (wm == 1)
+ {
+ int tmp=lastv;
+ lastv=v;
+ if (v >= tmp) while (v>=tmp) { gmem[x+v--*76*2] = 18; }
+ else while (v<=tmp) { gmem[x+v++*76*2] = 18; }
+ }
+ else if (wm == 2)
+ {
+ if (v >= 2) while (v>=2) { gmem[x+v--*76*2] = 18; }
+ else while (v<=2) { gmem[x+v++*76*2] = 18; }
+ }
+ }
+ }
+ }
+ }
+ else // doublesize
+ {
+ if (!ws)
+ {
+ if (config_sa == 2)
+ {
+ gmem = specData;// + 76*2*16;
+ if (draw)
+ {
+ int lv=-1;
+ if (((config_safire>>2)&3)==0) for (x = 0; x < 75*2; x += 2)
+ {
+ register int v; register char c;
+ v = (((int) ((signed char *)values)[x/2])) + 8;
+ if (v < 0) v = 0; if (v > 15) v = 15; c = v/2-4; if (c < 0) c = -c; c += 18;
+ gmem[v*76*2*2] = c; gmem++[v*76*2*2 + 76*2] = c;
+ gmem[v*76*2*2] = c; gmem++[v*76*2*2 + 76*2] = c;
+ }
+ else if (((config_safire>>2)&3)==1) for (x = 0; x < 75*2; x += 2)
+ {
+ register int v,t; register char c;
+ v = (((int) ((signed char *)values)[x/2])) + 8;
+ if (v < 0) v = 0; if (v > 15) v = 15; c = v/2-4; if (c < 0) c = -c; c += 18;
+ if (lv == -1) lv=v;
+ t=lv;
+ lv=v;
+ if (v >= t) while (v >= t)
+ {
+ gmem[v*76*2*2] = c;
+ gmem[v*76*2*2 + 76*2] = c;
+ gmem[v*76*2*2 + 1] = c;
+ gmem[v*76*2*2 + 76*2 + 1] = c;
+ v--;
+ }
+ else while (v < t)
+ {
+ gmem[v*76*2*2] = c;
+ gmem[v*76*2*2 + 76*2] = c;
+ gmem[v*76*2*2 + 1] = c;
+ gmem[v*76*2*2 + 76*2 + 1] = c;
+ v++;
+ }
+ gmem+=2;
+ }
+ else if (((config_safire>>2)&3)==2) for (x = 0; x < 75*2; x += 2)
+ {
+ register int v; register char c;
+ v = (((int) ((signed char *)values)[x/2])) + 8;
+ if (v < 0) v = 0; if (v > 15) v = 15; c = v/2-4; if (c < 0) c = -c; c += 18;
+ if (v > 7) while (v > 7)
+ {
+ gmem[v*76*2*2] = c;
+ gmem[v*76*2*2 + 76*2] = c;
+ gmem[v*76*2*2 + 1] = c;
+ gmem[v*76*2*2 + 76*2 + 1] = c;
+ v--;
+ }
+ else while (v <= 7)
+ {
+ gmem[v*76*2*2] = c;
+ gmem[v*76*2*2 + 76*2] = c;
+ gmem[v*76*2*2 + 1] = c;
+ gmem[v*76*2*2 + 76*2 + 1] = c;
+ v++;
+ }
+ gmem+=2;
+ }
+ }
+ }
+ else
+ {
+ for (x = 0; x < 75*2;)
+ {
+ register int y,v, t;
+ t=(x/2)&~3;
+ if (!(config_safire&32))
+ {
+ int a=values[t],b=values[t+1],c=values[t+2],d=values[t+3];
+ v = a+b+c+d;//-min(a,min(b,min(c,d)));
+ v/=4;
+ }
+ else v = (((int)values[x/2]));
+ if (v > 15) v = 15;
+ if ((v<<4) < bx[x/2]) v = (bx[x/2]-=dbx)>>4;
+ else bx[x/2] = v<<4;
+ if (bx[x/2] < 0) bx[x/2] = 0;
+ if (v < 0) v = 0;
+ gmem = specData+x;
+ if ((config_safire&3)==1) t = v+2;
+ else if ((config_safire&3)==2) t = 17 - v;
+ else t = 17;
+ if (t_bx[x/2] <= v*256) {
+ t_bx[x/2]=v*256;
+ t_vx[x/2]=3.0f;
+ }
+ v*=2;
+ if (draw && (config_safire&32 || ((x/2)&3)!=3))
+ {
+ if ((config_safire&3)!=2) for (y = 0; y < v; y ++)
+ {
+ gmem[0] = gmem[1] = t-y/2;
+ gmem += 76*2;
+ }
+ else for (y = 0; y < v; y ++)
+ {
+ gmem[0] = gmem[1] = t;
+ gmem += 76*2;
+ }
+ if (config_sa_peaks && t_bx[x/2]/256 > 0 && t_bx[x/2]/256 <= 15)
+ {
+ specData[(t_bx[x/2]/256)*76*4 + x]=specData[(t_bx[x/2]/256)*76*4 + x+1]=23;
+ specData[(t_bx[x/2]/256)*76*4 + x + 76*2]=specData[(t_bx[x/2]/256)*76*4 + x+1+ 76*2]=23;
+ }
+ }
+ t_bx[x/2] -= (int)t_vx[x/2];
+ t_vx[x/2] *=spfo;
+ if (t_bx[x/2] < 0) t_bx[x/2]=0;
+ x+=2;
+ }
+ }
+ }
+ else
+ {
+ if (config_sa == 2) // doublesize window shade scope
+ {
+ int wm=((config_safire>>2)&3);
+ int lastv=-5;
+ gmem = specData+76*2*(32-10);
+ for (x = 0; x < 75; x ++)
+ {
+ int v = (((int) ((signed char *)values)[x])) + 8;
+ v *= 10;
+ v /= 16;
+ if (v < 0) v = 0 ; if (v > 9) v = 9;
+ if (wm==0 || lastv==-5)
+ {
+ lastv=v;
+ gmem[x+v*76*2] = 18;
+ }
+ else if (wm == 1)
+ {
+ int tmp=lastv;
+ lastv=v;
+ if (v >= tmp) while (v>=tmp) { gmem[x+v--*76*2] = 18; }
+ else while (v<=tmp) { gmem[x+v++*76*2] = 18; }
+ }
+ else if (wm == 2)
+ {
+ if (v >= 4) while (v>=4) { gmem[x+v--*76*2] = 18; }
+ else while (v<=4) { gmem[x+v++*76*2] = 18; }
+ }
+ }
+ }
+ if (config_sa == 1) { // doublesize window shade spectrum
+ for (x = 0; x < 75; x ++)
+ {
+ register int y,v,t;
+ t=(x)&~3;
+ if (!(config_safire&32))
+ {
+ int a=values[t],b=values[t+1],c=values[t+2],d=values[t+3];
+ v = a+b+c+d;//-min(a,min(b,min(c,d)));
+ v/=4;
+ }
+ else v = (int)values[x];
+ if (v > 15) v = 15;
+ if ((v<<4) < bx[x]) v = (bx[x]-=dbx)>>4;
+ else bx[x] = v<<4;
+ if (bx[x] < 0) bx[x] = 0;
+ if (v < 0) v = 0;
+ gmem = specData + 76*2*(32-10) + x;
+ if ((config_safire&3)==1) t = v+2;
+ else if ((config_safire&3)==2) t=17-(v);
+ else t = 17;
+
+ if (t_bx[x] <= v*256) {
+ t_bx[x]=v*256;
+ t_vx[x]=3.0f;
+ }
+ v = (v * 10)/15;
+ if (draw && (config_safire&32 || (x&3)!=3))
+ {
+ int poo=(t_bx[x]*10)/15/256;
+ if ((config_safire&3)!=2) for (y = 0; y < v; y ++)
+ {
+ *gmem = t-(y*15)/10;
+ gmem += 76*2;
+ }
+ else for (y = 0; y < v; y ++)
+ {
+ *gmem = t;
+ gmem += 76*2;
+ }
+ if (config_sa_peaks && poo >= 0 && poo <= 9)
+ {
+ specData[76*2*(32-10) + poo*76*2 + x]=23;
+ }
+ }
+ t_bx[x] -= (int)t_vx[x];
+ t_vx[x] *= spfo;
+ if (t_bx[x] < 0) t_bx[x]=0;
+ }
+ }
+ }
+ }
+
+ if (draw)
+ {
+ if (config_mw_open && hVisWindow)
+ {
+ WADrawDC myDC(hVisWindow);
+ if (myDC)
+ {
+ do_palmode(myDC);
+ if(values)
+ {
+ if (!ws) BitBlt(myDC,0,0,76<<s,16<<s,specDC,0,0,SRCCOPY);
+ else BitBlt(myDC,0,0,38<<s,5<<s,specDC,0,0,SRCCOPY);
+ }
+ else
+ {
+ InvalidateRect(hMainWindow,NULL,FALSE);
+ }
+ }
+ }
+ else if (config_pe_open && config_pe_width >= 350 && config_pe_height != 14 && hPLVisWindow)
+ {
+ if (hPLWindow)
+ {
+ WADrawDC myDC(hPLVisWindow);
+ if (myDC)
+ {
+ do_palmode(myDC);
+ if(values)
+ BitBlt(myDC,0,0,72,16,specDC,0,0,SRCCOPY);
+ else
+ InvalidateRect(hPLWindow,NULL,FALSE);
+ }
+ }
+ }
+ }
+ sa_safe--;
+} \ No newline at end of file
diff --git a/Src/Winamp/draw_vw.cpp b/Src/Winamp/draw_vw.cpp
new file mode 100644
index 00000000..c8ec916f
--- /dev/null
+++ b/Src/Winamp/draw_vw.cpp
@@ -0,0 +1,231 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "draw.h"
+#include "resource.h"
+#include "WADrawDC.h"
+
+HBITMAP vwMainBM;
+extern "C" int vw_init=0;
+
+
+
+void draw_vw_init()
+{
+ if (vw_init)
+ draw_vw_kill();
+ vw_init=1;
+ vwMainBM = draw_LBitmap(MAKEINTRESOURCE(IDB_VIDEO),L"video.bmp");
+}
+
+void draw_vw_kill()
+{
+ if (!vw_init)
+ return;
+ DeleteObject(vwMainBM);
+
+}
+
+void draw_vw_mbuts(int whichb)
+{
+ if (!disable_skin_borders && hVideoWindow && vw_init)
+ {
+ int numb=5;
+ int x;
+ WADrawDC hdcout(hVideoWindow);
+
+ do_palmode(hdcout);
+ setSrcBM(vwMainBM);
+ for (x = 0; x < numb; x ++)
+ {
+ int nx=9+x*15;
+ int ny=51;
+ if (x==whichb)
+ {
+ nx+=158-9;
+ ny=42;
+ }
+ BitBlt(hdcout,9+x*15,config_video_height-29,15,18,bmDC,nx,ny,SRCCOPY);
+ }
+ unsetSrcBM();
+ }
+}
+
+void draw_vw_tbar(int state)
+{
+ if (!disable_skin_borders && hVideoWindow && vw_init)
+ {
+ WADrawDC hdcout(hVideoWindow);
+ state = state?0:21;
+ do_palmode(hdcout);
+ setSrcBM(vwMainBM);
+ {
+ int nt;
+ int xp=0;
+ BitBlt(hdcout,xp,0,25,20,bmDC,0,state,SRCCOPY);
+ xp+=25;
+ nt = (config_video_width - 25 - 25 - 100)/25;
+ if (nt)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdcout,xp,0,12,20,bmDC,127,state,SRCCOPY);
+ xp+=12;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdcout,xp,0,25,20,bmDC,127,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+ BitBlt(hdcout,xp,0,100,20,bmDC,26,state,SRCCOPY);
+ xp+=100;
+ nt = (config_video_width - 25 - 25 - 100)/25;
+ if (nt)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdcout,xp,0,13,20,bmDC,127,state,SRCCOPY);
+ xp+=13;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdcout,xp,0,25,20,bmDC,127,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+ nt = (config_video_width - 25 -25 - 100) %25;
+ if (nt)
+ {
+ StretchBlt(hdcout,xp,0,nt,20,bmDC,127,state,25,20,SRCCOPY);
+ xp+=nt;
+ }
+ BitBlt(hdcout,xp,0,25,20,bmDC,153,state,SRCCOPY);
+ }
+ unsetSrcBM();
+ }
+}
+
+void draw_vw(HDC hdcout)
+{
+ if (!hVideoWindow || !vw_init)
+ return;
+ do_palmode(hdcout);
+ draw_vw_tbar(GetForegroundWindow()==hVideoWindow?1:(config_hilite?0:1));
+ if (!disable_skin_borders)
+ {
+ setSrcBM(vwMainBM);
+ {
+ int y=(config_video_height-20-38)/29;
+ int yp=20,x,xp;
+ while (y-->0)
+ {
+ BitBlt(hdcout,0,yp,11,29,bmDC,127,42,SRCCOPY);
+ BitBlt(hdcout,config_video_width-8,yp,8,29,bmDC,139,42,SRCCOPY);
+ yp += 29;
+ }
+ y=(config_video_height-20-38)%29;
+ if (y)
+ {
+ StretchBlt(hdcout,0,yp,11,y,bmDC,127,42,11,29,SRCCOPY);
+ StretchBlt(hdcout,config_video_width-8,yp,8,y,bmDC,139,42,8,29,SRCCOPY);
+ yp += y;
+ }
+ BitBlt(hdcout,0,yp,125,38,bmDC,0,42,SRCCOPY);
+ x=(config_video_width-125-125)/25;
+ xp=125;
+ while (x-->0)
+ {
+ BitBlt(hdcout,xp,yp,25,38,bmDC,127,81,SRCCOPY);
+ xp+=25;
+ }
+ x=(config_video_width-125-125)%25;
+ if (x)
+ {
+ StretchBlt(hdcout,xp,yp,x,38,bmDC,127,81,25,38,SRCCOPY);
+ xp+=x;
+ }
+ BitBlt(hdcout,xp,yp,125,38,bmDC,0,81,SRCCOPY);
+ draw_vw_info(NULL,0);
+ }
+ unsetSrcBM();
+ }
+}
+
+wchar_t draw_vw_info_lastb[512] = {0};
+void draw_vw_info(wchar_t *t, int erase)
+{
+ if (!disable_skin_borders && hVideoWindow&&vw_init)
+ {
+ WADrawDC hdcout(hVideoWindow);
+ if (!t) t=draw_vw_info_lastb;
+ else lstrcpynW(draw_vw_info_lastb,t,sizeof(draw_vw_info_lastb));
+
+ if (erase)
+ {
+ //int y=(config_video_height-20-38)/29;
+ int yp=config_video_height-38,x,xp;
+ do_palmode(hdcout);
+ setSrcBM(vwMainBM);
+ BitBlt(hdcout,0,yp,125,38,bmDC,0,42,SRCCOPY);
+ x=(config_video_width-125-125)/25;
+ xp=125;
+ while (x-->0)
+ {
+ BitBlt(hdcout,xp,yp,25,38,bmDC,127,81,SRCCOPY);
+ xp+=25;
+ }
+ x=(config_video_width-125-125)%25;
+ if (x)
+ {
+ StretchBlt(hdcout,xp,yp,x,38,bmDC,127,81,25,38,SRCCOPY);
+ xp+=x;
+ }
+ BitBlt(hdcout,xp,yp,125,38,bmDC,0,81,SRCCOPY);
+ unsetSrcBM();
+ }
+
+ RECT r={92,config_video_height-27,config_video_width-25,config_video_height-13};
+ HGDIOBJ oldFont=SelectObject(hdcout,mfont);
+ SetTextColor(hdcout,Skin_PLColors[4]);
+ SetBkColor(hdcout,Skin_PLColors[5]);
+ DrawTextW(hdcout,t,-1,&r,DT_SINGLELINE|DT_LEFT|DT_NOPREFIX);
+ SelectObject(hdcout,oldFont);
+ }
+}
+
+
+void draw_paint_vw(HWND hwnd)
+{
+ if (!hVideoWindow || !vw_init)
+ return;
+ PAINTSTRUCT ps;
+ RECT r;
+ EnterCriticalSection(&g_mainwndcs);
+ draw_vw(BeginPaint(hwnd,&ps));
+ r=ps.rcPaint;
+ EndPaint(hwnd,&ps);
+ LeaveCriticalSection(&g_mainwndcs);
+}
+
+void draw_vw_tbutton(int b3)
+{
+ if (!disable_skin_borders && hVideoWindow && vw_init)
+ {
+ WADrawDC hdcout(hVideoWindow);
+ do_palmode(hdcout);
+ setSrcBM(vwMainBM);
+ if (!b3)
+ BitBlt(hdcout,config_video_width-11,3,9,9,bmDC,167,3,SRCCOPY);
+ else
+ BitBlt(hdcout,config_video_width-11,3,9,9,bmDC,148,42,SRCCOPY);
+ unsetSrcBM();
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/dwm.cpp b/Src/Winamp/dwm.cpp
new file mode 100644
index 00000000..03d94c52
--- /dev/null
+++ b/Src/Winamp/dwm.cpp
@@ -0,0 +1,386 @@
+#include "main.h"
+#include "config.h"
+#include "wintheme.h"
+#include <shobjidl.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <tataki/bitmap/bitmap.h>
+#include "../Agave/Language/api_language.h"
+
+typedef HRESULT(WINAPI *DWMREGISTERTHUMBNAIL)(HWND hwndDestination, HWND hwndSource, void **phThumbnailId);
+typedef HRESULT(WINAPI *DWMUPATETHUMBNAILPROPERTIES)(void* hThumbnailId, void* ptnProperties);
+typedef HRESULT(WINAPI *DWMUNREGISTERTHUMBNAIL)(void *hThumbnailId);
+typedef HRESULT(WINAPI *DWMSETWINDOWATTRIBUTE)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
+typedef HRESULT (WINAPI *DWMENABLEMMCSS)(BOOL fEnableMMCSS);
+typedef HRESULT (WINAPI *DWMSETICONICTHUMBNAIL)(HWND hwnd, HBITMAP hbmp, DWORD dwSITFlags);
+typedef HRESULT (WINAPI *DWMINVALIDATEICONICBITMAPS)( HWND hwnd);
+typedef HRESULT (WINAPI *DWMSETICONICLIVEPREVIEWBITMAP )(HWND hwnd, HBITMAP hbmp, POINT *pptClient, DWORD dwSITFlags);
+static HMODULE dwmapi;
+static void *thumbnail;
+static DWMREGISTERTHUMBNAIL regThumbnail;
+static DWMUPATETHUMBNAILPROPERTIES updateProp;
+static DWMUNREGISTERTHUMBNAIL unregThumbnail;
+static DWMSETWINDOWATTRIBUTE setWindowAttribute;
+static DWMENABLEMMCSS dwmEnableMMCSS;
+static DWMSETICONICTHUMBNAIL dwmSetIconicThumbnail;
+static DWMINVALIDATEICONICBITMAPS dwmInvalidateIconicBitmaps;
+static DWMSETICONICLIVEPREVIEWBITMAP dwmSetIconicLivePreviewBitmap;
+
+HIMAGELIST toolbarIcons = NULL;
+
+BOOL atti_present=false;
+static bool triedLoad=false;
+static bool LoadDWMApi()
+{
+ if (!triedLoad)
+ {
+ wchar_t gen_win7shell_path[MAX_PATH] = {0};
+ PathCombineW(gen_win7shell_path, PLUGINDIR, L"gen_win7shell.dll");
+ HMODULE gen_win7shell = LoadLibraryW(gen_win7shell_path);
+ if (gen_win7shell)
+ {
+ atti_present=true;
+ FreeLibrary(gen_win7shell);
+ }
+
+ dwmapi = LoadLibraryA("dwmapi.dll");
+
+ regThumbnail = (DWMREGISTERTHUMBNAIL)GetProcAddress(dwmapi, "DwmRegisterThumbnail");
+ updateProp = (DWMUPATETHUMBNAILPROPERTIES)GetProcAddress(dwmapi, "DwmUpdateThumbnailProperties");
+ unregThumbnail = (DWMUNREGISTERTHUMBNAIL)GetProcAddress(dwmapi, "DwmUnregisterThumbnail");
+ setWindowAttribute = (DWMSETWINDOWATTRIBUTE)GetProcAddress(dwmapi, "DwmSetWindowAttribute");
+ dwmEnableMMCSS = (DWMENABLEMMCSS)GetProcAddress(dwmapi, "DwmEnableMMCSS");
+ dwmSetIconicThumbnail = (DWMSETICONICTHUMBNAIL)GetProcAddress(dwmapi, "DwmSetIconicThumbnail");
+ dwmInvalidateIconicBitmaps = (DWMINVALIDATEICONICBITMAPS)GetProcAddress(dwmapi, "DwmInvalidateIconicBitmaps");
+ dwmSetIconicLivePreviewBitmap = (DWMSETICONICLIVEPREVIEWBITMAP)GetProcAddress(dwmapi, "DwmSetIconicLivePreviewBitmap");
+
+ triedLoad = true;
+ }
+
+ return dwmapi && regThumbnail && updateProp && unregThumbnail && setWindowAttribute && dwmEnableMMCSS;
+}
+
+bool LoadToolbarIcons()
+{
+ //toolbarIcons already loaded
+ if (toolbarIcons != NULL)
+ {
+ return true;
+ }
+
+ //load toolbarIcons
+ toolbarIcons = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32, 5, 0);
+ if (toolbarIcons == NULL)
+ return false;
+
+ for (int i = 0; i < 5; i++)
+ {
+ HICON hIcon = LoadIconW(hMainInstance, MAKEINTRESOURCE(IDI_TBICON1+i));
+ if (hIcon != NULL)
+ ImageList_AddIcon(toolbarIcons, hIcon);
+ // no need to call DestroyIcon(..) if using LoadIcon(..)
+ // as the OS will free things anyway - might be cause of
+ // the random button disappearing issue...?
+ //DestroyIcon(hIcon);
+ }
+
+ return true;
+}
+
+static BOOL taskbar_inited = FALSE;
+void OnTaskbarButtonCreated(BOOL force)
+{
+ if (pTaskbar3 || (SUCCEEDED(CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&pTaskbar3))) && pTaskbar3))
+ {
+ if (force)
+ {
+ taskbar_inited = TRUE;
+ pTaskbar3->HrInit();
+ }
+ if (taskbar_inited)
+ {
+ RegisterThumbnailTab(IsWindow(g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow);
+ }
+ }
+}
+
+void UnregisterThumbnailTab(HWND hWnd)
+{
+ if (LoadDWMApi() && !atti_present)
+ {
+ if (!IsVistaOrLower() && IsWindow(hWnd) && pTaskbar3 != NULL)
+ {
+ if (taskbar_inited)
+ pTaskbar3->UnregisterTab(hWnd);
+ }
+ }
+}
+
+static void addToolbarButtons(HWND hWnd, BOOL update)
+{
+ THUMBBUTTON thbButtons[5];
+ DWORD dwMask = THB_BITMAP | THB_TOOLTIP;
+
+ thbButtons[0].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[0].iId = 0;
+ thbButtons[0].iBitmap = 0;
+ StringCbCopyW(thbButtons[0].szTip, sizeof(thbButtons[0].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PREVIOUS, NULL, 0));
+
+ thbButtons[1].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[1].iId = 1;
+ thbButtons[1].iBitmap = 1;
+ StringCbCopyW(thbButtons[1].szTip, sizeof(thbButtons[1].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PLAY, NULL, 0));
+
+ thbButtons[2].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[2].iId = 2;
+ thbButtons[2].iBitmap = 2;
+ StringCbCopyW(thbButtons[2].szTip, sizeof(thbButtons[2].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PAUSE, NULL, 0));
+
+ thbButtons[3].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[3].iId = 3;
+ thbButtons[3].iBitmap = 3;
+ StringCbCopyW(thbButtons[3].szTip, sizeof(thbButtons[3].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_STOP, NULL, 0));
+
+ thbButtons[4].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[4].iId = 4;
+ thbButtons[4].iBitmap = 4;
+ StringCbCopyW(thbButtons[4].szTip, sizeof(thbButtons[4].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_NEXT, NULL, 0));
+
+ if (update)
+ pTaskbar3->ThumbBarUpdateButtons(hWnd, ARRAYSIZE(thbButtons), thbButtons);
+ else
+ pTaskbar3->ThumbBarAddButtons(hWnd, ARRAYSIZE(thbButtons), thbButtons);
+}
+
+void RegisterThumbnailTab(HWND hWnd)
+{
+ if (LoadDWMApi() && !atti_present)
+ {
+ if (dwmInvalidateIconicBitmaps) // even if DWM is loaded, this only exists on win7 (NT6.1)
+ dwmInvalidateIconicBitmaps(hMainWindow);
+
+ if (!IsWindow(hWnd))
+ {
+ hWnd = hMainWindow;
+ }
+
+ if (hWnd != hMainWindow)
+ {
+ wchar_t title[512] = {0};
+ GetWindowTextW(hMainWindow, title, sizeof(title));
+ SetWindowTextW(hWnd, title);
+
+#ifdef WIN64
+ HICON hIcon = (HICON)GetClassLongPtr(hMainWindow, GCLP_HICONSM);
+#else
+ HICON hIcon = (HICON)GetClassLong(hMainWindow, GCL_HICONSM);
+#endif
+
+
+ SendMessageW(hWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
+ }
+
+ if (IsWindow(hWnd) && IsWindow(hMainWindow))
+ {
+ BOOL dwm_setting = FALSE;
+ setWindowAttribute(hWnd, DWMWA_FORCE_ICONIC_REPRESENTATION, &dwm_setting, sizeof(dwm_setting));
+ setWindowAttribute(hWnd, DWMWA_HAS_ICONIC_BITMAP, &dwm_setting, sizeof(dwm_setting));
+
+ if (!IsVistaOrLower() && pTaskbar3 != NULL)
+ {
+ // shouldn't fail, but there's a case on loading where it can due to timing quirks
+ // so for that we then allow the regsistation to still happen (hence the dup code)
+ HRESULT hr = pTaskbar3->RegisterTab(hWnd, hMainWindow);
+ if (SUCCEEDED(hr))
+ {
+ if (SUCCEEDED(pTaskbar3->SetTabOrder(hWnd, NULL)))
+ {
+ pTaskbar3->SetTabActive(hWnd, hMainWindow, 0);
+
+ if (LoadToolbarIcons())
+ {
+ HRESULT hr = pTaskbar3->ThumbBarSetImageList(hWnd, toolbarIcons);
+ if (SUCCEEDED(hr))
+ {
+ addToolbarButtons(hWnd, false);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (SUCCEEDED(pTaskbar3->SetTabOrder(hWnd, NULL)))
+ {
+ pTaskbar3->SetTabActive(hWnd, hMainWindow, 0);
+
+ if (LoadToolbarIcons())
+ {
+ HRESULT hr = pTaskbar3->ThumbBarSetImageList(hWnd, toolbarIcons);
+ if (SUCCEEDED(hr))
+ {
+ addToolbarButtons(hWnd, false);
+ }
+ }
+ }
+ }
+ }
+
+ if (hWnd != hMainWindow)
+ {
+ dwm_setting = TRUE;
+ setWindowAttribute(hMainWindow, DWMWA_FORCE_ICONIC_REPRESENTATION, &dwm_setting, sizeof(dwm_setting));
+ setWindowAttribute(hMainWindow, DWMWA_HAS_ICONIC_BITMAP, &dwm_setting, sizeof(dwm_setting));
+ }
+ }
+ }
+}
+
+void DisableVistaPreview()
+{
+ if (LoadDWMApi())
+ {
+ BOOL blah=TRUE;
+ setWindowAttribute(hMainWindow, DWMWA_FORCE_ICONIC_REPRESENTATION, &blah, sizeof(blah));
+ setWindowAttribute(hMainWindow, DWMWA_HAS_ICONIC_BITMAP, &blah, sizeof(blah));
+ }
+}
+
+static bool done_the_dance=false;
+void DoTheVistaVideoDance()
+{
+ if (!done_the_dance && LoadDWMApi())
+ {
+ dwmEnableMMCSS(TRUE); // the magic "make my program not suck" function
+ /* TODO:
+ DWM_PRESENT_PARAMETERS dpp;
+ memset(&dpp, 0, sizeof(dpp));
+ dpp.cbSize = sizeof(dpp);
+ dpp.fQueue = true;
+ dpp.cBuffer = 8;
+ dpp.fUseSourceRate = false;
+ dpp.cRefreshesPerFrame = 1;
+ dpp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT;
+ HRESULT hr = DwmSetPresentParameters(hWnd, &dpp);
+ */
+ // TODO also, unrelated, but check out AvSetMmThreadCharacteristics sometime.
+ }
+ done_the_dance = true;
+}
+
+static void Adjust(int bmpw, int bmph, RECT &r)
+{
+ // maintain 'square' stretching
+ int w = r.right - r.left;
+ int h = r.bottom - r.top;
+ double aspX = (double)(w)/(double)bmpw;
+ double aspY = (double)(h)/(double)bmph;
+ double asp = min(aspX, aspY);
+ int newW = (int)(bmpw*asp);
+ int newH = (int)(bmph*asp);
+ r.left = (w - newW)/2;
+ r.top = (h - newH)/2;
+ r.right = r.left + newW;
+ r.bottom = r.top + newH;
+}
+
+void RefreshIconicThumbnail()
+{
+ if (LoadDWMApi() && !atti_present)
+ {
+ if (dwmInvalidateIconicBitmaps) // even if DWM is loaded, this only exists on win7 (NT6.1)
+ dwmInvalidateIconicBitmaps(hMainWindow);
+ }
+}
+
+void OnIconicThumbnail(int width, int height)
+{
+ static BltCanvas *iconic_thumbnail_bitmap=0;
+
+ HWND hWnd = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
+
+ RECT client_size;
+ GetClientRect(hWnd, &client_size);
+
+ if (!iconic_thumbnail_bitmap)
+ {
+ iconic_thumbnail_bitmap = new BltCanvas(client_size.right, client_size.bottom, hMainWindow);
+ }
+ else
+ {
+ iconic_thumbnail_bitmap->DestructiveResize(client_size.right, client_size.bottom);
+ }
+
+ SendMessageW(hWnd, WM_PRINTCLIENT, (WPARAM) iconic_thumbnail_bitmap->getHDC(), PRF_CHILDREN | PRF_CLIENT | /*PRF_ERASEBKGND |*/ PRF_NONCLIENT /*| PRF_OWNED*/);
+
+ void *bits=0;
+ BITMAPINFO bmi = {0};
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = width;
+ bmi.bmiHeader.biHeight = -height;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ HBITMAP hbmp = CreateDIBSection(iconic_thumbnail_bitmap->getHDC(), &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ if (hbmp)
+ {
+ BltCanvas resizedBitmap(hbmp);
+ int x=0, y=0;
+
+ RECT dest;
+ dest.left = x;
+ dest.top = y;
+ dest.right = width;
+ dest.bottom = height;
+ resizedBitmap.drawRect(&dest, 1, 0);
+ Adjust(client_size.right, client_size.bottom, dest);
+ iconic_thumbnail_bitmap->stretchToRectAlpha(&resizedBitmap, &client_size, &dest);
+ dwmSetIconicThumbnail(hMainWindow, hbmp, 0);
+ }
+}
+
+void OnThumbnailPreview()
+{
+ static BltCanvas *thumbnail_preview_bitmap=0;
+
+ HWND hWnd = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
+
+ RECT client_size;
+ GetClientRect(hWnd, &client_size);
+
+ if (!thumbnail_preview_bitmap)
+ {
+ thumbnail_preview_bitmap = new BltCanvas(client_size.right, client_size.bottom, hWnd);
+ }
+ else
+ {
+ thumbnail_preview_bitmap->DestructiveResize(client_size.right, client_size.bottom);
+ }
+
+ SendMessageW(hWnd, WM_PRINT, (WPARAM) thumbnail_preview_bitmap->getHDC(), PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT /*| PRF_OWNED*/);
+
+ void *bits=0;
+ BITMAPINFO bmi = {0};
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = client_size.right - client_size.left;
+ bmi.bmiHeader.biHeight = client_size.top - client_size.bottom;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ HBITMAP hbmp = CreateDIBSection(thumbnail_preview_bitmap->getHDC(), &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ if (hbmp)
+ {
+ POINT offset;
+ offset.x = client_size.left;
+ offset.y = client_size.top;
+ if (dwmSetIconicLivePreviewBitmap(hWnd, hbmp, &offset, 1) == S_OK)
+ {
+ MessageBoxA(NULL, "winamp/live", "winamp/live", MB_OK);
+ }
+ else
+ {
+ MessageBoxA(NULL, "winamp/no live", "winamp/no live", MB_OK);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/embwnd.cpp b/Src/Winamp/embwnd.cpp
new file mode 100644
index 00000000..7f74fb0f
--- /dev/null
+++ b/Src/Winamp/embwnd.cpp
@@ -0,0 +1,937 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include <windowsx.h>
+
+#include "main.h"
+#include "api.h"
+
+void draw_paint_emb( HWND, int, int, int );
+void draw_embed_tbar( HWND, int, int );
+void draw_embed_tbutton( HWND, int, int );
+void draw_embed( HDC, int, int );
+
+// all of this stuff is barely working. I will be fixing it soon soon.
+
+/// embed ui shit
+#define inreg(x,y,x2,y2) \
+ ((mouse_x <= ( x2 ) && mouse_x >= ( x ) && \
+ mouse_y <= ( y2 ) && mouse_y >= ( y )))
+
+enum
+{
+ NO_CAP, TITLE_CAP, TB_CAP, SZ_CAP
+};
+
+static void do_titlebar( HWND hwnd, embedWindowState *state );
+static void do_titlebuttons( HWND hwnd, embedWindowState *state );
+static void do_size( HWND hwnd, embedWindowState *state );
+
+static int mouse_x, mouse_y, mouse_type, mouse_stats;
+static int which_cap = 0;
+static HWND capwnd;
+
+void embedui_handlemouseevent( HWND hwnd, int x, int y, int type, int stats, embedWindowState *state )
+{
+ if ( which_cap != NO_CAP && hwnd != capwnd ) return;
+
+ mouse_x = x;
+ mouse_y = y;
+ mouse_type = type;
+ mouse_stats = stats;
+ switch ( which_cap )
+ {
+ case TITLE_CAP: do_titlebar( hwnd, state ); return;
+ case TB_CAP: do_titlebuttons( hwnd, state ); return;
+ case SZ_CAP: do_size( hwnd, state ); return;
+ default: break;
+ }
+ do_titlebuttons( hwnd, state );
+ do_size( hwnd, state );
+ do_titlebar( hwnd, state );
+
+ if ( which_cap != NO_CAP ) capwnd = hwnd; // not sure if this is gonna work
+}
+
+static void do_titlebar( HWND hwnd, embedWindowState *state )
+{
+ if ( which_cap == TITLE_CAP || ( !which_cap && ( config_easymove || mouse_y < 14 ) ) )
+ {
+ static int clickx, clicky;
+ switch ( mouse_type )
+ {
+ case 1:
+ {
+ which_cap = TITLE_CAP;
+ clickx = mouse_x;
+ clicky = mouse_y;
+ }
+ break;
+ case -1:
+ which_cap = 0;
+ break;
+ case 0:
+ if ( which_cap == TITLE_CAP && mouse_stats & MK_LBUTTON )
+ {
+ // TODO need to convert this into an API method so
+ // we can call it externally e.g. enhancer...
+ // or something like it to allow state->r to
+ // be updated once the move has been finished
+ POINT p = { mouse_x, mouse_y };
+ ClientToScreen( hwnd, &p );
+ int w = state->r.right - state->r.left;
+ int h = state->r.bottom - state->r.top;
+
+ state->r.left = p.x - clickx;
+ state->r.top = p.y - clicky;
+ state->r.right = state->r.left + w;
+ state->r.bottom = state->r.top + h;
+
+ if ( !!config_snap + !!( mouse_stats & MK_SHIFT ) == 1 )
+ {
+ SnapWindowToAllWindows( &state->r, hwnd );
+ }
+ POINT pt = { state->r.left, state->r.top };
+ SendMessageW( hwnd, WM_USER + 0x100, 1, (LPARAM) &pt );
+ SetWindowPos( hwnd, 0, state->r.left, state->r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+ }
+ break;
+ }
+ }
+}
+
+static void do_titlebuttons( HWND hwnd, embedWindowState *state )
+{
+ int w = 0;
+ w = inreg( state->r.right - state->r.left - 10, 3, state->r.right - state->r.left - 1, 3 + 9 ) ? 1 : 0;
+
+ if ( w ) // kill button
+ {
+ if ( mouse_type == -1 && which_cap == TB_CAP )
+ {
+ which_cap = 0;
+ draw_embed_tbutton( hwnd, 0, ( state->r.right - state->r.left ) );
+ SendMessageW( hwnd, WM_USER + 101, 0, 0 );
+ }
+ else if ( mouse_stats & MK_LBUTTON )
+ {
+ which_cap = TB_CAP;
+ draw_embed_tbutton( hwnd, w ? 1 : 0, ( state->r.right - state->r.left ) );
+ }
+ }
+ else if ( which_cap == TB_CAP )
+ {
+ which_cap = 0;
+ draw_embed_tbutton( hwnd, 0, ( state->r.right - state->r.left ) );
+ }
+}
+
+typedef struct _WNDREPAINT
+{
+ HWND hwndSender;
+ RECT rwR;
+ RECT rwB;
+} WNDREPAINT;
+
+static BOOL CALLBACK EnumWndRepaintProc( HWND hwnd, LPARAM param )
+{
+ WNDREPAINT *pwp = (WNDREPAINT *) param;
+ if ( hwnd != pwp->hwndSender && IsWindowVisible( hwnd ) )
+ {
+ RECT rw;
+ GetWindowRect( hwnd, &rw );
+ if ( ( rw.left < pwp->rwR.right && rw.right > pwp->rwR.left && rw.top < pwp->rwR.bottom && rw.bottom > pwp->rwR.top ) ||
+ ( rw.top < pwp->rwB.bottom && rw.bottom > pwp->rwB.top && rw.left < pwp->rwB.right && rw.right > pwp->rwB.left ) )
+ {
+ UpdateWindow( hwnd );
+ }
+
+ }
+ return TRUE;
+}
+static void do_size( HWND hwnd, embedWindowState *state )
+{
+ if ( state->flags & EMBED_FLAGS_NORESIZE )
+ {
+ if ( which_cap == SZ_CAP ) which_cap = 0;
+ return;
+ }
+ if ( which_cap == SZ_CAP || ( !which_cap &&
+ mouse_x > ( state->r.right - state->r.left ) - 20 && mouse_y > ( state->r.bottom - state->r.top ) - 20 &&
+ ( ( ( state->r.right - state->r.left ) - mouse_x + ( state->r.bottom - state->r.top ) - mouse_y ) <= 30 ) ) )
+ {
+ static int dx, dy;
+ if ( !which_cap && mouse_type == 1 )
+ {
+ dx = ( state->r.right - state->r.left ) - mouse_x;
+ dy = ( state->r.bottom - state->r.top ) - mouse_y;
+ which_cap = SZ_CAP;
+ }
+ if ( which_cap == SZ_CAP )
+ {
+ if ( mouse_type == -1 ) which_cap = 0;
+
+ int x = mouse_x + dx;
+ int y = mouse_y + dy;
+ // if (x >= GetSystemMetrics(SM_CXSCREEN)) x = GetSystemMetrics(SM_CXSCREEN)-24;
+ // if (y >= GetSystemMetrics(SM_CYSCREEN)) y = GetSystemMetrics(SM_CYSCREEN)-28;
+ if ( !config_embedwnd_freesize )
+ {
+ x += 24;
+ x -= x % 25;
+ y += 28;
+ y -= y % 29;
+ }
+
+ if ( x < 275 ) x = 275;
+ if ( y < 20 + 38 + 29 + 29 ) y = 20 + 38 + 29 + 29;
+
+ if ( x != ( state->r.right - state->r.left ) || y != ( state->r.bottom - state->r.top ) )
+ {
+ // TODO need to ensure this isn't used when freesize is disabled
+ // isn't keeping track of the positions correctly on change
+ // as some windows only part snap e.g. ml won't dock to edges or to bottom of main window
+ RECT rw = { 0 }, r = { 0 };
+ POINT pt = { x, y };
+ SendMessageW( hwnd, WM_USER + 0x101, 1, (LPARAM) &pt );
+
+ GetWindowRect( hwnd, &rw );
+
+ // trying to get classic skins to dock to other windows on resizing
+ /*rw.left = state->r.left;
+ rw.top = state->r.top;
+ rw.right = state->r.left + x;
+ rw.bottom = state->r.top + y;
+ CopyRect(&r, &rw);
+ //if (!!config_snap + !!(mouse_stats & MK_SHIFT) == 1)
+ {
+ SnapWindowToAllWindows(&rw, hwnd);
+ }
+
+ x += (rw.right - r.right);
+ y += (rw.bottom - r.bottom);
+ SetWindowPos(hwnd, 0, 0, 0, x, y, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);*/
+
+ SetWindowPos( hwnd, 0, 0, 0, x, y, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ if ( x < ( rw.right - rw.left ) || y < ( rw.bottom - rw.top ) )
+ {
+ WNDREPAINT wrp;
+ wrp.hwndSender = hwnd;
+ SetRect( &wrp.rwR, min( rw.left + x, rw.right ), rw.top, rw.right, rw.bottom );
+ SetRect( &wrp.rwB, rw.left, min( rw.top + y, rw.bottom ), rw.right, rw.bottom );
+ EnumThreadWindows( GetCurrentThreadId(), EnumWndRepaintProc, (LPARAM) &wrp );
+ }
+ }
+ }
+ }
+}
+
+//// embed window shut
+
+static int emb_OnLButtonUp( HWND hwnd, int x, int y, UINT flags );
+static int emb_OnRButtonUp( HWND hwnd, int x, int y, UINT flags );
+static int emb_OnLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags );
+static int emb_OnMouseMove( HWND hwnd, int x, int y, UINT keyFlags );
+static int emb_OnLButtonDblClk( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags );
+static BOOL emb_OnNCActivate( HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized );
+
+static int emb_OnRButtonUp( HWND hwnd, int x, int y, UINT flags )
+{
+ //display winamp's main popup menu
+ POINT p;
+ GetCursorPos( &p );
+ int ret = DoTrackPopup( main_menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, p.x, p.y, hwnd );
+ if ( ret ) SendMessageW( hMainWindow, WM_COMMAND, ret, 0 );
+ return 1;
+}
+
+static int emb_OnLButtonUp( HWND hwnd, int x, int y, UINT flags )
+{
+ ReleaseCapture();
+ embedui_handlemouseevent( hwnd, x, y, -1, flags, (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA ) );
+ return 1;
+}
+
+static int emb_OnLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags )
+{
+ SetCapture( hwnd );
+ embedui_handlemouseevent( hwnd, x, y, 1, keyFlags, (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA ) );
+ return 1;
+}
+
+static int emb_OnMouseMove( HWND hwnd, int x, int y, UINT keyFlags )
+{
+ embedui_handlemouseevent( hwnd, x, y, 0, keyFlags, (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA ) );
+ return 1;
+}
+
+static BOOL emb_OnNCActivate( HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized )
+{
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+ if ( fActive == FALSE )
+ {
+ draw_embed_tbar( hwnd, config_hilite ? 0 : 1, ( state->r.right - state->r.left ) );
+ which_cap = NO_CAP;
+ capwnd = 0;
+ }
+ else
+ {
+ draw_embed_tbar( hwnd, 1, ( state->r.right - state->r.left ) );
+ }
+ return TRUE;
+}
+
+static int emb_OnLButtonDblClk( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags )
+{
+ return 1;
+}
+
+CRITICAL_SECTION embedcs;
+embedWindowState *embedwndlist; // linked list
+int embedwndlist_cnt;
+
+static void EmbedWindow_OnShowWindow( HWND hwnd, BOOL fShow, UINT status )
+{
+ if ( 0 != status )
+ {
+ SetPropW( hwnd, L"EmbedWnd_ShowStatus", (HANDLE) status );
+ DefWindowProcW( hwnd, WM_SHOWWINDOW, (WPARAM) fShow, (LPARAM) status );
+ RemovePropW( hwnd, L"EmbedWnd_ShowStatus" );
+ return;
+ }
+
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+
+ HWND hChild = FindWindowExW( hwnd, NULL, NULL, NULL );
+
+ INT toggleResult = 1;
+
+ if ( state && FALSE == state->reparenting )
+ {
+ INT result = Ipc_WindowToggle( (INT_PTR) hwnd, ( FALSE != fShow ) ? 1 : 0 );
+ if ( fShow ) toggleResult = result;
+ }
+
+ if ( NULL != hChild && 0 != toggleResult )
+ {
+ if ( FALSE != fShow && NULL != state )
+ {
+ SetWindowPos( hChild, NULL, 11, 20,
+ ( state->r.right - state->r.left ) - 11 - 8,
+ ( state->r.bottom - state->r.top ) - 20 - 14,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOOWNERZORDER );
+ }
+
+ EMBEDSHOW embedShow;
+ embedShow.hdr.code = EWN_SHOWWINDOW;
+ embedShow.hdr.hwndFrom = hwnd;
+ embedShow.hdr.idFrom = GetDlgCtrlID( hwnd );
+ embedShow.fShow = fShow;
+ embedShow.nStatus = (UINT) (UINT_PTR) GetPropW( hwnd, L"EmbedWnd_ShowStatus" );
+
+ SendMessageW( hChild, WM_NOTIFY, (WPARAM) embedShow.hdr.idFrom, (LPARAM) &embedShow );
+ }
+}
+
+typedef struct __EMBEDWNDPART
+{
+ INT id;
+ RECT rect;
+}EMBEDWNDPART;
+
+
+static INT EmbedWindow_HitTest( HWND hwnd, POINT pt )
+{
+ DWORD windowStyle = GetWindowLongPtrW( hwnd, GWL_STYLE );
+ if ( 0 != ( WS_DISABLED & windowStyle ) )
+ return HTERROR;
+
+ MapWindowPoints( HWND_DESKTOP, hwnd, &pt, 1 );
+
+ RECT clientRect;
+ if ( !GetClientRect( hwnd, &clientRect ) )
+ return HTERROR;
+
+ if ( 0 != ( WS_CHILD & windowStyle ) )
+ {
+ return ( PtInRect( &clientRect, pt ) ) ? HTCLIENT : HTNOWHERE;
+ }
+
+ static EMBEDWNDPART embedWindowParts[] =
+ {
+ { HTCLOSE, {-( 275 - 264 ), 3,-( 275 - 272 ), 12}},
+ { HTCAPTION, {0, 0, -1, 13}},
+ { HTBOTTOMRIGHT, {-20,-20,-1,-1}},
+ };
+
+ INT hitTest = HTCLIENT;
+
+ RECT part;
+ for ( INT i = 0; i < ARRAYSIZE( embedWindowParts ); i++ )
+ {
+ CopyRect( &part, &embedWindowParts[ i ].rect );
+ if ( part.left < 0 ) part.left += clientRect.right;
+ if ( part.right < 0 ) part.right += clientRect.right;
+ if ( part.top < 0 ) part.top += clientRect.bottom;
+ if ( part.bottom < 0 ) part.bottom += clientRect.bottom;
+
+ if ( PtInRect( &part, pt ) )
+ {
+ hitTest = embedWindowParts[ i ].id;
+ break;
+ }
+ }
+
+ if ( HTBOTTOMRIGHT == hitTest )
+ {
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+ if ( 0 != ( EMBED_FLAGS_NORESIZE & state->flags ) )
+ hitTest = HTBORDER;
+ }
+
+ return hitTest;
+}
+
+static LRESULT EmbedWindow_OnSetCursor( HWND hwnd, HWND hwndCursor, INT hitTest, UINT uMsg )
+{
+ HCURSOR hCursor = NULL;
+
+ switch ( uMsg )
+ {
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_XBUTTONDOWN:
+ DisabledWindow_OnMouseClick( hwnd );
+ break;
+ }
+
+ if ( config_usecursors && !disable_skin_cursors )
+ {
+ int index = 15 + 5; // PNormal.cur
+ POINT pt;
+ GetCursorPos( &pt );
+ hitTest = EmbedWindow_HitTest( hwnd, pt );
+ switch ( hitTest )
+ {
+ case HTCAPTION:
+ index = 15 + 2; // PTBar.cur
+ break;
+ case HTCLOSE:
+ index = 15 + 1; // PClose.cur
+ break;
+ case HTLEFT:
+ case HTRIGHT:
+ case HTTOP:
+ case HTTOPLEFT:
+ case HTTOPRIGHT:
+ case HTBOTTOM:
+ case HTBOTTOMLEFT:
+ case HTBOTTOMRIGHT:
+ index = 15 + 4;// PSize.cur
+ break;
+ }
+
+ hCursor = Skin_Cursors[ index ];
+ }
+
+ if ( NULL != hCursor )
+ {
+ SetCursor( hCursor );
+ return TRUE;
+ }
+
+ return DefWindowProcW( hwnd, WM_SETCURSOR, (WPARAM) hwndCursor, MAKELPARAM( hitTest, uMsg ) );
+}
+
+extern "C"
+{
+ LRESULT CALLBACK emb_WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+ {
+ switch ( uMsg )
+ {
+ case WM_INITMENUPOPUP:
+ return SendMessageW( hMainWindow, uMsg, wParam, lParam ); // for popup menus
+ HANDLE_MSG( hwnd, WM_QUERYNEWPALETTE, Main_OnQueryNewPalette );
+ HANDLE_MSG( hwnd, WM_PALETTECHANGED, Main_OnPaletteChanged );
+ HANDLE_MSG( hwnd, WM_LBUTTONUP, emb_OnLButtonUp );
+ HANDLE_MSG( hwnd, WM_RBUTTONUP, emb_OnRButtonUp );
+ HANDLE_MSG( hwnd, WM_LBUTTONDOWN, emb_OnLButtonDown );
+ HANDLE_MSG( hwnd, WM_MOUSEMOVE, emb_OnMouseMove );
+ HANDLE_MSG( hwnd, WM_NCACTIVATE, emb_OnNCActivate );
+ HANDLE_MSG( hwnd, WM_LBUTTONDBLCLK, emb_OnLButtonDblClk );
+ case WM_SYSCOMMAND:
+ if ( ( wParam & 0xfff0 ) == SC_SCREENSAVE || ( wParam & 0xfff0 ) == SC_MONITORPOWER )
+ return SendMessageW( hMainWindow, uMsg, wParam, lParam );
+ case WM_COMMAND:
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ if ( ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) && wParam == VK_F4 )
+ {
+ if ( uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN )
+ SendMessageW( hwnd, WM_USER + 101, 0, 0 );
+ }
+ else
+ {
+ // HWND hh=FindWindowExW(hwnd,NULL,NULL,NULL);
+ // if (hh) PostMessageW(hh,uMsg,wParam,lParam);
+ // else PostMessageW(hMainWindow,uMsg,wParam,lParam);
+ }
+ }
+ break;
+ case WM_USER + 101:
+ {
+ HWND hh = FindWindowExW( hwnd, NULL, NULL, NULL );
+ if ( hh ) PostMessageW( hh, WM_CLOSE, 0, 0 );
+ }
+ return 0;
+ case WM_USER + 102:
+ {
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+ if ( !state || !state->reparenting )
+ ShowWindow( hwnd, SW_SHOWNA );
+ }
+ break;
+ case WM_USER + 103:
+ SetFocus( hwnd );
+ break;
+ case WM_SHOWWINDOW:
+ EmbedWindow_OnShowWindow( hwnd, (BOOL) wParam, (UINT) lParam );
+
+ RefreshIconicThumbnail();
+ return 0;
+
+ case WM_DISPLAYCHANGE:
+ {
+ HWND hh = FindWindowExW( hwnd, NULL, NULL, NULL );
+ if ( hh )
+ SendMessageW( hh, uMsg, wParam, lParam );
+ }
+
+ InvalidateRect( hwnd, NULL, TRUE );
+ return 0;
+ case WM_CLOSE:
+ SendMessageW( GetParent( hwnd ), WM_CLOSE, 0, 0 );
+ return 0;
+
+ case WM_PAINT:
+ {
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+ if ( state ) draw_paint_emb( hwnd, ( state->r.right - state->r.left ), ( state->r.bottom - state->r.top ), state->flags );
+ }
+ return 0;
+
+ case WM_WINDOWPOSCHANGING:
+ {
+ /*
+ if extra_data[EMBED_STATE_EXTRA_REPARENTING] is set, we are being reparented by the freeform lib, so we should
+ just ignore this message because our visibility will not change once the freeform
+ takeover/restoration is complete
+ */
+
+ WINDOWPOS *windowPos = (WINDOWPOS *) lParam;
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+ if ( state && state->reparenting )
+ {
+ if ( 0 != ( WS_CHILD & GetWindowLongPtrW( windowPos->hwnd, GWL_STYLE ) ) )
+ windowPos->flags |= ( SWP_NOREDRAW );
+ break;
+
+ }
+ }
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ {
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+ if ( state && 0 == ( SWP_NOSIZE & ( (WINDOWPOS *) lParam )->flags ) )
+ {
+
+ HWND hh;
+ HRGN rgnChild;
+ INT cx, cy, ox;//, oy;
+ RECT rv;
+
+ ox = state->r.right - state->r.left;
+ //oy = state->r.bottom - state->r.top;
+ cx = ( (WINDOWPOS *) lParam )->cx;
+ cy = ( (WINDOWPOS *) lParam )->cy;
+
+ state->r.right = state->r.left + cx;
+ state->r.bottom = state->r.top + cy;
+
+ hh = FindWindowExW( hwnd, NULL, NULL, NULL );
+
+ if ( 0 == ( SWP_NOREDRAW & ( (WINDOWPOS *) lParam )->flags ) )
+ InvalidateRect( hwnd, NULL, FALSE );
+
+ if ( hh )
+ {
+ INT cx, cy;
+ cx = ( state->r.right - state->r.left ) - 11 - 8;
+ cy = ( state->r.bottom - state->r.top ) - 20 - 14;
+
+ SetRect( &rv, 11, 20, 11 + cx, 20 + cy );
+ ValidateRect( hwnd, &rv );
+
+ rgnChild = CreateRectRgn( 0, 0, cx, cy );
+
+ if ( IsWindowVisible( hh ) )
+ SendMessageW( hh, WM_USER + 0x201, MAKEWPARAM( 0, 0 ), (LPARAM) rgnChild );
+
+ SetWindowPos( hh, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOCOPYBITS );
+
+ if ( IsWindowVisible( hh ) )
+ SendMessageW( hh, WM_USER + 0x201, 0, (LPARAM) NULL );
+
+ }
+ else rgnChild = NULL;
+
+ if ( ox == cx )
+ {
+ SetRect( &rv, 0, 0, cx, 14 );
+ ValidateRect( hwnd, &rv );
+ }
+
+ if ( 0 == ( SWP_NOREDRAW & ( (WINDOWPOS *) lParam )->flags ) )
+ {
+ HRGN rgnWnd;
+ rgnWnd = CreateRectRgn( 0, 0, 0, 0 );
+
+ if ( GetUpdateRect( hwnd, NULL, FALSE ) )
+ GetUpdateRgn( hwnd, rgnWnd, FALSE );
+
+ if ( rgnChild )
+ {
+ OffsetRgn( rgnChild, 11, 20 );
+ CombineRgn( rgnWnd, rgnWnd, rgnChild, RGN_OR );
+ }
+
+ RedrawWindow( hwnd, NULL, rgnWnd, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN );
+ if ( rgnWnd )
+ DeleteObject( rgnWnd );
+ }
+
+ if ( rgnChild )
+ DeleteObject( rgnChild );
+ }
+ }
+ return 0;
+
+ case WM_CREATE:
+ {
+ EMBEDWND *pew = (EMBEDWND *) calloc( 1, sizeof( EMBEDWND ) );
+ SetPropW( hwnd, EMBEDWND_PROPW, pew );
+
+ SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR) ( (LPCREATESTRUCT) lParam )->lpCreateParams );
+ embedWindowState *state = (embedWindowState *) ( (LPCREATESTRUCT) lParam )->lpCreateParams;
+
+ state->me = hwnd;
+
+ int w = ( state->r.right - state->r.left );
+ int h = ( state->r.bottom - state->r.top );
+ if ( !config_embedwnd_freesize )
+ {
+ w -= w % 25;
+ h -= h % 29;
+ }
+ if ( w < 275 ) w = 275;
+ if ( h < 116 ) h = 116;
+ state->r.right = state->r.left + w;
+ state->r.bottom = state->r.top + h;
+
+ EnterCriticalSection( &embedcs );
+ GUID temp = GUID_NULL;
+ if ( state->flags & EMBED_FLAGS_GUID )
+ temp = state->guid;
+
+ memset( state->extra_data, 0, sizeof( state->extra_data ) );
+ if ( state->flags & EMBED_FLAGS_GUID )
+ state->guid = temp;
+
+ state->link = embedwndlist;
+ embedwndlist = state;
+ embedwndlist_cnt++;
+ LeaveCriticalSection( &embedcs );
+
+ SetWindowLong( hwnd, GWL_STYLE, GetWindowLongW( hwnd, GWL_STYLE ) & ~( WS_CAPTION ) );
+ SetWindowPos( hwnd, 0, state->r.left, state->r.top, state->r.right - state->r.left, state->r.bottom - state->r.top, SWP_NOACTIVATE | SWP_NOZORDER );
+ }
+ return 0;
+ case WM_DESTROY:
+ {
+ embedWindowState *state = (embedWindowState *) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
+ if ( state )
+ {
+ EnterCriticalSection( &embedcs );
+ embedWindowState *p = embedwndlist;
+ if ( p == state )
+ {
+ embedwndlist = state->link;// remove ourselves
+ embedwndlist_cnt--;
+ }
+ else
+ {
+ while ( p )
+ {
+ if ( p->link == state )
+ {
+ p->link = state->link;
+ embedwndlist_cnt--;
+ break;
+ }
+ p = p->link;
+ }
+ }
+ LeaveCriticalSection( &embedcs );
+ }
+ HWND hh = FindWindowExW( hwnd, NULL, NULL, NULL );
+ if ( hh ) DestroyWindow( hh );
+ EMBEDWND *pew = GetEmbedWnd( hwnd );
+ if ( pew )
+ {
+ RemovePropW( hwnd, EMBEDWND_PROPW );
+ free( pew );
+ }
+ }
+ return 0;
+ case WM_SETCURSOR:
+ return EmbedWindow_OnSetCursor( hwnd, (HWND) wParam, LOWORD( lParam ), HIWORD( lParam ) );
+
+ case WM_GETMINMAXINFO:
+ {
+ MINMAXINFO *p = (MINMAXINFO *) lParam;
+ if ( NULL != p )
+ {
+ p->ptMaxTrackSize.x = 16384;
+ p->ptMaxTrackSize.y = 16384;
+ }
+ }
+ return 0;
+
+ case WM_MOUSEACTIVATE:
+ if ( NULL != WASABI_API_APP )
+ WASABI_API_APP->ActiveDialog_Register( hwnd );
+ break;
+
+ case WM_CHILDACTIVATE:
+ if ( NULL != WASABI_API_APP )
+ WASABI_API_APP->ActiveDialog_Register( hwnd );
+ break;
+
+ case WM_ACTIVATE:
+ if ( WA_INACTIVE == LOWORD( wParam ) )
+ {
+ EMBEDWND *pew = GetEmbedWnd( hwnd );
+ if ( pew )
+ {
+ pew->hLastFocus = GetFocus();
+ if ( !IsChild( hwnd, pew->hLastFocus ) )
+ pew->hLastFocus = NULL;
+ }
+
+ if ( NULL != WASABI_API_APP )
+ WASABI_API_APP->ActiveDialog_Unregister( hwnd );
+ }
+ else
+ {
+ if ( WA_CLICKACTIVE == LOWORD( wParam ) )
+ {
+ EMBEDWND *pew = GetEmbedWnd( hwnd );
+ if ( pew )
+ {
+ POINT pt;
+ DWORD pts = GetMessagePos();
+ POINTSTOPOINT( pt, pts );
+ MapWindowPoints( HWND_DESKTOP, hwnd, &pt, 1 );
+
+ HWND hTarget = ChildWindowFromPointEx( hwnd, pt, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED | CWP_SKIPTRANSPARENT );
+ if ( hTarget && hTarget != hwnd )
+ pew->hLastFocus = hTarget;
+ }
+ }
+
+ if ( NULL != WASABI_API_APP )
+ WASABI_API_APP->ActiveDialog_Register( hwnd );
+
+ }
+ break;
+ case WM_SETFOCUS:
+ {
+ HWND hChild, hTab;
+ EMBEDWND *pew;
+
+ hChild = FindWindowExW( hwnd, NULL, NULL, NULL );
+ pew = GetEmbedWnd( hwnd );
+ hTab = NULL;
+ if ( pew )
+ {
+ while ( pew->hLastFocus && IsChild( hwnd, pew->hLastFocus ) )
+ {
+ if ( IsWindowEnabled( pew->hLastFocus ) && IsWindowVisible( pew->hLastFocus ) && 0 != ( WS_TABSTOP & GetWindowLongPtrW( pew->hLastFocus, GWL_STYLE ) ) )
+ {
+ hTab = pew->hLastFocus;
+ break;
+ }
+
+ pew->hLastFocus = GetParent( pew->hLastFocus );
+ }
+ }
+
+ if ( !hTab )
+ hTab = ( hChild ) ? GetNextDlgTabItem( hwnd, hChild, FALSE ) : hwnd;
+
+ if ( hTab && hTab != hwnd )
+ {
+ WCHAR szName[ 128 ] = { 0 };
+ DWORD lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT );
+ if ( GetClassNameW( hChild, szName, sizeof( szName ) / sizeof( WCHAR ) ) && CSTR_EQUAL == CompareStringW( lcid, NORM_IGNORECASE, szName, -1, L"#32770", -1 ) )
+ SendMessageW( hChild, WM_NEXTDLGCTL, (WPARAM) hTab, TRUE );
+ else
+ SetFocus( hTab );
+
+ //return 0;
+ }
+
+ }
+ break;
+ case WM_KILLFOCUS:
+ {
+ EMBEDWND *pew = GetEmbedWnd( hwnd );
+ if ( pew )
+ {
+ pew->hLastFocus = GetFocus();
+ if ( !IsChild( hwnd, pew->hLastFocus ) )
+ pew->hLastFocus = NULL;
+ }
+ }
+ break;
+ }
+
+ if ( FALSE != IsDirectMouseWheelMessage( uMsg ) )
+ {
+ if ( ( WS_CHILD & GetWindowStyle( hwnd ) ) == 0 )
+ return TRUE;
+ else
+ {
+ HWND hParent;
+ hParent = GetAncestor( hwnd, GA_PARENT );
+ if ( hParent != NULL )
+ return SendMessageW( hwnd, uMsg, wParam, lParam );
+
+ return FALSE;
+ }
+ }
+
+ return DefWindowProcW( hwnd, uMsg, wParam, lParam );
+ }
+
+ HWND embedWindow( embedWindowState *state )
+ {
+ HWND hwnd;
+ if ( !state ) return NULL;
+
+ hwnd = CreateWindowExW( WS_EX_NOPARENTNOTIFY /*| WS_EX_CONTROLPARENT | WS_EX_TOOLWINDOW*/,
+ L"Winamp Gen",
+ L"",
+ WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0, 0, 200, 200,
+ hMainWindow,
+ NULL,
+ hMainInstance,
+ state );
+ return hwnd;
+ }
+
+ BOOL SnapToScreen( RECT *outrc )
+ {
+ if ( config_keeponscreen & 1 )
+ {
+ RECT rc;
+ int w = outrc->right - outrc->left;
+ int h = outrc->bottom - outrc->top;
+
+ getViewport( &rc, NULL, 0, outrc );
+
+ if ( outrc->left < ( rc.left + config_snaplen ) && outrc->left >( rc.left - config_snaplen ) )
+ {
+ outrc->left = rc.left;
+ outrc->right = rc.left + w;
+ }
+
+ if ( outrc->top < ( rc.top + config_snaplen ) && outrc->top >( rc.top - config_snaplen ) )
+ {
+ outrc->top = rc.top;
+ outrc->bottom = rc.top + h;
+ }
+
+ if ( outrc->right > rc.right - config_snaplen && outrc->right < rc.right + config_snaplen )
+ {
+ outrc->left = rc.right - w;
+ outrc->right = rc.right;
+ }
+
+ if ( outrc->bottom > rc.bottom - config_snaplen && outrc->bottom < rc.bottom + config_snaplen )
+ {
+ outrc->top = rc.bottom - h;
+ outrc->bottom = rc.bottom;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ void SnapWindowToAllWindows( RECT *outrc, HWND hwndNoSnap )
+ {
+ RECT rc;
+ SnapToScreen( outrc );
+
+ if ( config_pe_open && hwndNoSnap != hPLWindow )
+ {
+ GetWindowRect( hPLWindow, &rc );
+ SnapWindowToWindow( outrc, rc );
+ }
+
+ if ( config_eq_open && hwndNoSnap != hEQWindow )
+ {
+ GetWindowRect( hEQWindow, &rc );
+ SnapWindowToWindow( outrc, rc );
+ }
+
+ if ( config_mw_open && hwndNoSnap != hMainWindow )
+ {
+ GetWindowRect( hMainWindow, &rc );
+ FixMainWindowRect( &rc );
+ SnapWindowToWindow( outrc, rc );
+ }
+
+ if ( config_video_open && hwndNoSnap != hVideoWindow )
+ {
+ GetWindowRect( hVideoWindow, &rc );
+ SnapWindowToWindow( outrc, rc );
+ }
+
+ EnterCriticalSection( &embedcs );
+ embedWindowState *state = embedwndlist;
+ while ( state )
+ {
+ if ( state->me != hwndNoSnap && IsWindowVisible( state->me ) )
+ SnapWindowToWindow( outrc, state->r );
+
+ state = state->link;
+ }
+
+ LeaveCriticalSection( &embedcs );
+ }
+}; \ No newline at end of file
diff --git a/Src/Winamp/eq10dsp.cpp b/Src/Winamp/eq10dsp.cpp
new file mode 100644
index 00000000..5f8f0137
--- /dev/null
+++ b/Src/Winamp/eq10dsp.cpp
@@ -0,0 +1,277 @@
+/*****************************************
+
+ EQ10 library version 1.0
+ Copyright (C)2002 4Front Technologies
+ Written by George Yohng
+
+ http://www.opensound.com
+
+ Proprietary software.
+
+ *****************************************/
+#include "main.h"
+#include "eq10dsp.h"
+
+//#include <stdio.h>
+//#include <string.h>
+#include <math.h>
+#include "WinampAttributes.h"
+
+#define DENORMAL_FIX // comment this for no denormal fixes
+
+char _eq10_copyright[]=
+"EQ10 Library version 1.0\n"
+"Copyright (C)2002 4Front Technologies http://www.opensound.com\n"
+"Copyright (C)2001-2002 by George Yohng http://www.yohng.com\n\0"
+"EQ10 ENGINE";
+
+static double eq10_freq[EQ10_NOFBANDS]={ 70, 180, 320, 600, 1000, 3000, 6000, 12000, 14000, 16000 }; // winamp style frequency table;
+static double eq10_freq_iso[EQ10_NOFBANDS]={31,62,125,250,500,1000,2000,4000,8000,16000}; // ISO frequency table
+
+#ifdef EQ10_DQ
+static double eq10_q[EQ10_NOFBANDS]=EQ10_DQ;
+#endif
+
+
+static void eq10_bsetup2(int u,double rate,eq10band_t *band,double freq,double Q)
+{
+ double angle;
+ double a0,/*a1,a2,*/b0,b1,b2,alpha;
+
+ if (rate<4000.0) rate=4000.0;
+ if (rate>384000.0) rate=384000.0;
+ if (freq<20.0) freq=20.0;
+ if (freq>=(rate*0.499)) {band->ua0=band->da0=0;return;}
+
+ angle = 2.0*3.1415926535897932384626433832795*freq/rate;
+ alpha = sin(angle)/(2.0*Q);
+
+ b0 = 1.0/(1.0+alpha);
+ a0 = b0*alpha;
+ b1 = b0*2*cos(angle);
+ b2 = b0*(alpha-1);
+
+ if (u>0)
+ {
+ band->ua0=a0;
+ band->ub1=b1;
+ band->ub2=b2;
+ }
+ else
+ {
+ band->da0=a0;
+ band->db1=b1;
+ band->db2=b2;
+ }
+}
+
+static void eq10_bsetup(double rate,eq10band_t *band,double freq,double Q)
+{
+ memset(band,0,sizeof(*band));
+ eq10_bsetup2(-1,rate,band,freq,Q*0.5);
+ eq10_bsetup2(1,rate,band,freq,Q*2.0);
+#ifdef EQ10_DETECTOR_CODE
+ /* release of detector */
+ band->detectdecay=pow(0.001,1.0/(rate*EQ10_DETECTOR_RELEASE));
+#endif
+}
+
+void eq10_setup(eq10_t *eq, int eqs, double rate)
+{
+ int t,k;
+
+ for(k=0;k<eqs;k++,eq++)
+ {
+ for(t=0;t<EQ10_NOFBANDS;t++)
+#ifndef EQ10_DQ
+ eq10_bsetup(rate,&eq->band[t],(config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?eq10_freq[t]:eq10_freq_iso[t],EQ10_Q);
+#else
+ eq10_bsetup(rate,&eq->band[t],(config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?eq10_freq[t]:eq10_freq_iso[t],eq10_q[t]);
+#endif
+
+ eq->detect=0;
+ /* release of trimmer */
+ eq->detectdecay=pow(0.001,1.0/(rate*EQ10_TRIM_RELEASE));
+ }
+}
+
+void eq10_processf(eq10_t *eq,float *buf,float *outbuf,int sz,int idx,int step)
+{
+ int t,k;
+ float *in,*out;
+ if (!eq) return;
+
+ buf+=idx;
+ outbuf+=idx;
+
+ in=buf;
+
+ for(k=0;k<EQ10_NOFBANDS;k++)
+ {
+ double a0,b1,b2;
+ double x1 = eq->band[k].x1;
+ double x2 = eq->band[k].x2;
+ double y1 = eq->band[k].y1;
+ double y2 = eq->band[k].y2;
+ double gain = eq->band[k].gain;
+
+#ifdef EQ10_DETECTOR_CODE
+ double detect = eq->band[k].detect;
+ double detectdecay = eq->band[k].detectdecay;
+#endif
+
+
+ out = outbuf;
+
+ if (gain>0.0)
+ {
+ a0 = eq->band[k].ua0*gain;
+ b1 = eq->band[k].ub1;
+ b2 = eq->band[k].ub2;
+ }
+ else
+ {
+ a0 = eq->band[k].da0*gain;
+ b1 = eq->band[k].db1;
+ b2 = eq->band[k].db2;
+ }
+
+ if (a0==0.0) continue;
+
+ for(t=0;t<sz;t++,in+=step,out+=step)
+ {
+ double y0 = (in[0]-x2)*a0 + y1*b1 + y2*b2
+
+#ifdef DENORMAL_FIX
+ + 1e-30;
+#else
+ ;
+#endif
+
+#ifdef EQ10_DETECTOR_CODE
+ if (fabs(y0)>detect) detect=fabs(y0);
+ detect*=detectdecay;
+
+#ifdef DENORMAL_FIX
+ detect+=1e-30;
+#endif
+
+#endif
+ x2=x1; x1=in[0]; y2=y1; y1=y0;
+
+ out[0] = (float)(y0 + in[0]);
+ }
+
+ in=outbuf;
+
+ eq->band[k].x1=x1;
+ eq->band[k].x2=x2;
+ eq->band[k].y1=y1;
+ eq->band[k].y2=y2;
+
+#ifdef EQ10_DETECTOR_CODE
+ eq->band[k].detect=detect;
+#endif
+ }
+
+ if (config_eq_limiter)
+ {
+ double detect=eq->detect;
+ double detectdecay=eq->detectdecay;
+ out=outbuf;
+ for(t=0;t<sz;t++,in+=step,out+=step)
+ {
+ /* *0.99 - reserve */
+ if (fabs(in[0])>detect) detect=fabs(in[0]);
+
+
+ if (detect>EQ10_TRIM_CODE)
+ out[0]=in[0]*(float)(EQ10_TRIM_CODE/detect);
+ else
+ out[0]=in[0];
+
+ detect*=detectdecay;
+#ifdef DENORMAL_FIX
+ detect+=1e-30;
+#endif
+ }
+ eq->detect=detect;
+ }
+ else if ((in==buf)&&(buf!=outbuf))
+ {
+ out=outbuf;
+ for(t=0;t<sz;t++,in+=step,out+=step) out[0]=in[0];
+ }
+
+}
+
+double eq10_db2gain(double gain_dB)
+{
+ return pow(10.0,gain_dB/20.0)-1.0;
+}
+
+double eq10_gain2db(double gain)
+{
+ return 20.0*log10(gain+1.0);
+}
+
+
+void eq10_setgain(eq10_t *eq,int eqs,int bandnr,double gain_dB)
+{
+ double realgain;
+ int k;
+
+ if (!eq)
+ return;
+
+ realgain=eq10_db2gain(gain_dB);
+
+ for(k=0;k<eqs;k++,eq++)
+ eq->band[bandnr].gain=realgain;
+}
+
+double eq10_getgain(eq10_t *eq,int bandnr)
+{
+ return eq10_gain2db(eq->band[bandnr].gain);
+}
+
+double eq10_detect(eq10_t *eq,int bandnr)
+{
+#ifdef EQ10_DETECTOR_CODE
+ return eq10_gain2db(eq->band[bandnr].detect);
+#else
+ return 0;
+#endif
+}
+
+
+#ifdef TESTCASE
+
+
+eq10_t eq;
+
+float buf1[4096] = {0};
+float buf[4096] = {0};
+
+int main()
+{
+ int t,k;
+ eq10_setup(&eq,1,44100);
+
+ for(t=0;t<4096;t++)
+ {
+ buf1[t]=warand()*(1.0/16384);
+ }
+
+ for(t=0;t<EQ10_NOFBANDS;t++) eq.band[t].gain=-0.874107;
+
+ for(t=0;t<10000;t++)
+ {
+ eq10_processf(&eq,buf1,buf,4096,0,1);
+ }
+
+ return 0;
+}
+
+#endif
+
diff --git a/Src/Winamp/eq10dsp.h b/Src/Winamp/eq10dsp.h
new file mode 100644
index 00000000..5d752a82
--- /dev/null
+++ b/Src/Winamp/eq10dsp.h
@@ -0,0 +1,175 @@
+/*****************************************
+
+ EQ10 library version 1.0
+ Copyright (C)2002 4Front Technologies
+ Written by George Yohng
+
+ http://www.opensound.com
+
+ Proprietary software.
+
+ *****************************************/
+
+
+#ifndef EQ10DSP_H_INCLUDED
+#define EQ10DSP_H_INCLUDED
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* used for volume detectors. for instance, if you want to plot
+ frequency response, you can use "detect" variable of needed
+ subband to query level of that frequency band.
+
+ release time - is the time in seconds in which detector falls back
+ to zero, if no peaks detected */
+
+
+// #define EQ10_DETECTOR_CODE /* uncomment this to */
+// #define EQ10_DETECTOR_RELEASE 1.0f /* enable band detector */
+
+
+/* Dynamic limiter, which prevents EQ from distortion. In no case you
+ can overflow EQ and cause it to clip */
+
+#define EQ10_TRIM_CODE 0.930 /* trim at -0.6dB */
+#define EQ10_TRIM_RELEASE 0.700 /* trim release, in seconds */
+
+
+#define EQ10_NOFBANDS 10 /* want more bands? not a problem */
+
+#define EQ10_Q 1.41 /* global `Q' factor */
+
+/* if you want separate Q per each band, comment global Q and uncomment
+ the following array */
+
+//#define EQ10_DQ {1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4}
+
+/* frequency table compatible to Q10 standard */
+
+
+
+
+typedef
+struct eq10band_s
+{
+ double gain; /* gain of current band. Do not use this value,
+ use eq10_setgain instead */
+
+#ifdef EQ10_DETECTOR_CODE
+ double detect; /* band detector value, do not use.
+ use eq10_detect to read detector value in dB */
+
+ double detectdecay; /* internal - do not use */
+#endif
+
+ double ua0,ub1,ub2; /* internal - do not use */
+ double da0,db1,db2; /* internal - do not use */
+ double x1,x2,y1,y2; /* internal - do not use */
+
+} eq10band_t;
+
+
+typedef
+struct eq10_s
+{
+ double rate; /* sample rate; do not modify */
+ /* use eq10_setup to change */
+
+ eq10band_t band[EQ10_NOFBANDS]; /* bands of equalizer */
+
+ double detect; /* global detector value. do not use */
+ double detectdecay; /* internal - do not use */
+
+} eq10_t;
+
+
+
+double eq10_db2gain(double gain_dB); /* converts decibels to internal gain value*/
+double eq10_gain2db(double gain); /* converts internal gain value to decibels*/
+
+
+/* prepare eq array for processing,
+
+ eq - pointer to array,
+ eqs - number of elements in array (number of audio channels)
+ rate - sample rate
+
+ WARNING! this function resets all data in eq and sets all gains to 0dB
+*/
+void eq10_setup(eq10_t *eq, int eqs, double rate);
+
+
+
+/* set band gain */
+/*
+ eq - pointer to array,
+ eqs - number of elements in array (number of audio channels)
+ bandnr - # of band (0...EQ_NOFBANDS-1)
+*/
+void eq10_setgain(eq10_t *eq,int eqs,int bandnr,double gain_dB);
+
+
+/* get current band gain */
+/* eq - pointer to element, possible to read gain on each channel
+ separately */
+double eq10_getgain(eq10_t *eq,int bandnr);
+
+
+/* get detector value */
+/* eq - pointer to element, possible to read detector value on
+ each channel separately */
+double eq10_detect(eq10_t *eq,int bandnr);
+
+
+/* process function
+
+ eq - pointer to eq structure, corresponding to wanted channel
+ buf - input buffer (interleaved multichannel)
+ outbuf - output buffer
+ sz - number of samples in input buffer
+ idx - index of processed channel (0...N-1)
+ step - total number of channels in interleaved stream (N)
+
+*/
+
+void eq10_processf(eq10_t *eq,float *buf,float *outbuf,int sz,int idx,int step);
+
+
+/*
+
+Example:
+
+ #define NCHAN 6
+
+ ...
+
+ eq10_t eq[NCHAN]; // we process 5.1 data, thus 6 channels
+ int t;
+ eq10_t *peq;
+
+ ...
+
+ eq10_setup(eq,NCHAN,44100); // initialize
+
+ ...
+
+ eq10_setgain(eq,NCHAN, 5, -10.0f ); // set -10dB for gain6 (nr's from zero)
+ ...
+
+ while (bla bla bla) // inner loop
+ {
+ for(t=0, peq=eq; t<NCHAN; t++, peq++)
+ {
+ eq10_processf(peq, input_buf, output_buf, cSamples, t, NCHAN);
+ }
+ }
+
+ ...
+
+*/
+
+#ifdef __cplusplus
+}
+#endif
+#endif //EQ10DSP_H_INCLUDED
diff --git a/Src/Winamp/feeds.cpp b/Src/Winamp/feeds.cpp
new file mode 100644
index 00000000..59824ce9
--- /dev/null
+++ b/Src/Winamp/feeds.cpp
@@ -0,0 +1,60 @@
+#include "main.h"
+#include "feeds.h"
+
+const static wchar_t VID_Info[] = L"VID_Info";
+int VideoTextFeed::hasFeed(const wchar_t *name)
+{
+ if (!_wcsicmp(name, VID_Info))
+ return 1;
+ else
+ return 0;
+}
+
+//extern "C" extern char vidoutbuf_save[1024];
+static wchar_t wideVideo[1024]=L"";
+ const wchar_t *VideoTextFeed::getFeedText(const wchar_t *name)
+ {
+ return wideVideo;
+ }
+
+ const wchar_t *VideoTextFeed::getFeedDescription(const wchar_t *name)
+ {
+ return L"Video Info Text";
+ }
+
+ void VideoTextFeed::UpdateText(const wchar_t *text, int length)
+ {
+ if (!text)
+ text=L"";
+ wideVideo[1023]=0;
+ StringCchCopyW(wideVideo, 1024, text);
+ CallViewers(VID_Info, text, length);
+ }
+
+
+// --------
+
+const static wchar_t PE_Info[] = L"PE_Info";
+int PlaylistTextFeed::hasFeed(const wchar_t *name)
+{
+ if (!_wcsicmp(name, PE_Info))
+ return 1;
+ else
+ return 0;
+}
+
+ const wchar_t *PlaylistTextFeed::getFeedText(const wchar_t *name)
+ {
+ return playlistStr;
+ }
+
+ const wchar_t *PlaylistTextFeed::getFeedDescription(const wchar_t *name)
+ {
+ return L"Playlist Info Text";
+ }
+
+ void PlaylistTextFeed::UpdateText(const wchar_t *text, int length)
+ {
+ CallViewers(PE_Info, text, length);
+ }
+
diff --git a/Src/Winamp/feeds.h b/Src/Winamp/feeds.h
new file mode 100644
index 00000000..de991117
--- /dev/null
+++ b/Src/Winamp/feeds.h
@@ -0,0 +1,24 @@
+#ifndef NULLSOFT_WINAMP_FEEDS_H
+#define NULLSOFT_WINAMP_FEEDS_H
+
+#include "FeedBase.h"
+
+class VideoTextFeed : public FeedBase
+{
+public:
+ int hasFeed(const wchar_t *name);
+ const wchar_t *getFeedText(const wchar_t *name);
+ const wchar_t *getFeedDescription(const wchar_t *name);
+ void UpdateText(const wchar_t *text, int length);
+};
+
+class PlaylistTextFeed : public FeedBase
+{
+public:
+ int hasFeed(const wchar_t *name);
+ const wchar_t *getFeedText(const wchar_t *name);
+ const wchar_t *getFeedDescription(const wchar_t *name);
+ void UpdateText(const wchar_t *text, int length);
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/fullscreen.cpp b/Src/Winamp/fullscreen.cpp
new file mode 100644
index 00000000..f092973f
--- /dev/null
+++ b/Src/Winamp/fullscreen.cpp
@@ -0,0 +1,159 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+
+
+
+HWND hFSMonitorWindow;
+extern "C"
+{
+ int g_fsapp = 0;
+ int g_restoreaot_timer_set = 0;
+ int g_dropaot_timer_set = 0;
+}
+#define APPBAR_CALLBACK WM_USER + 1010
+#define appbartag L"wa_fsmonitorclass"
+LRESULT CALLBACK fsMonitorWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+void BeginFullscreenAppMonitor()
+{
+ // this lets us receive appbar messages.
+ // we're interested in ABN_FULLSCREENAPP so we can turn AOT off temporarily
+ APPBARDATA abd;
+
+ WNDCLASSW wc;
+ if (!GetClassInfoW(hMainInstance, appbartag, &wc))
+ {
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = fsMonitorWndProc;
+ wc.hInstance = hMainInstance;
+ wc.lpszClassName = appbartag;
+ wc.style = 0;
+
+ RegisterClassW(&wc);
+ }
+
+ hFSMonitorWindow = CreateWindowExW(0, appbartag, L"", 0, 0, 0, 1, 1, NULL, NULL, hMainInstance, NULL);
+
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = hFSMonitorWindow;
+ abd.uCallbackMessage = APPBAR_CALLBACK;
+ abd.uEdge = ABE_TOP;
+ memset(&abd.rc, 0, sizeof(RECT));
+
+ SHAppBarMessage(ABM_NEW, &abd);
+}
+
+void EndFullscreenAppMonitor()
+{
+ APPBARDATA abd;
+
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = hFSMonitorWindow;
+
+ SHAppBarMessage(ABM_REMOVE, &abd);
+
+ if (IsWindow(hFSMonitorWindow))
+ DestroyWindow(hFSMonitorWindow);
+}
+
+
+void OnFullscreenApp()
+{
+ // ignore this event if the window going fullscreen is a winamp window
+ if (!is_fullscreen_video && !vis_fullscreen)
+ {
+ if (g_restoreaot_timer_set)
+ {
+ g_restoreaot_timer_set = 0;
+ KillTimer(hMainWindow, 100);
+ }
+ else
+ {
+ g_dropaot_timer_set = 1;
+ SetTimer(hMainWindow, 99, 250, NULL);
+ }
+ }
+}
+
+void OnCancelFullscreenApp()
+{
+ if (!is_fullscreen_video && !vis_fullscreen)
+ {
+ if (g_dropaot_timer_set)
+ {
+ KillTimer(hMainWindow, 99);
+ g_dropaot_timer_set = 0;
+ }
+ else
+ {
+ SetTimer(hMainWindow, 100, 250, NULL);
+ g_restoreaot_timer_set = 1;
+ }
+ }
+}
+
+LRESULT CALLBACK fsMonitorWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case APPBAR_CALLBACK:
+ switch (wParam)
+ {
+ case ABN_FULLSCREENAPP:
+ if (lParam && !g_fsapp)
+ {
+ g_fsapp = 1;
+ OnFullscreenApp();
+ }
+ else if (!lParam && g_fsapp)
+ {
+ g_fsapp = 0;
+ OnCancelFullscreenApp();
+ }
+ }
+ return 0;
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+
+
+void dropAOT()
+{
+ if (!config_dropaotfs) return ;
+ set_aot(0);
+ if (config_aot)
+ {
+ SetWindowPos(hMainWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ SetWindowPos(hMainWindow, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+}
+
+void restoreAOT()
+{
+ if (!config_dropaotfs) return ;
+ if (config_aot)
+ {
+ // normally, changing hMainWindow's ONTOP flag should be enough to change all the owned window' z-orders too,
+ // but for some reason I cannot figure out, it does not work unless WA has been clicked away and back in focus.
+ // if that hasn't been done, then reseting the flag on each window is necessary.
+ // now for the fun part: the above is true for classic skin, but in modern skins, reseting the flag
+ // on those windows actually prevents the player from coming back ONTOP! FUN!
+ if (GetParent(hPLWindow) == NULL)
+ {
+ SetWindowPos(hPLWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+ SetWindowPos(hVideoWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+ SetWindowPos(hEQWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+ }
+ SetWindowPos(hMainWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+ set_aot(0);
+}
diff --git a/Src/Winamp/gen.cpp b/Src/Winamp/gen.cpp
new file mode 100644
index 00000000..1f3a9908
--- /dev/null
+++ b/Src/Winamp/gen.cpp
@@ -0,0 +1,213 @@
+#include "main.h"
+#include "gen.h"
+#include <vector>
+#include "../nu/AutoWide.h"
+
+#include "..\WAT\wa_logger.h"
+
+
+std::vector<winampGeneralPurposePlugin*> gen_plugins;
+extern LARGE_INTEGER freq;
+int got_ml = 0;
+
+typedef struct _PLUGINORDER
+{
+ LPCWSTR name;
+ bool found;
+} PLUGINORDER;
+
+static PLUGINORDER preload[] =
+{
+ { L"gen_crasher.dll", false }, //
+ { L"gen_ff.dll", false }, //
+ { L"gen_hotkeys.dll", false }, //
+ { L"gen_tray.dll", false }, //
+ { L"gen_ml.dll", false }, //
+ { L"gen_jumpex.dll", false },
+};
+
+void LoadGenPlugin(const wchar_t* filename)
+{
+ wchar_t file[MAX_PATH] = { 0 };
+ PathCombineW(file, PLUGINDIR, filename);
+
+ if (!wa::files::file_exists(file))
+ {
+ wsprintfW( _log_message_w, L"The plugin '%s' is not found in the \"Plugins\" folder!", filename );
+
+ LOG_ERROR( _log_message_w );
+
+
+ return;
+ }
+
+
+ HMODULE hLib = LoadLibraryW(file);
+ if (hLib == NULL)
+ {
+ DWORD l_error_code = ::GetLastError();
+
+ wsprintfW( _log_message_w, L"Error when loading the plugin '%s'! Error code : %d!", filename, l_error_code );
+
+
+ LOG_ERROR( _log_message_w );
+
+
+ return;
+ }
+
+ winampGeneralPurposePlugin* (*pr)();
+ pr = (winampGeneralPurposePlugin * (__cdecl*)(void)) GetProcAddress(hLib, "winampGetGeneralPurposePlugin");
+ if ( pr == NULL )
+ {
+ wsprintfW( _log_message_w, L"No entry point found for the plugin '%s'!", filename );
+
+ LOG_ERROR( _log_message_w );
+
+
+ FreeModule(hLib);
+ return;
+ }
+
+
+ winampGeneralPurposePlugin* plugin = pr();
+ if ( plugin && (plugin->version == GPPHDR_VER || plugin->version == GPPHDR_VER_U) )
+ {
+ wsprintfW( _log_message_w, L"The plugin '%s' is correctly loaded!", filename );
+
+ LOG_DEBUG( _log_message_w );
+
+
+ if ( g_safeMode )
+ {
+ char desc[128] = { 0 };
+ lstrcpynA(desc, plugin->description, sizeof(desc));
+ if ( desc[0] && !memcmp(desc, "nullsoft(", 9) )
+ {
+ char* p = strrchr(desc, ')');
+ if ( p )
+ {
+ *p = 0;
+ if ( _wcsicmp(filename, AutoWide(desc + 9)) )
+ {
+ FreeModule(hLib);
+ return;
+ }
+ }
+ }
+ else
+ {
+ // TODO need to look into making this into a controlled
+ // list or something like that without the need for
+ // a client update so it's possible for user to fix
+ //
+ // for some plug-ins, we sadly need to leave them loaded
+ // otherwise they'll just cause Winamp to keep crashing!
+ if ( _wcsicmp(PathFindFileNameW(filename), L"gen_Wake_up_call.dll") )
+ {
+ FreeModule(hLib);
+ }
+ return;
+ }
+ }
+
+ plugin->hwndParent = hMainWindow;
+ plugin->hDllInstance = hLib;
+
+ if ( plugin->init() == GEN_INIT_SUCCESS )
+ {
+ wsprintfW( _log_message_w, L"The plugin '%s' is initialized!", filename );
+
+ LOG_DEBUG( _log_message_w );
+
+
+ if ( !_wcsicmp(filename, L"gen_ml.dll") )
+ got_ml = 1;
+
+ gen_plugins.push_back(plugin);
+ }
+ else
+ {
+ wsprintfW( _log_message_w, L"An error occurs when initializing the plugin '%s'!", filename );
+
+ LOG_ERROR( _log_message_w );
+
+
+ FreeModule( hLib );
+ }
+ }
+ else
+ {
+ wsprintfW( _log_message_w, L"Either the plugin '%s' can't be loaded, either its version is incorrect!", filename );
+
+ LOG_ERROR( _log_message_w );
+
+ FreeModule( hLib );
+ }
+}
+
+void load_genplugins()
+{
+ int i = 0, count = sizeof(preload) / sizeof(PLUGINORDER);
+ for ( ; i < count; i++ )
+ LoadGenPlugin(preload[i].name);
+
+ wchar_t dirstr[MAX_PATH] = { 0 };
+ WIN32_FIND_DATAW d = { 0 };
+ PathCombineW(dirstr, PLUGINDIR, L"GEN_*.DLL");
+
+ HANDLE h = FindFirstFileW(dirstr, &d);
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ for ( i = 0; i < count && (preload[i].found || lstrcmpiW(preload[i].name, d.cFileName)); i++ );
+
+ if ( i == count )
+ LoadGenPlugin(d.cFileName);
+ else
+ preload[i].found = true;
+ } while ( FindNextFileW(h, &d) );
+
+ FindClose(h);
+ }
+}
+
+void unload_genplugins()
+{
+ size_t x = gen_plugins.size();
+ while ( x-- )
+ {
+ if ( gen_plugins[x] )
+ {
+ wchar_t filename[MAX_PATH] = { 0 };
+
+ if ( !(config_no_visseh & 4) )
+ {
+ try
+ {
+ if ( gen_plugins[x]->quit )
+ gen_plugins[x]->quit();
+ }
+ catch ( ... )
+ {
+ }
+ }
+ else
+ {
+ if ( gen_plugins[x]->quit )
+ gen_plugins[x]->quit();
+ }
+
+ gen_plugins[x] = 0;
+ }
+ }
+ try
+ {
+ gen_plugins.clear();
+ }
+ catch ( ... )
+ {
+ }
+
+} \ No newline at end of file
diff --git a/Src/Winamp/handler.cpp b/Src/Winamp/handler.cpp
new file mode 100644
index 00000000..0e096efe
--- /dev/null
+++ b/Src/Winamp/handler.cpp
@@ -0,0 +1,90 @@
+#include "main.h"
+#include "handler.h"
+#include "../Agave/URIHandler/svc_urihandler.h"
+#include <api/service/waservicefactory.h>
+#include "api.h"
+
+int HandleFilename(const wchar_t *filename)
+{
+ size_t i=0;
+ waServiceFactory *sf = 0;
+ int handled_count=0;
+
+ while (NULL != (sf=WASABI_API_SVC->service_enumService(svc_urihandler::getServiceType(), i++)))
+ {
+ svc_urihandler *handler = (svc_urihandler *)sf->getInterface();
+ if (handler)
+ {
+ int ret = handler->ProcessFilename(filename);
+ sf->releaseInterface(handler);
+ if (ret == svc_urihandler::HANDLED)
+ handled_count++;
+ else if (ret == svc_urihandler::HANDLED_EXCLUSIVE)
+ return svc_urihandler::HANDLED;
+ }
+
+ }
+ return handled_count?svc_urihandler::HANDLED:svc_urihandler::NOT_HANDLED;
+}
+
+
+int WinampURIHandler::ProcessFilename(const wchar_t *filename)
+{
+ //MessageBoxW(NULL, filename, L"oi", MB_OK);
+ return NOT_HANDLED;
+}
+
+int WinampURIHandler::IsMine(const wchar_t *filename)
+{
+ if (CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, filename, (int)wcsnlen(filename, 9), L"winamp://", 9) == CSTR_EQUAL)
+ return HANDLED;
+ else
+ return NOT_HANDLED;
+}
+
+int WinampURIHandler::EnumProtocols(size_t n, wchar_t *protocol, size_t protocolCch, wchar_t *description, size_t descriptionCch)
+{
+ switch(n)
+ {
+ case 0:
+ StringCchCopyW(protocol, protocolCch, L"winamp");
+ StringCchCopyW(description, descriptionCch, L"Winamp Command Handler");
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int WinampURIHandler::RegisterProtocol(const wchar_t *protocol, const wchar_t *winampexe)
+{
+ return 1;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ wchar_t str[MAX_PATH+32] = {0};
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" /HANDLE \"%%1\"",winampexe);
+ wchar_t icon[MAX_PATH+32] = {0};
+ StringCchPrintfW(icon,MAX_PATH+32,L"\"%s\",%d",winampexe, config_whichicon);
+ registrar->RegisterProtocol(L"winamp", str, icon);
+ registrar->Release();
+ return 0;
+ }
+ return 1;
+}
+
+int WinampURIHandler::UnregisterProtocol(const wchar_t *protocol)
+{
+ // TODO:
+ return 1;
+}
+
+#define CBCLASS WinampURIHandler
+START_DISPATCH;
+CB(PROCESSFILENAME, ProcessFilename);
+CB(ISMINE, IsMine);
+CB(ENUMPROTOCOLS, EnumProtocols);
+CB(REGISTERPROTOCOL, RegisterProtocol);
+CB(UNREGISTERPROTOCOL, UnregisterProtocol);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/handler.h b/Src/Winamp/handler.h
new file mode 100644
index 00000000..475bc29e
--- /dev/null
+++ b/Src/Winamp/handler.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "../Agave/URIHandler/svc_urihandler.h"
+
+// {800A9A73-8891-4892-AEEB-FF970B16A39D}
+static const GUID winamp_uri_handler_guid =
+{ 0x800a9a73, 0x8891, 0x4892, { 0xae, 0xeb, 0xff, 0x97, 0xb, 0x16, 0xa3, 0x9d } };
+
+
+class WinampURIHandler : public svc_urihandler
+{
+public:
+ static const char *getServiceName() { return "Winamp URI Handler"; }
+ static GUID getServiceGuid() { return winamp_uri_handler_guid; }
+ int ProcessFilename(const wchar_t *filename);
+ int IsMine(const wchar_t *filename); // just like ProcessFilename but don't actually process
+ int EnumProtocols(size_t n, wchar_t *protocol, size_t protocolCch, wchar_t *description, size_t descriptionCch); // return 0 on success
+ int RegisterProtocol(const wchar_t *protocol, const wchar_t *winampexe);
+ int UnregisterProtocol(const wchar_t *protocol);
+
+protected:
+ RECVS_DISPATCH;
+}; \ No newline at end of file
diff --git a/Src/Winamp/install.cpp b/Src/Winamp/install.cpp
new file mode 100644
index 00000000..90b3a215
--- /dev/null
+++ b/Src/Winamp/install.cpp
@@ -0,0 +1,184 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include "api.h"
+#include "../nu/AutoChar.h"
+
+#include "./setup/svc_setup.h"
+#include <api/service/waservicefactorybase.h>
+#include "./setup/postsetup.h"
+#define APSTUDIO_READONLY_SYMBOLS
+#include "./setup/setup_resource.h"
+#include "./setup/setupfactory.h"
+
+void DoInstall(int is_install)
+{
+ //2=audiotype
+ //4=videotype
+ //8=cd
+ //16=set needreg=1
+ //32=dircontextmenus
+ //64=playlisttype
+ //128=run setup wizard
+
+ if (is_install&128)
+ {
+ HRESULT hr(S_FALSE);
+ HWND hwndStatus(NULL), hwndWA(NULL);
+
+ waServiceFactory *psf = WASABI_API_SVC->service_getServiceByGuid(UID_SVC_SETUP);
+ if (psf)
+ {
+ svc_setup *pSvc = (svc_setup*)psf->getInterface();
+ if (pSvc)
+ {
+ Setup_RegisterDefault();
+ Setup_RegisterPlugins();
+
+ hr = pSvc->Start(hMainWindow);
+
+ if (S_OK == hr)
+ {
+ pSvc->CreateStatusWnd(&hwndStatus);
+ if (hwndStatus)
+ {
+ ShowWindow(hwndStatus, SW_SHOWNORMAL);
+ UpdateWindow(hwndStatus);
+ }
+ pSvc->Save(hwndStatus);
+ pSvc->ExecJobs(hwndStatus);
+ }
+ pSvc->Release();
+ }
+ WASABI_API_SVC->service_deregister(psf);
+ }
+
+ if (S_OK == hr && hwndStatus)
+ {
+ SetDlgItemTextW(hwndStatus, IDC_LBL_STATUS, getStringW(IDS_STATUS_RUNWA, NULL, 0));
+ }
+
+ out_deinit();
+ in_deinit();
+ w5s_deinit();
+
+ if (S_OK == hr)
+ {
+ DWORD attr = GetFileAttributesW(INI_FILE);
+ if(attr & FILE_ATTRIBUTE_READONLY)
+ {
+ SetFileAttributesW(INI_FILE,(attr - FILE_ATTRIBUTE_READONLY));
+ }
+
+ char szWAParam[MAX_PATH] = {0};
+ WritePrivateProfileStringW(L"WinampReg", L"NeedReg", L"0", INI_FILE);
+ GetPrivateProfileStringA("SETUP", "WAParam", "", szWAParam, sizeof(szWAParam)/sizeof(char), INI_FILEA);
+ WritePrivateProfileStringW(L"SETUP", NULL, NULL, INI_FILE);
+ PathQuoteSpacesA(szWAParam);
+ StartWinamp((NULL != hwndStatus), &hwndWA, szWAParam);
+ }
+
+ Wasabi_Unload();
+
+ if (hwndStatus) DestroyWindow(hwndStatus);
+ if (hwndWA && IsWindow(hwndWA)) SetForegroundWindow(hwndWA);
+ RemoveRegistrar();
+ ExitProcess(0);
+ return;
+ }
+
+ config_setup_filetypes(0);
+ config_registermediaplayer(1);
+
+ if (is_install&32) config_adddircontext(0);
+ else config_removedircontext(0);
+
+ if (is_install&16) WritePrivateProfileStringW(L"WinampReg", L"NeedReg", L"1", INI_FILE);
+
+ if (is_install&8)
+ {
+ if (!config_iscdplayer()) config_regcdplayer(1, 0);
+ }
+ else
+ {
+ if (config_iscdplayer()) config_regcdplayer(0, 0);
+ }
+
+ if (is_install&(4 | 2 | 64)) // audio or video or both
+ {
+ extern void _w_sW(const char *name, const wchar_t *data);
+ wchar_t ext_list[16384] = {0};
+
+ if (is_install&(4 | 2))
+ {
+ wchar_t *ext = in_getextlistW();
+ wchar_t *a = ext;
+
+ if (ext)
+ {
+ while (a && *a)
+ {
+ wchar_t buf[1024] = {0}, buf2[64] = {0};
+ StringCchPrintfW(buf, 1024, L"test.%s", a);
+
+ buf2[0] = 0;
+ in_get_extended_fileinfoW(buf, L"type", buf2, 32);
+ int type = _wtoi(buf2);
+
+ if (lstrlenW(ext_list) + lstrlenW(buf) > 16128) break;
+ {
+ int doreg = (!type && (is_install & 2)) || (type && (is_install & 4));
+
+ if (doreg) config_register(a, doreg);
+ if (doreg)
+ {
+ if (*ext_list) StringCchCatW(ext_list, 16384, L":");
+ StringCchCatW(ext_list, 16384, a);
+ }
+ }
+
+ a += lstrlenW(a) + 1;
+ }
+ GlobalFree((HGLOBAL)ext);
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
+ }
+ }
+
+ if (is_install&64)
+ {
+ const wchar_t *p;
+ size_t i=0;
+ while (NULL != (p = playlistManager->EnumExtension(i++)))
+ {
+ int doreg = !!(is_install & 64);
+ if (doreg)
+ {
+ config_register((wchar_t*)p, doreg);
+ if (*ext_list) StringCchCatW(ext_list, 16384, L":");
+ StringCchCatW(ext_list, 8192, p);
+ }
+ p += lstrlenW(p) + 1;
+ }
+ }
+ _w_sW("config_extlist", ext_list);
+ }
+
+ //CreateEQPresets();
+
+ config_register(L"wsz", 1);
+ config_register(L"wal", 1);
+ config_register(L"wlz", 1);
+ config_write(0);
+ out_deinit();
+ in_deinit();
+ w5s_deinit();
+ Wasabi_Unload();
+ RemoveRegistrar();
+ ExitProcess(0);
+} \ No newline at end of file
diff --git a/Src/Winamp/ipc.cpp b/Src/Winamp/ipc.cpp
new file mode 100644
index 00000000..a472c31e
--- /dev/null
+++ b/Src/Winamp/ipc.cpp
@@ -0,0 +1,1633 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include "language.h"
+#define APSTUDIO_INVOKED
+#include "resource.h"
+
+#include "../Plugins/General/gen_ml/ml.h"
+#include "../Plugins/General/gen_ff/ff_ipc.h"
+#include "../nu/ns_wc.h"
+#include "menuv5.h"
+#include "vis.h"
+#include "minizip/unzip.h"
+#include "wa_dlg.h"
+#include "CurrentSongCOM.h"
+#include "SkinCOM.h"
+#include "ExternalCOM.h"
+#include "api.h"
+
+#include "tagz.h"
+#include "Browser.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoWideFn.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoCharFn.h"
+#include <api/syscb/callbacks/metacb.h>
+
+#include "./skinwindow.h"
+#include "JSAPI2_ExternalObject.h"
+#include "JSAPI2_CallbackManager.h"
+
+#include "stats.h"
+
+#include "..\WAT\WAT.h"
+
+extern std::vector<prefsDlgRec*> g_piprefsdlgs;
+int unique_loword_command = _APS_NEXT_COMMAND_VALUE;
+
+//extern "C" wa_inflate_struct inflate_struct;
+wa_inflate_struct inflate_struct =
+{
+ (int (*)(void *))inflateReset,
+ (int (*)(void *, const char *, int))inflateInit_,
+ (int (*)(void *, int))inflate,
+ (int (*)(void *))inflateEnd,
+ crc32,
+};
+
+LRESULT wa_register_ipc(WPARAM data)
+{
+ if (data)
+ {
+ typedef struct _regipcrec
+ {
+ char *name;
+ struct _regipcrec *next;
+ }
+ regipcrec;
+ int cnt = 65537;
+ static regipcrec *root = NULL;
+ regipcrec *p = root, *lp = root;
+ while (p)
+ {
+ if (!lstrcmpiA(p->name, (char*)data)) break;
+ lp = p;
+ p = p->next;
+ cnt++;
+ }
+ if (!p)
+ {
+ if (!lp) // first item
+ {
+ root = (regipcrec *)calloc(1, sizeof(regipcrec));
+ if (!root) return 0;
+ root->next = 0;
+ root->name = _strdup((char*)data);
+ }
+ else
+ {
+ lp->next = (regipcrec *)calloc(1, sizeof(regipcrec));
+ if (!lp->next) return 0;
+
+ lp->next->next = 0;
+ lp->next->name = _strdup((char*)data);
+ }
+ }
+ return cnt;
+ }
+ return 0;
+}
+
+// used to delay / filter out quick IPC_SETDIALOGBOXPARENT messages
+// to try to prevent the aero-peek buttons failing / part loading
+#define AEROPEEK 0xC0DE+4
+VOID CALLBACK DialogBoxParentChanged(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ KillTimer(hwnd, idEvent);
+ OnTaskbarButtonCreated(FALSE);
+}
+
+// IPC handler (for frontends and ourself)
+LRESULT Main_OnIPC(HWND hwnd, int which, WPARAM data)
+{
+ LRESULT returnValue = 0;
+ if (VideoIPCProcedure(which, data, &returnValue))
+ return returnValue;
+
+ static int ldata;
+ static char fn[FILENAME_SIZE];
+ static wchar_t fnW[FILENAME_SIZE];
+ switch (which)
+ {
+ case IPC_GET_API_SERVICE:
+ return reinterpret_cast<LRESULT>((api_service *)WASABI_API_SVC);
+ case IPC_USE_REGISTRY:
+ return !config_no_registry;
+ case IPC_GET_DISPATCH_OBJECT:
+ {
+ ExternalCOM *external;
+ return (SUCCEEDED(JSAPI1_GetExternal(&external))) ? reinterpret_cast<LRESULT>((IDispatch*)external) : NULL;
+ }
+ case IPC_REGISTER_LOWORD_COMMAND:
+ if (data == 0)
+ return unique_loword_command++;
+ else
+ {
+ LRESULT temp = unique_loword_command;
+ unique_loword_command+=data;
+ return temp;
+ }
+ case IPC_METADATA_CHANGED:
+ {
+ CurrentSongCOM *currentSongCOM;
+ if(SUCCEEDED(JSAPI1_GetCurrentSongCOM(&currentSongCOM)))
+ {
+ currentSongCOM->MetadataChanged((char *)data);
+ currentSongCOM->Release();
+ }
+ break;
+ }
+ case IPC_FF_ONCOLORTHEMECHANGED:
+ case IPC_SKIN_CHANGED:
+ {
+ WADlg_init(hMainWindow);
+ JSAPI1_SkinChanged();
+ break;
+ }
+ case IPC_GET_RANDFUNC:
+ switch(data)
+ {
+ case 0:
+ return reinterpret_cast<LRESULT>(warand);
+ case 1 :
+ return reinterpret_cast<LRESULT>(warandf);
+ }
+ break;
+ case IPC_USE_UXTHEME_FUNC:
+ switch(data)
+ {
+ case IPC_ISWINTHEMEPRESENT:
+ return !IsWinXPTheme();
+ case IPC_ISAEROCOMPOSITIONACTIVE:
+ return !IsAero();
+ default:
+ if(IsWindow((HWND)data))
+ DoWinXPStyle((HWND)data);
+ return 0;
+ }
+ break;
+ case IPC_USES_RECYCLEBIN:
+ return config_playlist_recyclebin;
+ case IPC_IS_AOT:
+ return config_aot;
+ case IPC_IS_EXIT_ENABLED:
+ return g_exit_disabled == 0;
+ case IPC_PUSH_DISABLE_EXIT:
+ g_exit_disabled++;
+ return g_exit_disabled;
+ case IPC_POP_DISABLE_EXIT:
+ g_exit_disabled--;
+ return g_exit_disabled;
+ case IPC_REGISTER_WINAMP_IPCMESSAGE:
+ return wa_register_ipc(data);
+ case IPC_WRITECONFIG:
+ if (data >= 0 && data <= 2) config_write(data);
+ return 0;
+ case IPC_HOOK_OKTOQUIT:
+ // do nothing, but let people hook it
+ return 1;
+ case IPC_ALLOW_PLAYTRACKING:
+ // keep a track of the old state since we can use it to see
+ // if we need to ignore showing the video window on tag edit
+ last_no_notify_play = no_notify_play;
+ no_notify_play = !data;
+ break;
+ case IPC_SETDRAWBORDERS:
+ disable_skin_borders = !data;
+ break;
+ case IPC_DISABLESKINCURSORS:
+ disable_skin_cursors = data;
+ break;
+ case IPC_GETSKINCURSORS:
+ return ((INT)data >= 0 && (INT)data < N_CURSORS && config_usecursors && !disable_skin_cursors) ? (LRESULT)Skin_Cursors[(INT)data] : NULL;
+ case IPC_STATS_LIBRARY_ITEMCNT:
+ stats.SetStat(Stats::LIBRARY_SIZE, data);
+ return 0;
+ case IPC_GETOUTPUTPLUGIN:
+ return reinterpret_cast<LRESULT>(config_outname);
+ case IPC_GETLANGUAGEPACKINSTANCE:
+ // changed to check on LOWORD(data) in 5.51+ since we can take extra params in hiword for data==5
+ if (LOWORD(data) == 1) return (language_pack_instance == hMainInstance);
+ else if (LOWORD(data) == 2) return reinterpret_cast<LRESULT>(LANGDIR);
+ else if (LOWORD(data) == 3) return reinterpret_cast<LRESULT>(lang_directory);
+ else if (LOWORD(data) == 4)
+ {
+ static wchar_t lngfilename[MAX_PATH] = {0};
+ // cache the result once done - no point in re-generating it when not needed
+ if(!lngfilename[0])
+ {
+ if(config_langpack[0])
+ {
+ // strip off the lng/wlz from the file so it matches with the config display
+ lstrcpynW(lngfilename, config_langpack, MAX_PATH);
+ wchar_t* p = extensionW(lngfilename);
+ if(p) *CharPrevW(lngfilename, p) = 0;
+ }
+ else
+ {
+ // otherwise set it to the default
+ lstrcpynW(lngfilename, L"English (US)", MAX_PATH);
+ }
+ }
+ return reinterpret_cast<LRESULT>(lngfilename);
+ }
+ else if (LOWORD(data) == 5)
+ {
+ return reinterpret_cast<LRESULT>(langManager->GetLanguageIdentifier(HIWORD(data)));
+ }
+ return reinterpret_cast<LRESULT>(language_pack_instance);
+ case IPC_SET_PE_WIDTHHEIGHT:
+ {
+ POINT *pt = (POINT *)data;
+ config_pe_width = pt->x;
+ if (config_pe_height != 14)
+ {
+ config_pe_height = pt->y;
+ if (hPLVisWindow)
+ {
+ int x, y, w, h;
+ x = config_pe_width - 150 - 75 + 2;
+ y = config_pe_height - 26;
+ w = (config_pe_width >= 350 && config_pe_height != 14 ? 72 : 0);
+ h = 16;
+ SetWindowPos(hPLVisWindow, 0, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
+ else
+ config_pe_height_ws = pt->y;
+
+ // update the position of the tooltip on window resize
+ set_pl_wnd_tooltip();
+ return 0;
+ }
+ case IPC_TRANSLATEACCELERATOR:
+ return 0;
+ case IPC_FORMAT_TITLE:
+ if (data)
+ {
+ waFormatTitle *p = (waFormatTitle*)data;
+ FormatTitle(p);
+ }
+ return 0;
+ case IPC_FORMAT_TITLE_EXTENDED:
+ if (data)
+ {
+ waFormatTitleExtended *p = (waFormatTitleExtended *)data;
+ FormatTitleExtended(p);
+ }
+ return 0;
+ case IPC_HOOK_TITLES:
+ return 0;
+ case IPC_HOOK_TITLESW:
+ if (data)
+ {
+ waHookTitleStructW *hts = (waHookTitleStructW *)data;
+ return FormatTitle(hts);
+ }
+ // hookable
+ return 0;
+ case IPC_FF_ISMAINWND:
+ return 0;
+ case IPC_ISVISRUNNING:
+ return vis_running();
+ case IPC_SETRATING:
+ {
+ LRESULT ret = sendMlIpc(ML_IPC_SETRATING, data);
+ if (!ret)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (!PlayList_getitem2W(PlayList_getPosition(), fn, NULL))
+ {
+ wchar_t buf[64] = {0};
+ if (data > 0)
+ StringCchPrintfW(buf, 64, L"%d", data);
+ else
+ buf[0] = 0;
+
+ in_set_extended_fileinfoW(fn, L"rating", buf);
+ in_write_extended_fileinfo();
+ }
+ }
+ return ret;
+ }
+ case IPC_GETRATING:
+ {
+ LRESULT ret = sendMlIpc(ML_IPC_GETRATING, 0);
+
+ // deal with no ml being present and querying the rating of a file from the tag (if possible)
+ // as well as getting a zero rating which could mean that it's not present in the library
+ if (!ret && !got_ml)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (!PlayList_getitem2W(PlayList_getPosition(), fn, NULL))
+ {
+ wchar_t buf[64] = {0};
+ in_get_extended_fileinfoW(fn, L"rating", buf, 64);
+ ret = _wtoi(buf);
+ }
+ }
+ return ret;
+ }
+ case IPC_GETVISWND:
+ return reinterpret_cast<LRESULT>(hExternalVisWindow);
+ case IPC_SETVISWND:
+ if (hExternalVisWindow != (HWND)data)
+ {
+ hExternalVisWindow = (HWND)data;
+ vis_setextwindow(hExternalVisWindow);
+ }
+ break;
+ case IPC_GETTIMEDISPLAYMODE:
+ return config_timeleftmode;
+ case IPC_ISDOUBLESIZE:
+ return config_dsize;
+ case IPC_SPAWNEQPRESETMENU:
+ if (data)
+ {
+ waSpawnMenuParms *p = (waSpawnMenuParms*)data;
+ int x = DoTrackPopup(GetSubMenu(top_menu, 1), TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, p->xpos, p->ypos, p->wnd);
+ if (x) SendMessageW(hEQWindow, WM_COMMAND, x, 0);
+ }
+ return 0;
+ case IPC_SETPLEDITCOLORS:
+ if (data)
+ {
+ waSetPlColorsStruct *p = (waSetPlColorsStruct *)data;
+ if (p->numElems && p->elems) memcpy(Skin_PLColors, p->elems, 4*min(p->numElems, sizeof(Skin_PLColors) / sizeof(Skin_PLColors[0])));
+ if (p->bm) draw_set_plbm(p->bm);
+ draw_reinit_plfont(0);
+ if (config_pe_open) InvalidateRect(hPLWindow, NULL, FALSE);
+ }
+ return 0;
+ case IPC_ADDBOOKMARK:
+ {
+ static char *narrowBMfile=0;
+ static char *narrowBMfile8=0;
+ if (!data && !narrowBMfile)
+ narrowBMfile = _strdup(AutoCharFn(BOOKMARKFILE));
+ if(data == 666 && !narrowBMfile8)
+ narrowBMfile8 = _strdup(AutoCharFn(BOOKMARKFILE8));
+ return (data == 666?reinterpret_cast<LRESULT>(narrowBMfile8):reinterpret_cast<LRESULT>(narrowBMfile));
+ }
+ case IPC_ADDBOOKMARKW:
+ return (data == 666?reinterpret_cast<LRESULT>(BOOKMARKFILE8):reinterpret_cast<LRESULT>(BOOKMARKFILE));
+ case IPC_OPENPREFSTOPAGE:
+ if (data != -1) prefs_last_page = data;
+ prefs_dialog(1);
+ return 0;
+ case IPC_ISMAINWNDVISIBLE: return config_mw_open;
+ case IPC_GETSADATAFUNC:
+ if (data == 0) return reinterpret_cast<LRESULT>(export_sa_get_deprecated);
+ else if (data == 1) return reinterpret_cast<LRESULT>(export_sa_setreq);
+ else if (data == 2) return reinterpret_cast<LRESULT>(export_sa_get);
+ return 0;
+ case IPC_GETVUDATAFUNC:
+ if (data == 0) return reinterpret_cast<LRESULT>(export_vu_get);
+ return 0;
+ case IPC_CB_MISC:
+ switch (data)
+ {
+ case IPC_CB_MISC_STATUS:
+ if (NULL != g_dialog_box_parent)
+ {
+ wchar_t title[512] = {0};
+ GetWindowTextW(hMainWindow, title, sizeof(title));
+ SetWindowTextW(g_dialog_box_parent, title);
+ }
+ break;
+ }
+ return 0;
+ case IPC_CB_GETTOOLTIP:
+ return 0;
+ case IPC_CB_GETTOOLTIPW:
+ return 0;
+ case IPC_GETWND:
+ if (data == IPC_GETWND_EQ) return reinterpret_cast<LRESULT>(hEQWindow);
+ if (data == IPC_GETWND_PE) return reinterpret_cast<LRESULT>(hPLWindow);
+ //if (data == IPC_GETWND_MB) return reinterpret_cast<LRESULT>(hMBWindow);
+ //if (data == IPC_GETWND_VIDEO) return reinterpret_cast<LRESULT>(hVideoWindow);
+ return 0;
+ case IPC_ISWNDVISIBLE:
+ if (data == IPC_GETWND_EQ) return config_eq_open;
+ if (data == IPC_GETWND_PE) return config_pe_open;
+ //if (data == IPC_GETWND_MB) return config_mb_open;
+ //if (data == IPC_GETWND_VIDEO) return config_video_open;
+ return 0;
+ case IPC_GET_EXTLIST:
+ if (data == 1) return reinterpret_cast<LRESULT>(in_getfltstr());
+ return reinterpret_cast<LRESULT>(in_getextlist());
+ case IPC_GET_EXTLISTW:
+ if (data == 1) return reinterpret_cast<LRESULT>(in_getfltstrW(FALSE));
+ return reinterpret_cast<LRESULT>(in_getextlistW());
+ case IPC_GET_PLAYLIST_EXTLISTW:
+ {
+ if (!data)
+ {
+ static wchar_t extStr[1024] = {0};
+ if (!extStr[0])
+ {
+ playlistManager->GetExtensionList(extStr, ARRAYSIZE(extStr));
+ }
+ return reinterpret_cast<LRESULT>(extStr);
+ }
+ else if (data == 1)
+ {
+ static wchar_t fltStr[1024] = {0};
+ if (!fltStr[0])
+ {
+ playlistManager->GetFilterList(fltStr, ARRAYSIZE(fltStr));
+ }
+ return reinterpret_cast<LRESULT>(fltStr);
+ }
+ else if (data == 2)
+ {
+ // TODO if a playlist writer service is implemented then update
+ // this so we're not using a hard-coded implementation
+ static wchar_t extSaveStr[1024] = {L"*.M3U;*.PLS;*.M3U8\0\0"};
+ return reinterpret_cast<LRESULT>(extSaveStr);
+ }
+ else if (data == 3)
+ {
+ // TODO if a playlist writer service is implemented then update
+ // this so we're not using a hard-coded implementation
+ static wchar_t fltSaveStr[1024] = {0};
+ if (!fltSaveStr[0])
+ {
+ wchar_t *fStr = fltSaveStr;
+ ZeroMemory(fltSaveStr, sizeof(fltSaveStr));
+ getStringW(IDS_PLAYLIST_FILTER_STRING, fltSaveStr, MAX_PATH);
+ // store the filter string with | separators so that parts can be translated as needed
+ // (\0 or more \0000 will work but it's not reliable to work with that - the pipe is a
+ // a work around from mfc apps wanting to do what we want for language support)
+ while(fStr && *fStr)
+ {
+ wchar_t* rfsStr = 0;
+ if(*fStr == L'|')
+ {
+ rfsStr = fStr;
+ }
+ fStr = CharNextW(fStr);
+ if(rfsStr)
+ {
+ *rfsStr = 0;
+ }
+ }
+ }
+ return reinterpret_cast<LRESULT>(fltSaveStr);
+ }
+ return 0;
+ }
+ case IPC_GET_GENSKINBITMAP:
+ {
+ if (!data) return reinterpret_cast<LRESULT>(draw_LBitmap(MAKEINTRESOURCE(IDB_GENEX), L"genex.bmp"));
+
+ if (data == 1)
+ {
+ return reinterpret_cast<LRESULT>(GetFontName());
+ }
+ else if (data == 2)
+ {
+ return atoi(getString(IDS_PLFONT_CHARSET, NULL, 0));
+ }
+ else if (data == 3)
+ {
+ return ScaleY(config_pe_fontsize);
+ }
+ else if (data == 4)
+ {
+ return Skin_PLColors[1];
+ }
+ return 0;
+ }
+ case IPC_REMOVE_PREFS_DLG:
+ {
+ prefsDlgRec *t = (prefsDlgRec *)data;
+
+ //g_piprefsdlgs.eraseObject(t);
+ auto it = std::find(g_piprefsdlgs.begin(), g_piprefsdlgs.end(), t);
+ if (it != g_piprefsdlgs.end())
+ {
+ g_piprefsdlgs.erase(it);
+ }
+
+ prefs_liveDlgRemove(t);
+ }
+ return 0;
+ case IPC_ADD_PREFS_DLG:
+ case IPC_ADD_PREFS_DLGW:
+ {
+ prefsDlgRec *p = (prefsDlgRec *)data;
+ p->next = (which == IPC_ADD_PREFS_DLG ? 0 : PREFS_UNICODE);
+
+ // we use the dialog proc for the preferences to determine the hinstance of the module and
+ // use that to then determine if we have gen_crasher.dll or not to move to the very bottom
+ MEMORY_BASIC_INFORMATION mbi = {0};
+ if(VirtualQuery(p->proc, &mbi, sizeof(mbi)))
+ {
+ if (GetModuleHandleW(L"gen_crasher.dll") == (HINSTANCE)mbi.AllocationBase)
+ {
+ p->where = -2;
+ }
+ }
+
+ g_piprefsdlgs.push_back(p);
+ prefs_liveDlgAdd(p);
+ }
+ return 0;
+ case IPC_UPDATE_PREFS_DLG:
+ case IPC_UPDATE_PREFS_DLGW:
+ {
+ prefsDlgRec *p = (prefsDlgRec *)data;
+ p->next = (which == IPC_UPDATE_PREFS_DLG ? 0 : PREFS_UNICODE);
+ prefs_liveDlgUpdate(p);
+ }
+ return 0;
+ case IPC_ADJUST_OPTIONSMENUPOS:
+ if (data == -1) g_mm_optionsbase_adj--;
+ if (data == 1) g_mm_optionsbase_adj++;
+ return g_mm_optionsbase_adj;
+ case IPC_ADJUST_FFWINDOWSMENUPOS:
+ if (data == -1) g_mm_ffwindowsbase_adj--;
+ if (data == 1) g_mm_ffwindowsbase_adj++;
+ return g_mm_ffwindowsbase_adj;
+ case IPC_ADJUST_FFOPTIONSMENUPOS:
+ if (data == -1) g_mm_ffoptionsbase_adj--;
+ if (data == 1) g_mm_ffoptionsbase_adj++;
+ return g_mm_ffoptionsbase_adj;
+ case IPC_GET_HMENU:
+ if (data == -1) return reinterpret_cast<LRESULT>(top_menu);
+ if (data == 0) return reinterpret_cast<LRESULT>(main_menu);
+ if (data > 0 && data < 11) return reinterpret_cast<LRESULT>(GetSubMenu(v5_top_menu, data - 1));
+ return 0;
+ case IPC_GETUNCOMPRESSINTERFACE:
+ if (data == 0x10100000)
+ return reinterpret_cast<LRESULT>(&inflate_struct);
+ return reinterpret_cast<LRESULT>(uncompress);
+ case IPC_ENABLEDISABLE_ALL_WINDOWS:
+ EnableWindow(hwnd, data != 0xdeadbeef);
+ EnableWindow(hPLWindow, data != 0xdeadbeef);
+ EnableWindow(hEQWindow, data != 0xdeadbeef);
+ //EnableWindow(hMBWindow,data!=0xdeadbeef);
+ //EnableWindow(hVideoWindow,data!=0xdeadbeef);
+ return 0;
+ case IPC_RESTARTWINAMP:
+ case IPC_RESTARTSAFEWINAMP:
+ {
+ g_restartonquit = (1 + (which == IPC_RESTARTSAFEWINAMP));
+ Main_OnClose(hwnd);
+ }
+ return 0;
+ case IPC_UPDTITLE:
+ g_need_titleupd = 1;
+ return 0;
+ case IPC_REFRESHPLCACHE:
+ {
+ const wchar_t *prefix = (const wchar_t *)data;
+ int t = PlayList_getlength();
+ int x;
+
+ if (prefix)
+ {
+ wchar_t filename[FILENAME_SIZE] = {0};
+ int prefixLen = lstrlenW(prefix);
+ for (x = 0; x < t; x ++)
+ {
+ PlayList_getitem(x, filename, 0);
+ if (!_wcsnicmp(prefix, filename, prefixLen))
+ PlayList_setcached(x, 0);
+ }
+ }
+ else
+ {
+ for (x = 0; x < t; x ++)
+ PlayList_setcached(x, 0);
+ }
+ return 0;
+ }
+ case IPC_CHANGECURRENTFILE:
+ PlayList_setcurrent(AutoWideFn((const char *)data), PlayList_gettitle(AutoWide((const char*)data), 1));
+ SendMessageW(hPLWindow, WM_USER + 1, 0, 0);
+ return 0;
+ case IPC_CHANGECURRENTFILEW:
+ PlayList_setcurrent((const wchar_t *)data, PlayList_gettitle((const wchar_t *)data, 1));
+ SendMessageW(hPLWindow, WM_USER + 1, 0, 0);
+ return 0;
+ case IPC_ISFULLSTOP:
+ return g_fullstop;
+ case IPC_GETEQDATA:
+ ldata = data;
+ if (data >= 0 && data <= 9) return eq_tab[data];
+ if (data == 10) return config_preamp;
+ if (data == 11) return config_use_eq;
+ if (data == 12) return config_autoload_eq;
+ return 0;
+ case IPC_SETEQDATA:
+ {
+ int thisone = ldata; // compatability mode, shouldnt use anymore
+ if ((data & 0xFF000000) == 0xDB000000) thisone = (data >> 16) & 0xFF;
+ data &= 0xFFFF;
+
+ if (thisone >= 0 && thisone <= 9) eq_tab[thisone] = (unsigned char)data;
+ else if (thisone == 10) config_preamp = (unsigned char)data;
+ else if (thisone == 11) config_use_eq = (unsigned char)data;
+ else if (thisone == 12) config_autoload_eq = (unsigned char)data;
+ if (thisone == 11 || thisone == 12) draw_eq_onauto(config_use_eq, config_autoload_eq, 0, 0);
+ if (thisone != 12) eq_set(config_use_eq, (char *)eq_tab, config_preamp);
+
+ if (config_eq_open)
+ {
+ if (thisone >= 0 && thisone <= 10)
+ {
+ draw_eq_slid(thisone == 10 ? 0 : thisone + 1, data, 0);
+ draw_eq_graphthingy();
+ }
+ }
+ PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_EQ, IPC_CB_MISC);
+ }
+ return 0;
+ case IPC_GETLISTPOS:
+ return PlayList_getPosition();
+ case IPC_GETNEXTLISTPOS:
+ return PlayList_getNextPosition();
+ case IPC_GETINFO:
+ if (data == 0) return g_srate;
+ if (data == 1) return g_brate;
+ if (data == 2) return g_nch;
+ if (data == 5) return g_srate_exact;
+
+ return 0;
+ case IPC_SETSKIN:
+ if (data && lstrlenA((char *)data))
+ {
+ AutoWide dataW((char *)data);
+ if (_wcsicmp(config_skin, dataW))
+ {
+ StringCchCopyW(config_skin, MAX_PATH, dataW);
+ }
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_REFRESHSKIN, 0);
+ }
+ return 0;
+ case IPC_SETSKINW:
+ if (data && lstrlenW((wchar_t *)data))
+ {
+ if (_wcsicmp(config_skin, (wchar_t *)data))
+ {
+ StringCchCopyW(config_skin, MAX_PATH, (wchar_t *)data);
+ }
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_REFRESHSKIN, 0);
+ }
+ return 0;
+ case IPC_GETSKINW:
+ {
+ if (data)
+ StringCchCopyW((wchar_t *)data, MAX_PATH, skin_directory);
+ return (LRESULT)config_skin;
+ }
+ case IPC_GETSKIN:
+ {
+ if (data)
+ WideCharToMultiByteSZ(CP_ACP, 0, skin_directory, -1, (char *)data, MAX_PATH, 0, 0);
+ static char config_skinA[MAX_PATH];
+ WideCharToMultiByteSZ(CP_ACP, 0, config_skin, -1, config_skinA, MAX_PATH,0 ,0);
+ return (LRESULT)config_skinA;
+ }
+ case IPC_EXECPLUG:
+ if (data) vis_start(hwnd, AutoWide((char *)data));
+ return 0;
+ case IPC_GETPLAYLISTFILE:
+ {
+ if (!PlayList_getitem2(data, fn, NULL)) return (LRESULT)fn;
+ return 0;
+ }
+ case IPC_GETPLAYLISTFILEW:
+ {
+ if (!PlayList_getitem2W(data, fnW, NULL)) return (LRESULT)fnW;
+ return 0;
+ }
+ case IPC_GETPLAYLISTTITLE:
+ {
+ if (!PlayList_getitem2(data, NULL, fn)) return (LRESULT)fn;
+ return 0;
+ }
+ case IPC_GETPLAYLISTTITLEW:
+ {
+ if (!PlayList_getitem2W(data, NULL, fnW)) return (LRESULT)fnW;
+ return 0;
+ }
+ case IPC_GETVERSION:
+ return APP_VERSION_NUM;
+ case IPC_GETVERSIONSTRING:
+ return (LRESULT)app_version_string;
+ case IPC_OPEN_URL:
+ {
+ char *url = (char *)data;
+ if ((url[0] == 'h' || url[0] == 'H') && url[1] == 0) // unicode!
+ {
+ myOpenURL(NULL, (wchar_t *)url);
+ }
+ else // ANSI
+ {
+ // copes with trying to open local files e.g. local help
+ // as above checking would otherwise force it always to
+ // be treated as ansi even if sent as a unicode file:///
+ if(PathFileExistsW((wchar_t *)url))
+ {
+ myOpenURL(NULL, (wchar_t *)url);
+ }
+ else
+ {
+ myOpenURL(NULL, AutoWide(url));
+ }
+ }
+
+ return 0;
+ }
+ case IPC_GETREGISTEREDVERSION:
+ if (((unsigned int) data) > 0xffff)
+ {
+ unsigned long *p = (unsigned long *)data;
+ p[2] = 0;
+ static unsigned long key[4] = { 31337, 0xf00d, 0xdead, 0xbeef}; //fucko: hide this a bit
+ tealike_crappy_code(p, key);
+ p[2] = 2;
+ }
+ else if (!data)
+ {
+ prefs_last_page = 20;
+ prefs_dialog(1);
+ }
+ return 0;
+ case IPC_IS_SAFEMODE:
+ if (g_safeMode == 2)
+ return 2;
+ return (!g_safeMode);
+ case IPC_SETPLAYLISTPOS:
+ PlayList_setposition(data);
+ InvalidateRect(hPLWindow, NULL, FALSE);
+ return 0;
+ case IPC_GETLISTLENGTH:
+ return PlayList_getlength();
+ case IPC_SETVOLUME:
+ if (data == -666) return config_volume;
+ config_volume = (unsigned char)data;
+ if (config_volume < 0) config_volume = 0;
+ if (config_volume > 255) config_volume = 255;
+ in_setvol(config_volume);
+ draw_volumebar(config_volume, 0);
+ update_volume_text(-2);
+ return 0;
+ case IPC_SETPANNING:
+ if (data == -666) return config_pan;
+ config_pan = (char)data;
+ if (config_pan < -127) config_pan = -127;
+ if (config_pan > 127) config_pan = 127;
+ draw_panbar(config_pan, 0);
+ in_setpan(config_pan);
+ update_panning_text(-2);
+ return 0;
+ case IPC_WRITEPLAYLIST:
+ if (plneedsave)
+ {
+ plneedsave = 0;
+ savem3ufn(OLD_M3U_FILE, 0, 1);
+ savem3ufn(M3U_FILE, 0, 1);
+ }
+ return PlayList_getlength() ? PlayList_getPosition() : -1;
+ case IPC_INFOBOX:
+ {
+ infoBoxParam *p = (infoBoxParam*)data;
+ int a = in_infobox(p->parent, AutoWideFn(p->filename));
+ MSG msg;
+ Sleep(100);
+ while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return
+ return a;
+ }
+ case IPC_INFOBOXW:
+ {
+ infoBoxParamW *p = (infoBoxParamW*)data;
+ int a = in_infobox(p->parent, p->filename);
+ MSG msg;
+ Sleep(100);
+ while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return
+ return a;
+ }
+ case IPC_GETMLINIFILE:
+ {
+ static char *narrowMLINIfile=0;
+ if (!narrowMLINIfile)
+ narrowMLINIfile = _strdup(AutoCharFn(ML_INI_FILE));
+ return reinterpret_cast<LRESULT>(narrowMLINIfile);
+ }
+ case IPC_GETMLINIFILEW:
+ return reinterpret_cast<LRESULT>(ML_INI_FILE);
+ case IPC_GETSHAREDDLLDIRECTORYW:
+ return reinterpret_cast<LRESULT>(SHAREDDIR);
+ case IPC_GETINIFILE:
+ {
+ static char *narrowINIfile=0;
+ if (!narrowINIfile)
+ narrowINIfile = _strdup(AutoCharFn(INI_FILE));
+ return reinterpret_cast<LRESULT>(narrowINIfile);
+ }
+ case IPC_GETINIFILEW:
+ return reinterpret_cast<LRESULT>(INI_FILE);
+ case IPC_GETINIDIRECTORY:
+ {
+ static char *narrowINIdir=0;
+ if (!narrowINIdir)
+ narrowINIdir = _strdup(AutoCharFn(CONFIGDIR));
+ return reinterpret_cast<LRESULT>(narrowINIdir);
+ }
+ case IPC_GETINIDIRECTORYW:
+ return reinterpret_cast<LRESULT>(CONFIGDIR);
+ case IPC_GETPLUGINDIRECTORY:
+ {
+ static char *narrowPlugindir=0;
+ if (!narrowPlugindir)
+ narrowPlugindir = _strdup(AutoCharFn(PLUGINDIR));
+ return reinterpret_cast<LRESULT>(narrowPlugindir);
+ }
+ case IPC_GETPLUGINDIRECTORYW:
+ return reinterpret_cast<LRESULT>(PLUGINDIR);
+ case IPC_GETM3UDIRECTORY:
+ {
+ static char *narrowM3Udir=0;
+ if (!narrowM3Udir)
+ narrowM3Udir = _strdup(AutoCharFn(M3UDIR));
+ return reinterpret_cast<LRESULT>(narrowM3Udir);
+ }
+ case IPC_GETM3UDIRECTORYW:
+ return reinterpret_cast<LRESULT>(M3UDIR);
+ case IPC_GETVISDIRECTORYW:
+ return reinterpret_cast<LRESULT>(VISDIR);
+ case IPC_GETSKINDIRECTORYW:
+ return reinterpret_cast<LRESULT>(SKINDIR);
+ case IPC_GETDSPDIRECTORYW:
+ return reinterpret_cast<LRESULT>(DSPDIR);
+ case IPC_OPENURLBOX:
+ return getNewLocation( -1, (HWND)data);
+ //FG> 5/19/03 -- added an ipc call similar to WINAMP_FILE_PLAY but with a parent HWND param, like OPENURLBOX
+ case IPC_OPENFILEBOX:
+ getNewFile(1, (HWND)data, 0);
+ plEditRefresh();
+ return 1;
+ //FG> 5/19/03 -- added an ipc call similar to WINAMP_FILE_DIR but with a parent HWND param, like OPENURLBOX
+ case IPC_OPENDIRBOX:
+ {
+ BROWSEINFOW bi = {0};
+ wchar_t name[MAX_PATH] = {0};
+ bi.hwndOwner = (HWND)data;
+ bi.pszDisplayName = name;
+ bi.lpszTitle = L"__foo";
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist)
+ {
+ wchar_t path[MAX_PATH] = {0};
+ SHGetPathFromIDListW(idlist, path);
+ Shell_Free(idlist);
+ WASABI_API_APP->path_setWorkingPath(path);
+ PlayList_delete();
+ PlayList_adddir(path, (config_rofiob&2) ? 0 : 1);
+ if (config_rofiob&1) PlayList_sort(2, 0);
+ BeginPlayback();
+ plEditRefresh();
+ }
+ return 1;
+ }
+ case IPC_SPAWNBUTTONPOPUP:
+ {
+ HMENU hmenu = NULL;
+ switch (data)
+ {
+ case 0:
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu, 3), 7);
+ UpdateAudioCDMenus(hmenu);
+ }
+ break;
+ case 1: hmenu = GetSubMenu(GetSubMenu(top_menu, 3), 2); break;
+ case 2: hmenu = GetSubMenu(GetSubMenu(top_menu, 3), 6); break;
+ case 3: hmenu = GetSubMenu(GetSubMenu(top_menu, 3), 4); break;
+ case 4: hmenu = GetSubMenu(GetSubMenu(top_menu, 3), 3); break;
+ case 5: hmenu = GetSubMenu(GetSubMenu(top_menu, 3), 5); break;
+ }
+ if (hmenu != NULL)
+ {
+ DWORD msgpos = GetMessagePos();
+ POINTS pt = MAKEPOINTS(msgpos);
+ DoTrackPopup(hmenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, hwnd);
+ }
+ return 1;
+ }
+ //FG> 5/19/03 -- added ipc call to set the parent HWND for open operations (file, dir, url) call with NULL to reset
+ case IPC_UPDATEDIALOGBOXPARENT:
+ {
+ if (g_dialog_box_parent == (HWND)data && IsWindow((HWND)data))
+ {
+ RefreshIconicThumbnail();
+ return 0;
+ }
+ // run through otherwise to force an update of things
+ }
+ case IPC_SETDIALOGBOXPARENT:
+ {
+ UnregisterThumbnailTab(g_dialog_box_parent);
+
+ g_dialog_box_parent = (HWND)data;
+
+ HWND new_parent = (IsWindow(g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow);
+ if (IsWindow(prefs_hwnd))
+ SetWindowLongPtrW(prefs_hwnd, 0xFFFFFFF8, (LONG_PTR)new_parent);
+ if (IsWindow(about_hwnd))
+ SetWindowLongPtrW(about_hwnd, 0xFFFFFFF8, (LONG_PTR)new_parent);
+ if (IsWindow(jump_hwnd))
+ SetWindowLongPtrW(jump_hwnd, 0xFFFFFFF8, (LONG_PTR)new_parent);
+ if (IsWindow(jump_hwnd2))
+ SetWindowLongPtrW(jump_hwnd2, 0xFFFFFFF8, (LONG_PTR)new_parent);
+
+ KillTimer(hMainWindow, AEROPEEK);
+ SetTimer(hMainWindow, AEROPEEK, 250, DialogBoxParentChanged);
+ return 1;
+ }
+ case IPC_GETDIALOGBOXPARENT:
+ return reinterpret_cast<LRESULT>(IsWindow(g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow);
+ case IPC_GETPREFSWND:
+ return reinterpret_cast<LRESULT>((IsWindow(prefs_hwnd) ? prefs_hwnd : NULL));
+ case IPC_INITIAL_SHOW_STATE:
+ return g_showcode;
+ case IPC_PLAYFILE:
+ {
+ static char *filename;
+ if (data > 0xffff)
+ {
+ enqueueFileWithMetaStruct *p = (enqueueFileWithMetaStruct*)data;
+ if ( p->title )
+ {
+ wa::strings::wa_string l_ext( p->filename );
+ PlayList_append_withinfo( AutoWideFn( p->filename ), AutoWide( p->title ), PathFindExtensionW( l_ext.GetW().c_str() ), p->length, 0 );
+ }
+ else
+ PlayList_appendthing(AutoWideFn(p->filename), 0, 0);
+
+ plEditRefresh();
+ }
+ else if (!data)
+ {
+ if (filename)
+ {
+ PlayList_appendthing(AutoWideFn(filename), 0, 0);
+ GlobalFree(filename);
+ filename = 0;
+ plEditRefresh();
+ }
+ }
+ else
+ {
+ static int i;
+ if (!i) filename = (char *) GlobalAlloc(GPTR, MAX_PATH);
+ filename[i++] = (char)data;
+ }
+ return 1;
+ }
+ case IPC_PLAYFILEW:
+ {
+ if ( data > 0xffff )
+ {
+ enqueueFileWithMetaStructW *p = (enqueueFileWithMetaStructW *)data;
+ if ( p->title )
+ PlayList_append_withinfo( p->filename, p->title, p->ext, p->length, 0 );
+ else
+ PlayList_appendthing( p->filename, 0, 0 );
+
+ plEditRefresh();
+ }
+ return 1;
+ }
+ case IPC_PLAYFILEW_NDE:
+ {
+ if (data > 0xffff)
+ {
+ enqueueFileWithMetaStructW *p = (enqueueFileWithMetaStructW *)data;
+ if (p->title)
+ PlayList_append_withinfo(p->filename, p->title, p->ext, p->length, 1);
+ else
+ PlayList_appendthing(p->filename, 0, 1);
+ plEditRefresh();
+ }
+ return 1;
+ }
+ case IPC_PLAYFILEW_NDE_TITLE:
+ {
+ if (data > 0xffff)
+ {
+ enqueueFileWithMetaStructW *p = (enqueueFileWithMetaStructW *)data;
+ if (p->title)
+ PlayList_append_withinfo(p->filename, p->title, p->ext, p->length, 3);
+ else
+ PlayList_appendthing(p->filename, 0, 3);
+
+ plEditRefresh();
+ }
+ return 1;
+ }
+ case IPC_CHDIR:
+ {
+ static char *filename;
+ static int i;
+ if (!data)
+ {
+ if (filename)
+ {
+ filename[i] = 0;
+ i = 0;
+ SetCurrentDirectoryA(filename);
+ GlobalFree(filename);
+ filename = 0;
+ }
+ }
+ else
+ {
+ if (!i) filename = (char *) GlobalAlloc(GPTR, MAX_PATH);
+ filename[i++] = (char)data;
+ }
+ return 1;
+ }
+ case IPC_DELETE_INT:
+ case IPC_DELETE:
+ {
+ int x = PlayList_getlength() > 0 ? 1 : 0;
+ PlayList_delete();
+ PlayList_randpos(0);
+ plEditRefresh();
+ return x;
+ }
+ case IPC_STARTPLAY_INT:
+ case IPC_STARTPLAY:
+ BeginPlayback();
+ plEditRefresh();
+ return 1;
+ case IPC_ISPLAYING:
+ return (playing ? 1 : 0) | (paused ? 2 : 0);
+ case IPC_GETOUTPUTTIME:
+ if (!data)
+ {
+ if (playing) return in_getouttime();
+ else return -1;
+ }
+ else if (data == 1)
+ {
+ if (!playing || !in_mod) return PlayList_getcurrentlength();
+ else return in_mod->GetLength() / 1000;
+ }
+ else if (data == 2)
+ {
+ if (!playing || !in_mod) return PlayList_getcurrentlength() * 1000;
+ else return in_mod->GetLength();
+ }
+ return 0;
+ case IPC_GETMODULENAME:
+ return 0;
+ case IPC_JUMPTOTIME:
+ if (playing && in_mod && in_mod->is_seekable && !PlayList_ishidden(PlayList_getPosition()))
+ {
+
+ int t = data;
+ if (t < 0) t = 0;
+ if (in_seek(t) < 0)
+ {
+ SendMessageW(hwnd, WM_WA_MPEG_EOF, 0, 0);
+ return 1;
+ }
+ else
+ {
+ ui_drawtime(in_getouttime() / 1000, 0);
+ }
+ return 0;
+ }
+ return -1;
+ case IPC_EX_ISRIGHTEXE:
+ return stat_isit;
+ case IPC_GETHTTPGETTER:
+ return (LRESULT)httpRetrieveFile;
+ case IPC_GETHTTPGETTERW:
+ return (LRESULT)httpRetrieveFileW;
+ case IPC_INETAVAILABLE:
+ return isInetAvailable();
+ case IPC_GET_SHUFFLE:
+ return !!config_shuffle;
+ case IPC_GET_MANUALPLADVANCE:
+ return !config_pladv;
+ case IPC_GET_STOP_AFTER_CURRENT:
+ return !g_stopaftercur;
+ case IPC_GET_REPEAT:
+ return !!config_repeat;
+ case IPC_SET_SHUFFLE:
+ if (!!config_shuffle != !!data)
+ {
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_SHUFFLE, 0);
+ }
+ break;
+ case IPC_SET_REPEAT:
+ if (!!config_repeat != !!data)
+ {
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_REPEAT, 0);
+ }
+ break;
+ case IPC_SET_MANUALPLADVANCE:
+ if ((!!config_pladv) != (!data))
+ {
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_MANUALPLADVANCE, 0);
+ }
+ break;
+ case IPC_IS_FULLSCREEN:
+ return vis_fullscreen;
+ case IPC_SET_VIS_FS_FLAG:
+ vis_fullscreen = !!data;
+ break;
+ case IPC_GET_EMBEDIF:
+ if (data) return reinterpret_cast<LRESULT>(embedWindow((embedWindowState*)data));
+ else return reinterpret_cast<LRESULT>(embedWindow);
+ case IPC_SKINWINDOW:
+ {
+ SKINWINDOWPARAM *swp = (SKINWINDOWPARAM*)data;
+ if (NULL == swp || swp->cbSize != sizeof(SKINWINDOWPARAM))
+ return 0;
+ return SkinWindow(swp->hwndToSkin, swp->windowGuid, swp->flagsEx, swp->callbackFF);
+ }
+ break;
+ case IPC_EMBED_ENUM:
+ EnterCriticalSection(&embedcs);
+ {
+ embedEnumStruct *parms = (embedEnumStruct*)data;
+ embedWindowState *p = embedwndlist;
+ while (p)
+ {
+ int x = parms->enumProc(p, parms);
+ if (x)
+ {
+ LeaveCriticalSection(&embedcs);
+ return x;
+ }
+ p = p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+ return 0;
+ case IPC_EMBED_ISVALID:
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *p = embedwndlist;
+ embedWindowState *parm = (embedWindowState*)data;
+ while (p)
+ {
+ if (p == parm)
+ {
+ LeaveCriticalSection(&embedcs);
+ return 1;
+ }
+ p = p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+ return 0;
+ case IPC_EMBED_ADD_LEGACY:
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *parms = (embedWindowState*)data;
+
+ if (!parms || (((unsigned int)parms) < 65536) || !IsWindow(parms->me)) return 1;
+
+ EMBEDWND *pew = (EMBEDWND*)calloc(1, sizeof(EMBEDWND));
+ SetPropW(parms->me, EMBEDWND_PROPW, pew);
+ // this makes sure that JTFE won't mess with the windows
+ SetPropA(parms->me, "WnShdProcIgnore", (HANDLE)1);
+
+ // do this just incase it's missed off by the plug-in
+ parms->flags |= EMBED_FLAGS_LEGACY_WND;
+
+ SetWindowLongPtrW(parms->me, GWLP_USERDATA, (LONG_PTR)parms);
+
+ EnterCriticalSection(&embedcs);
+ GUID temp = GUID_NULL;
+ if (parms->flags & EMBED_FLAGS_GUID)
+ temp = parms->guid;
+
+ memset(parms->extra_data, 0, sizeof(parms->extra_data));
+ if (parms->flags & EMBED_FLAGS_GUID)
+ parms->guid = temp;
+
+ parms->link = embedwndlist;
+ embedwndlist = parms;
+ embedwndlist_cnt++;
+ LeaveCriticalSection(&embedcs);
+ }
+ LeaveCriticalSection(&embedcs);
+ return 0;
+ case IPC_EMBED_REMOVE_LEGACY:
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *parm = (embedWindowState*)data;
+ if (parm)
+ {
+ EnterCriticalSection(&embedcs);
+ embedWindowState *p=embedwndlist;
+ if (p == parm)
+ {
+ embedwndlist = parm->link;// remove ourselves
+ embedwndlist_cnt--;
+ }
+ else
+ {
+ while (p)
+ {
+ if (p->link == parm)
+ {
+ p->link = parm->link;
+ embedwndlist_cnt--;
+ break;
+ }
+ p=p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+
+ EMBEDWND *pew = GetEmbedWnd(parm->me);
+ if (pew)
+ {
+ RemovePropW(parm->me, EMBEDWND_PROPW);
+ free(pew);
+ }
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+ return 0;
+ case IPC_EMBED_UPDATE_LEGACY_POS:
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *p = embedwndlist;
+ embedWindowState *parm = (embedWindowState*)data;
+ while (p)
+ {
+ if (p == parm)
+ {
+ CopyRect(&p->r, &parm->r);
+ return 1;
+ }
+ p = p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+ return 0;
+ case IPC_GET_EMBED_SNAPFUNC:
+ if (data) return reinterpret_cast<LRESULT>(SnapWindowToAllWindows);
+ else return reinterpret_cast<LRESULT>(SnapToScreen);
+ case IPC_GET_EXTENDED_FILE_INFO_HOOKABLE:
+ {
+ }
+ // fall through
+ case IPC_GET_EXTENDED_FILE_INFO:
+ {
+ extendedFileInfoStruct *efis = (extendedFileInfoStruct *)data;
+ if (efis && efis->filename)
+ return in_get_extended_fileinfo(efis->filename, efis->metadata, efis->ret, efis->retlen);
+ else
+ return 0;
+ }
+ case IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE:
+ {
+ extendedFileInfoStructW *efis = (extendedFileInfoStructW *)data;
+ if (JSAPI2::callbackManager.OverrideMetadata(efis->filename, efis->metadata, efis->ret, efis->retlen))
+ return 1;
+ }
+ // fall through
+ case IPC_GET_EXTENDED_FILE_INFOW:
+ {
+ extendedFileInfoStructW *efis = (extendedFileInfoStructW *)data;
+ if (efis && efis->filename)
+ return in_get_extended_fileinfoW(efis->filename, efis->metadata, efis->ret, efis->retlen);
+ else
+ return 0;
+ }
+ case IPC_GET_BASIC_FILE_INFO:
+ {
+ basicFileInfoStruct *bfis = (basicFileInfoStruct*)data;
+ if (bfis->quickCheck == 2 && config_riol == 1) bfis->quickCheck = 0;
+ AutoWideFn wfn(bfis->filename);
+ if (PathIsURLW(wfn))
+ {
+ const wchar_t *cachedTitle = PlayList_GetCachedTitle(wfn);
+ if (cachedTitle && cachedTitle[0])
+ {
+ lstrcpynA(bfis->title, AutoChar(cachedTitle), bfis->titlelen);
+ bfis->length = PlayList_get_lastlen();
+ return 0;
+ }
+ }
+ lstrcpynA(bfis->title, AutoChar(remove_urlcodesW(PlayList_gettitle(wfn, !bfis->quickCheck))), bfis->titlelen);
+ bfis->length = PlayList_get_lastlen();
+ return 0;
+ }
+ case IPC_GET_BASIC_FILE_INFOW:
+ {
+ basicFileInfoStructW *bfis = (basicFileInfoStructW *)data;
+ if ( bfis->quickCheck == 2 && config_riol == 1 ) bfis->quickCheck = 0;
+ if ( bfis->filename && *bfis->filename && PathIsURLW( bfis->filename ) )
+ {
+ const wchar_t *cachedTitle = PlayList_GetCachedTitle( bfis->filename );
+ if ( cachedTitle && cachedTitle[ 0 ] )
+ {
+ lstrcpynW( bfis->title, cachedTitle, bfis->titlelen );
+ bfis->length = PlayList_get_lastlen();
+ return 0;
+ }
+ }
+
+ lstrcpynW( bfis->title, remove_urlcodesW( PlayList_gettitle( bfis->filename, !bfis->quickCheck ) ), bfis->titlelen );
+ bfis->length = PlayList_get_lastlen();
+
+ return 0;
+ }
+ case IPC_SET_EXTENDED_FILE_INFO:
+ {
+ extendedFileInfoStruct *efis = (extendedFileInfoStruct *)data;
+ return in_set_extended_fileinfo(efis->filename, efis->metadata, efis->ret);
+ }
+ case IPC_SET_EXTENDED_FILE_INFOW:
+ {
+ extendedFileInfoStructW *efis = (extendedFileInfoStructW *)data;
+ return in_set_extended_fileinfoW(efis->filename, efis->metadata, efis->ret);
+ }
+ case IPC_WRITE_EXTENDED_FILE_INFO:
+ return in_write_extended_fileinfo();
+ case IPC_CONVERTFILE:
+ return convert_file((convertFileStruct *)data);
+ case IPC_CONVERTFILEW:
+ return convert_fileW((convertFileStructW *)data);
+ case IPC_CONVERT_TEST:
+ return convert_file_test((convertFileStructW *)data);
+ case IPC_CONVERTFILE_END:
+ convert_end((convertFileStruct *)data);
+ break;
+ case IPC_CONVERTFILEW_END:
+ convert_endW((convertFileStructW *)data);
+ break;
+ case IPC_CONVERT_CONFIG:
+ return reinterpret_cast<LRESULT>(convert_config((convertConfigStruct *)data));
+ case IPC_CONVERT_CONFIG_END:
+ convert_config_end((convertConfigStruct *)data);
+ break;
+ case IPC_CONVERT_CONFIG_ENUMFMTS:
+ convert_enumfmts((converterEnumFmtStruct *)data);
+ break;
+ case IPC_CONVERT_SET_PRIORITY:
+ convert_setPriority((convertSetPriority *)data);
+ break;
+ case IPC_CONVERT_SET_PRIORITYW:
+ convert_setPriorityW((convertSetPriorityW *)data);
+ break;
+ case IPC_CONVERT_CONFIG_SET_ITEM:
+ return convert_setConfigItem((convertConfigItem*)data);
+ case IPC_CONVERT_CONFIG_GET_ITEM:
+ return convert_getConfigItem((convertConfigItem*)data);
+ case IPC_PLCMD:
+ PE_Cmd((windowCommand*)data);
+ break;
+ case IPC_GETDROPTARGET:
+ return reinterpret_cast<LRESULT>(Ole_getDropTarget());
+ #ifdef BURN_SUPPORT
+ #if !defined(_WIN64)
+ case IPC_BURN_CD:
+ return burn_start((burnCDStruct *)data);
+ #endif
+ #endif
+ case IPC_GET_NEXT_PLITEM:
+ return -1;
+ case IPC_GET_PREVIOUS_PLITEM:
+ return -1;
+ case IPC_IS_WNDSHADE:
+ if (data == -1) return config_windowshade;
+ if (data == IPC_GETWND_PE) return config_pe_height == 14;
+ if (data == IPC_GETWND_EQ) return config_eq_ws;
+ return 0;
+ case IPC_SPAWNFILEMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_File_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNPLAYMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_Play_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNOPTIONSMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_Options_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNWINDOWSMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_Windows_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNHELPMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_Help_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNPEFILEMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_PE_File_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNPEPLAYLISTMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_PE_Playlist_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNPESORTMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_PE_Sort_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNPEHELPMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_PE_Help_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNMLFILEMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_ML_File_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNMLVIEWMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_ML_View_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNMLHELPMENU:
+ {
+ waSpawnMenuParms2 *p = (waSpawnMenuParms2*)data;
+ return V5_ML_Help_Menu(p->wnd, p->xpos, p->ypos, p->width, p->height);
+ }
+ case IPC_SPAWNPELISTOFPLAYLISTS:
+ {
+ waSpawnMenuParms *p = (waSpawnMenuParms*)data;
+ return V5_PE_ListOfPlaylists_Menu(p->xpos, p->ypos);
+ }
+ case IPC_GET_UNIQUE_DISPATCH_ID:
+ return JSAPI1_GenerateUniqueDispatchId();
+ case IPC_ADD_DISPATCH_OBJECT:
+ {
+ DispatchInfo *info = (DispatchInfo*)data;
+ if (NULL != info)
+ {
+ ExternalCOM *external;
+ if (SUCCEEDED(JSAPI1_GetExternal(&external)))
+ {
+ info->id = external->AddDispatch(info->name, info->dispatch);
+ external->Release();
+ }
+ else
+ {
+ info->id = 0;
+ }
+ }
+ return 0;
+ }
+ case IPC_REMOVE_DISPATCH_OBJECT:
+ {
+ ExternalCOM *external;
+ if (SUCCEEDED(JSAPI1_GetExternal(&external)))
+ {
+ external->RemoveDispatch((DWORD)data);
+ external->Release();
+ }
+ }
+ return 0;
+ case IPC_GET_PROXY_STRING:
+ return reinterpret_cast<LRESULT>(config_proxy);
+ case IPC_PLAYLIST_GET_NEXT_SELECTED:
+ return PlayList_GetNextSelected(data);
+ case IPC_PLAYLIST_GET_SELECTED_COUNT:
+ return PlayList_GetSelectedCount();
+ case IPC_FILE_TAG_MAY_HAVE_UPDATED:
+ {
+ extern In_Module *g_in_infobox;
+ if (!g_in_infobox)
+ PlayList_UpdateTitle(AutoWideFn((const char *)data));
+ return 0;
+ }
+ case IPC_FILE_TAG_MAY_UPDATEW:
+ {
+ // issue sys callback
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::META, MetadataCallback::FILE_MAY_UPDATE, (intptr_t)data);
+ return 0;
+ }
+ case IPC_FILE_TAG_MAY_HAVE_UPDATEDW:
+ {
+ extern In_Module *g_in_infobox;
+ if (!g_in_infobox)
+ PlayList_UpdateTitle((const wchar_t *)data);
+
+ // issue sys callback
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::META, MetadataCallback::FILE_UPDATED, (intptr_t)data);
+ return 0;
+ }
+ case IPC_SET_JTF_COMPARATOR:
+ SetJumpComparator((void *)data);
+ return 0;
+ case IPC_SET_JTF_COMPARATOR_W:
+ SetJumpComparatorW((void *)data);
+ return 0;
+ case IPC_SET_JTF_DRAWTEXT:
+ jtf_drawtext=reinterpret_cast<int (WINAPI *)(HDC, LPCWSTR, int, LPRECT, UINT)>(data);
+ return 0;
+ case IPC_SET_JTF_LOAD_MODE:
+ if (data == -666) return config_jtf_check;
+ config_jtf_check = data;
+ _w_i("jtf_check", config_jtf_check);
+ return 0;
+ case IPC_UPDATE_URL:
+ {
+ ReplyMessage(0);
+ char *url=(char *)data;
+ UpdateWindow_Show(url);
+ free(url);
+ return 0;
+ }
+ case IPC_GETPLAYITEM_START:
+ return PlayList_GetItem_Start(PlayList_getPosition());
+ case IPC_GETPLAYITEM_END:
+ return PlayList_GetItem_End(PlayList_getPosition());
+ case IPC_GET_PLAYING_FILENAME:
+ return reinterpret_cast<LRESULT>(FileName);
+ case IPC_GET_PLAYING_TITLE:
+ return reinterpret_cast<LRESULT>(FileTitle);
+ case IPC_COPY_EXTENDED_FILE_INFO:
+ {
+ copyFileInfoStruct *copy = (copyFileInfoStruct *)data;
+ CopyExtendedFileInfo(AutoWideFn(copy->source), AutoWideFn(copy->dest));
+ return 0;
+ }
+ case IPC_COPY_EXTENDED_FILE_INFOW:
+ {
+ copyFileInfoStructW *copy = (copyFileInfoStructW *)data;
+ CopyExtendedFileInfo(copy->source, copy->dest);
+ return 0;
+ }
+ case IPC_CANPLAY:
+ {
+ int a=0;
+ return (LRESULT)in_setmod_noplay((const wchar_t *)data, &a);
+ }
+ // disabled 30 May 2012 as per email from Tejas w.r.t. to Rovi deal ending
+ // if called it will now act like a failure and return 1 by default handling
+ /*case IPC_FETCH_ALBUMART:
+ {
+ extern int RetrieveAlbumArt(artFetchData * data);
+ return RetrieveAlbumArt((artFetchData *)data);
+ }*/
+ case IPC_JSAPI2_GET_DISPATCH_OBJECT:
+ return (LRESULT)new JSAPI2::ExternalObject((const wchar_t *)data);
+ case IPC_HANDLE_URI:
+ {
+ const wchar_t *cmd = (const wchar_t *)data;
+ if (cmd)
+ {
+ if (cmd[0] == '\"')
+ {
+ wchar_t temp[1024] = {0};
+ GetParameter(cmd, temp, 1024);
+ HandleFilename(temp);
+ }
+ else
+ HandleFilename(cmd);
+ return 0;
+ }
+ }
+ case IPC_GET_D3DX9:
+ {
+ HMODULE d3dx_lib = FindD3DX9();
+ return (LRESULT)d3dx_lib;
+ }
+ case IPC_GET_FILEREGISTRAR_OBJECT:
+ {
+ IFileTypeRegistrar *registrar = 0;
+ if (GetRegistrar(&registrar, !data) == 0 && registrar)
+ return (LRESULT)registrar;
+ return 0;
+ }
+ } // switch(which)
+ return 1;
+}
+
+// Main_OnIPC() \ No newline at end of file
diff --git a/Src/Winamp/ipc_pe.h b/Src/Winamp/ipc_pe.h
new file mode 100644
index 00000000..3f0076aa
--- /dev/null
+++ b/Src/Winamp/ipc_pe.h
@@ -0,0 +1,171 @@
+#ifndef __IPC_PE_H
+#define __IPC_PE_H
+
+/*
+** To use these messages you will need a valid window handle for the playlist window
+** and the format to use them is:
+**
+** SendMessageW(playlist_wnd,WM_WA_IPC,IPC_*,(parameter));
+**
+** Note:
+** This IS the OPPOSITE way to how the messages to the main winamp window are sent
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*);
+*/
+
+/*
+** Playlist Window:
+**
+** To get the playlist window there are two ways depending on the version you're using
+**
+** HWND playlist_wnd = 0;
+** int wa_version = SendMessageW(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);
+**
+** if(wa_version >= 0x2900)
+** {
+** // use the built in api to get the handle
+** playlist_wnd = (HWND)SendMessageW(plugin.hwndParent,WM_WA_IPC,IPC_GETWND_PE,IPC_GETWND);
+** }
+**
+** // if it failed then use the old way :o)
+** if(!IsWindow(playlist_wnd))
+** {
+** playlist_wnd = FindWindow("Winamp PE",0);
+** }
+*/
+
+
+/*
+** Structures used by some of the apis referenced.
+*/
+typedef struct {
+ char file[MAX_PATH];
+ int index;
+} fileinfo;
+
+typedef struct {
+ wchar_t file[MAX_PATH];
+ int index;
+} fileinfoW;
+
+typedef struct {
+ HWND callback;
+ int index;
+} callbackinfo;
+
+typedef struct {
+ int fileindex;
+ char filetitle[256];
+ char filelength[16];
+} fileinfo2;
+
+typedef struct {
+ int fileindex;
+ wchar_t filetitle[256];
+ wchar_t filelength[16];
+} fileinfo2W;
+
+
+#define IPC_PE_GETCURINDEX 100 // returns current idx (typically the playing item)
+#define IPC_PE_GETINDEXTOTAL 101 // returns the number of items in the playlist
+
+#define IPC_PE_GETINDEXINFO 102 // (copydata) lpData is of type callbackinfo, callback is called with copydata/fileinfo structure and msg IPC_PE_GETINDEXINFORESULT
+#define IPC_PE_GETINDEXINFORESULT 103 // callback message for IPC_PE_GETINDEXINFO
+
+#define IPC_PE_DELETEINDEX 104 // lParam = index
+
+#define IPC_PE_SWAPINDEX 105 // (lParam & 0xFFFF0000) >> 16 = from, (lParam & 0xFFFF) = to
+/*
+** SendMessageW(playlist_wnd,WM_WA_IPC,IPC_PE_SWAPINDEX,MAKELPARAM(from,to));
+*/
+
+#define IPC_PE_INSERTFILENAME 106 // (copydata) lpData is of type fileinfo
+#define IPC_PE_INSERTFILENAMEW 114 // (copydata) lpData is of type fileinfoW (5.3+)
+/* COPYDATASTRUCT cds = {0};
+** fileinfo f = {0};
+**
+** lstrcpyn(f.file, file,MAX_PATH); // path to the file
+** f.index = position; // insert file position
+**
+** cds.dwData = IPC_PE_INSERTFILENAME;
+** cds.lpData = (void*)&f;
+** cds.cbData = sizeof(fileinfo);
+** SendMessageW(playlist_wnd,WM_COPYDATA,0,(LPARAM)&cds);
+*/
+
+
+#define IPC_PE_GETDIRTY 107 // returns 1 if the playlist changed since the last IPC_PE_SETCLEAN
+#define IPC_PE_SETCLEAN 108 // resets the dirty flag until next modification
+
+#define IPC_PE_GETIDXFROMPOINT 109 // pass a point param and will return a playlist index (if in the area)
+/*
+** POINT pt;
+** RECT rc;
+**
+** // Get the current position of the mouse and the current client area of the playlist window
+** // and then mapping the mouse position to the client area
+** GetCursorPos(&pt);
+**
+** // Get the client area of the playlist window and then map the mouse position to it
+** GetClientRect(playlist_wnd,&rc);
+** ScreenToClient(playlist_wnd,&pt);
+**
+** // this corrects so the selection works correctly on the selection boundary
+** // appears to happen on the older 2.x series as well
+** pt.y -= 2;
+**
+** // corrections for the playlist window area so that work is only done for valid positions
+** // and nicely enough it works for both classic and modern skin modes
+** rc.top += 18;
+** rc.left += 12;
+** rc.right -= 19;
+** rc.bottom -= 40;
+**
+** // is the click in
+** if(PtInRect(&rc,pt))
+** {
+** // get the item index at the given point
+** // if this is out of range then it will return 0 (not very helpful really)
+** int idx = SendMessageW(playlist_wnd,WM_WA_IPC,IPC_PE_GETIDXFROMPOINT,(LPARAM)&pt);
+**
+** // makes sure that the item isn't past the last playlist item
+** if(idx < SendMessageW(playlist_wnd,WM_WA_IPC,IPC_PE_GETINDEXTOTAL,0))
+** {
+** // ... do stuff in here (this example will start playing the selected track)
+** SendMessageW(plugin.hwndParent,WM_WA_IPC,idx,IPC_SETPLAYLISTPOS);
+** SendMessageW(plugin.hwndParent,WM_COMMAND,MAKEWPARAM(WINAMP_BUTTON2,0),0);
+** }
+** }
+*/
+
+#define IPC_PE_SAVEEND 110 // pass index to save from
+#define IPC_PE_RESTOREEND 111 // no parm
+
+#define IPC_PE_GETNEXTSELECTED 112 // same as IPC_PLAYLIST_GET_NEXT_SELECTED for the main window
+#define IPC_PE_GETSELECTEDCOUNT 113
+
+#define IPC_PE_GETINDEXINFO_TITLE 115 // like IPC_PE_GETINDEXINFO, but writes the title to char file[MAX_PATH] instead of filename
+#define IPC_PE_GETINDEXINFORESULT_TITLE 116 // callback message for IPC_PE_GETINDEXINFO
+
+
+// the following messages are in_process ONLY
+
+#define IPC_PE_GETINDEXTITLE 200 // lParam = pointer to fileinfo2 struct
+#define IPC_PE_GETINDEXTITLEW 201 // lParam = pointer to fileinfo2W struct
+/*
+** fileinfo2 file;
+** int ret = 0;
+**
+** file.fileindex = position; // this is zero based!
+** ret = SendMessageW(playlist_wnd,WM_WA_IPC,IPC_PE_GETINDEXTITLE,(LPARAM)&file);
+**
+** // if it returns 0 then track information was received
+** if(!ret)
+** {
+** // ... do stuff
+** }
+*/
+
+#define IPC_PE_GETINDEXINFO_INPROC 202 // lParam = pointer to fileinfo struct
+#define IPC_PE_GETINDEXINFOW_INPROC 203 // lParam = pointer to fileinfoW struct
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/jnetcom.cpp b/Src/Winamp/jnetcom.cpp
new file mode 100644
index 00000000..8a2f429b
--- /dev/null
+++ b/Src/Winamp/jnetcom.cpp
@@ -0,0 +1,528 @@
+#include "jnetcom.h"
+#include "../nu/AutoChar.h"
+/* --- Jnetlib COM object --- */
+extern "C" extern HANDLE DuplicateCurrentThread();
+
+JNetCOM::JNetCOM( IDispatch *_dispatch )
+{
+ refCount = 1;
+ token = 0;
+ dispatch = _dispatch;
+ threadId = GetCurrentThreadId();
+ threadHandle = DuplicateCurrentThread();
+ retained = false;
+
+ if ( NULL != dispatch )
+ dispatch->AddRef();
+}
+
+JNetCOM::~JNetCOM()
+{
+ if ( retained )
+ {
+ if ( NULL != WAC_API_DOWNLOADMANAGER )
+ WAC_API_DOWNLOADMANAGER->ReleaseDownload( token );
+ }
+
+ CloseHandle( threadHandle );
+
+ if ( NULL != dispatch )
+ dispatch->Release();
+}
+
+enum
+{
+ DISP_JNETCOM_ABORT,
+ DISP_JNETCOM_ADDHEADER,
+ DISP_JNETCOM_CONNECT,
+ DISP_JNETCOM_GETCONTENT,
+ DISP_JNETCOM_GETCONTENTASSTRING,
+ DISP_JNETCOM_GETERRORSTRING,
+ DISP_JNETCOM_GETHEADER,
+ DISP_JNETCOM_GETREPLY,
+ DISP_JNETCOM_GETREPLYCODE,
+ DISP_JNETCOM_GETURL,
+ DISP_JNETCOM_SETPOSTSTRING,
+};
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+HRESULT JNetCOM::GetIDsOfNames( REFIID riid, OLECHAR FAR *FAR *rgszNames, unsigned int cNames, LCID lcid, DISPID FAR *rgdispid )
+{
+ bool unknowns = false;
+ for ( unsigned int i = 0; i != cNames; i++ )
+ {
+ CHECK_ID( "Abort", DISP_JNETCOM_ABORT );
+ CHECK_ID( "AddHeader", DISP_JNETCOM_ADDHEADER );
+ CHECK_ID( "Connect", DISP_JNETCOM_CONNECT );
+ CHECK_ID( "GetContent", DISP_JNETCOM_GETCONTENT );
+ CHECK_ID( "GetContentAsString", DISP_JNETCOM_GETCONTENTASSTRING );
+ CHECK_ID( "GetErrorString", DISP_JNETCOM_GETERRORSTRING );
+ CHECK_ID( "GetHeader", DISP_JNETCOM_GETHEADER );
+ CHECK_ID( "GetReply", DISP_JNETCOM_GETREPLY );
+ CHECK_ID( "GetReplyCode", DISP_JNETCOM_GETREPLYCODE );
+ CHECK_ID( "GetURL", DISP_JNETCOM_GETURL );
+ CHECK_ID( "SetPOSTString", DISP_JNETCOM_SETPOSTSTRING );
+
+ rgdispid[ i ] = DISPID_UNKNOWN;
+ unknowns = true;
+ }
+
+ if ( unknowns )
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+HRESULT JNetCOM::GetTypeInfo( unsigned int itinfo, LCID lcid, ITypeInfo FAR *FAR *pptinfo )
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JNetCOM::GetTypeInfoCount( unsigned int FAR *pctinfo )
+{
+ return E_NOTIMPL;
+}
+
+HRESULT JNetCOM::Invoke( DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR *pexecinfo, unsigned int FAR *puArgErr )
+{
+ switch ( dispid )
+ {
+ case DISP_JNETCOM_ABORT:
+ return Abort();
+ case DISP_JNETCOM_ADDHEADER:
+ return AddHeader( pdispparams->rgvarg[ 0 ].bstrVal );
+ case DISP_JNETCOM_CONNECT:
+ if ( pdispparams->cArgs == 2 )
+ return Connect( pdispparams->rgvarg[ 1 ].bstrVal, pdispparams->rgvarg[ 0 ].bstrVal );
+ else
+ return Connect( pdispparams->rgvarg[ 0 ].bstrVal, L"GET" );
+ case DISP_JNETCOM_GETCONTENT:
+ return GetContent( pvarResult );
+ case DISP_JNETCOM_GETCONTENTASSTRING:
+ return GetContentAsString( pvarResult );
+ case DISP_JNETCOM_GETERRORSTRING:
+ return GetErrorString( pvarResult );
+ case DISP_JNETCOM_GETHEADER:
+ return GetHeader( pdispparams->rgvarg[ 0 ].bstrVal, pvarResult );
+ case DISP_JNETCOM_GETREPLY:
+ return GetReply( pvarResult );
+ case DISP_JNETCOM_GETREPLYCODE:
+ return GetReplyCode( pvarResult );
+ case DISP_JNETCOM_GETURL:
+ return GetUrl( pvarResult );
+ case DISP_JNETCOM_SETPOSTSTRING:
+ break;
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+
+STDMETHODIMP JNetCOM::QueryInterface( REFIID riid, PVOID *ppvObject )
+{
+ if ( !ppvObject )
+ return E_POINTER;
+ else if ( IsEqualIID( riid, IID_IDispatch ) )
+ *ppvObject = (IDispatch *)this;
+ else if ( IsEqualIID( riid, IID_IUnknown ) )
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return S_OK;
+}
+
+ULONG JNetCOM::AddRef( void )
+{
+ return InterlockedIncrement( &refCount );
+}
+
+ULONG JNetCOM::Release( void )
+{
+ LONG lRef = InterlockedDecrement( &refCount );
+ if ( lRef == 0 )
+ delete this;
+
+ return lRef;
+}
+
+/* ---- */
+HRESULT JNetCOM::Abort()
+{
+ if ( NULL != WAC_API_DOWNLOADMANAGER )
+ WAC_API_DOWNLOADMANAGER->CancelDownload( token );
+
+ return S_OK;
+}
+
+HRESULT JNetCOM::AddHeader( LPCWSTR header )
+{
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
+ if ( http )
+ http->addheader( AutoChar( header, CP_UTF8 ) );
+
+ return S_OK;
+}
+
+HRESULT JNetCOM::Connect( LPCWSTR url, LPCWSTR requestMethod )
+{
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ AddRef();
+
+ token = WAC_API_DOWNLOADMANAGER->DownloadEx( AutoChar( url, CP_UTF8 ), this, api_downloadManager::DOWNLOADEX_BUFFER );
+
+ return S_OK;
+}
+
+HRESULT JNetCOM::GetContent( VARIANT *variant )
+{
+ char dummy[ 1 ] = { 0 };
+ size_t sourcelen = 0;
+ void *source = 0;
+
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ WAC_API_DOWNLOADMANAGER->GetBuffer( token, &source, &sourcelen );
+
+ if ( !sourcelen || !source )
+ {
+ source = dummy;
+ sourcelen = 1;
+ }
+
+ SAFEARRAY *bufferArray = SafeArrayCreateVector( VT_UI1, 0, (ULONG)sourcelen );
+ void *data;
+ SafeArrayAccessData( bufferArray, &data );
+ memcpy( data, source, sourcelen );
+ SafeArrayUnaccessData( bufferArray );
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_ARRAY | VT_UI1;
+ V_ARRAY( variant ) = bufferArray;
+
+ return S_OK;
+}
+
+HRESULT JNetCOM::GetContentAsString( VARIANT *variant )
+{
+ // TODO: try to determine character encoding
+ size_t sourcelen = 0;
+ void *source = 0;
+
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ if ( WAC_API_DOWNLOADMANAGER->GetBuffer( token, &source, &sourcelen ) == 0 )
+ {
+ if ( source && sourcelen )
+ {
+ int len = MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)source, (int)sourcelen, 0, 0 );
+ BSTR str = SysAllocStringLen( 0, len );
+
+ MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)source, (int)sourcelen, str, len );
+
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_BSTR;
+ V_BSTR( variant ) = str;
+
+ return S_OK;
+ }
+ else
+ {
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_BSTR;
+ V_BSTR( variant ) = SysAllocString( L"" );
+
+ return S_OK;
+ }
+ }
+ else
+ return E_FAIL;
+}
+
+HRESULT JNetCOM::GetErrorString( VARIANT *variant )
+{
+ const char *source = 0;
+
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
+ if ( http )
+ source = http->geterrorstr();
+
+ if ( !source )
+ source = "";
+
+ int sourcelen = (int)strlen( source );
+ int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
+ BSTR str = SysAllocStringLen( 0, len );
+
+ MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_BSTR;
+ V_BSTR( variant ) = str;
+
+ return S_OK;
+}
+
+HRESULT JNetCOM::GetHeader( LPCWSTR header, VARIANT *variant )
+{
+ const char *source = 0;
+
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
+ if ( http )
+ source = http->getheader( AutoChar( header, CP_UTF8 ) );
+
+ if ( !source )
+ source = "";
+
+ int sourcelen = (int)strlen( source );
+ int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
+ BSTR str = SysAllocStringLen( 0, len );
+
+ MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_BSTR;
+ V_BSTR( variant ) = str;
+
+ return S_OK;
+}
+
+
+HRESULT JNetCOM::GetReply( VARIANT *variant )
+{
+ const char *source = 0;
+
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
+ if ( http )
+ source = http->GetReply();
+
+ if ( !source )
+ source = "";
+
+ int sourcelen = (int)strlen( source );
+ int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
+ BSTR str = SysAllocStringLen( 0, len );
+
+ MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_BSTR;
+ V_BSTR( variant ) = str;
+
+ return S_OK;
+}
+
+HRESULT JNetCOM::GetReplyCode( VARIANT *variant )
+{
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ int code = 0;
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
+ if ( http )
+ code = http->getreplycode();
+
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_UI4;
+ V_UI4( variant ) = code;
+
+ return S_OK;
+}
+
+HRESULT JNetCOM::GetUrl( VARIANT *variant )
+{
+ if ( NULL == WAC_API_DOWNLOADMANAGER )
+ return E_POINTER;
+
+ const char *source = 0;
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
+ if ( http )
+ source = http->get_url();
+
+ if ( !source )
+ source = "";
+
+ int sourcelen = (int)strlen( source );
+ int len = MultiByteToWideChar( 1252, 0, source, sourcelen, 0, 0 );
+ BSTR str = SysAllocStringLen( 0, len );
+
+ MultiByteToWideChar( 1252, 0, source, sourcelen, str, len );
+ VariantInit( variant );
+
+ V_VT( variant ) = VT_BSTR;
+ V_BSTR( variant ) = str;
+
+ return S_OK;
+}
+
+extern void CallDispatchMethod( IDispatch *dispatch, DISPPARAMS &params, OLECHAR *name );
+
+struct APCWait
+{
+ IDispatch *dispatch;
+ HANDLE hEvent;
+};
+
+#define AutoAPC(name) \
+ static VOID CALLBACK name ## APC(ULONG_PTR param) {\
+ APCWait *wait = (APCWait *)param;\
+\
+ DISPPARAMS params;\
+ params.cArgs = 0;\
+ params.cNamedArgs = 0;\
+ params.rgdispidNamedArgs = 0;\
+ params.rgvarg = 0;\
+ if (wait->dispatch != NULL)\
+ CallDispatchMethod(wait->dispatch, params, L ## #name);\
+ if (wait->hEvent)\
+ SetEvent(wait->hEvent);\
+}
+
+AutoAPC( OnFinish );
+AutoAPC( OnTick );
+AutoAPC( OnError );
+AutoAPC( OnCancel );
+AutoAPC( OnConnect );
+AutoAPC( OnInit );
+
+void JNetCOM::Call( PAPCFUNC func )
+{
+ DWORD curThreadId = GetCurrentThreadId();
+
+ if ( curThreadId == threadId )
+ {
+ APCWait wait;
+ wait.dispatch = dispatch;
+ wait.hEvent = 0;
+
+ func( (ULONG_PTR)&wait );
+ }
+ else
+ {
+ if ( threadHandle )
+ {
+ APCWait wait;
+ wait.dispatch = dispatch;
+ wait.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ if ( QueueUserAPC( func, threadHandle, (ULONG_PTR)&wait ) != 0 )
+ WaitForSingleObject( wait.hEvent, INFINITE );
+
+ CloseHandle( wait.hEvent );
+ }
+ }
+
+}
+
+void JNetCOM::OnFinish( DownloadToken token )
+{
+ if ( NULL != WAC_API_DOWNLOADMANAGER )
+ WAC_API_DOWNLOADMANAGER->RetainDownload( token );
+
+ retained = true;
+
+ Call( OnFinishAPC );
+
+ token = 0;
+
+ Release();
+}
+
+void JNetCOM::OnTick( DownloadToken token )
+{
+ //Call(OnTickAPC);
+}
+
+void JNetCOM::OnError( DownloadToken token, int error )
+{
+ if ( NULL != WAC_API_DOWNLOADMANAGER )
+ WAC_API_DOWNLOADMANAGER->RetainDownload( token );
+
+ retained = true;
+
+ Call( OnErrorAPC );
+
+ token = 0;
+
+ Release();
+}
+
+void JNetCOM::OnCancel( DownloadToken token )
+{
+ if ( NULL != WAC_API_DOWNLOADMANAGER )
+ WAC_API_DOWNLOADMANAGER->RetainDownload( token );
+
+ retained = true;
+
+ Call( OnCancelAPC );
+
+ token = 0;
+
+ Release();
+}
+
+void JNetCOM::OnConnect( DownloadToken token )
+{
+ Call( OnConnectAPC );
+}
+
+void JNetCOM::OnInit( DownloadToken token )
+{
+ Call( OnInitAPC );
+}
+
+size_t JNetCOM::Dispatchable_AddRef()
+{
+ return InterlockedIncrement( &refCount );
+}
+
+size_t JNetCOM::Dispatchable_Release()
+{
+ LONG lRef = InterlockedDecrement( &refCount );
+ if ( lRef == 0 )
+ delete this;
+
+ return lRef;
+}
+
+
+#define CBCLASS JNetCOM
+START_DISPATCH;
+CB( ADDREF, Dispatchable_AddRef )
+CB( RELEASE, Dispatchable_Release )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Winamp/jnetcom.h b/Src/Winamp/jnetcom.h
new file mode 100644
index 00000000..aa2e357e
--- /dev/null
+++ b/Src/Winamp/jnetcom.h
@@ -0,0 +1,77 @@
+#pragma once
+#include <ocidl.h>
+#include "..\Components\wac_network\wac_network_http_receiver_api.h"
+#include "api.h"
+
+
+class JNetCOM : public IDispatch, public ifc_downloadManagerCallback
+{
+public:
+ JNetCOM(IDispatch *_dispatch);
+ ~JNetCOM();
+ STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ // *** IDispatch Methods ***
+ STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
+ STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
+ STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
+ STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
+
+ STDMETHOD (Abort)();
+ STDMETHOD (AddHeader)(LPCWSTR header);
+ STDMETHOD (Connect)(LPCWSTR url, LPCWSTR requestMethod);
+ STDMETHOD (GetContent)(VARIANT *variant);
+ STDMETHOD (GetContentAsString)(VARIANT *variant);
+ STDMETHOD (GetErrorString)(VARIANT *variant);
+ STDMETHOD (GetHeader)(LPCWSTR header, VARIANT *variant);
+ STDMETHOD (GetReply)(VARIANT *variant);
+ STDMETHOD (GetReplyCode)(VARIANT *variant);
+ STDMETHOD (GetUrl)(VARIANT *variant);
+
+ /* Dispatchable */
+ size_t Dispatchable_AddRef();
+ size_t Dispatchable_Release();
+
+ void OnFinish(DownloadToken token);
+ void OnTick(DownloadToken token);
+ void OnError(DownloadToken token, int error);
+ void OnCancel(DownloadToken token);
+ void OnConnect(DownloadToken token);
+ void OnInit(DownloadToken token);
+
+ void Call(PAPCFUNC func);
+ /*
+ methods:
+ Abort
+ AddHeader (only call this during OnInit)
+ Connect (here is where you specify the URL)
+ GetContent
+ GetContentAsString
+ GetErrorString
+ GetHeader
+ GetReply
+ GetReplyCode
+ GetUrl (may not be the same as what you originally connected because of redirection)
+ SetPostString (only call this during OnInit)
+
+ callback methods in YOUR object:
+ OnCancel
+ OnConnect
+ OnError
+ OnFinish
+ OnTick (called every once in a while)
+ OnInit (called immediately after Connect(), you can add headers and shit here
+
+ */
+
+private:
+ LONG refCount;
+ DWORD threadId;
+ HANDLE threadHandle;
+ IDispatch *dispatch;
+ DownloadToken token;
+ bool retained;
+protected:
+ RECVS_DISPATCH;
+}; \ No newline at end of file
diff --git a/Src/Winamp/lang.cpp b/Src/Winamp/lang.cpp
new file mode 100644
index 00000000..5c2f9581
--- /dev/null
+++ b/Src/Winamp/lang.cpp
@@ -0,0 +1,1136 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description: Utility functions for handling language support
+** Author:
+** Created:
+**/
+
+#include <locale.h>
+#include "main.h"
+#include "language.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "minizip/unzip.h"
+#include <vector>
+#include "../nu/AutoCharFn.h"
+
+typedef struct {
+ wchar_t *module;
+ wchar_t *guidstr; // generally is 0 or 39 (38+null)
+ int guid;
+ int external;
+ HINSTANCE hDllInstance;
+} winampLangStruct;
+
+static std::vector<winampLangStruct*> lnglist;
+int already_extracted = 0, prev_wlz_ex_state = 0, geno = 1, started = 0;
+
+// data storage of the read in values requires just the hash and the id to be stored
+// and has to be logged against the different id types so just need a list of structs
+// based against each type (dialog, string resource, etc)
+
+// for the moment we deal with the following resource types
+// RT_DIALOG, RT_MENU, RT_STRING & custom resources
+// so for initial implementation we only need to store upto 4 hash+id lists
+
+#if 0
+typedef struct {
+ int id;
+ char id_str[32];
+ char hash[17];
+ char str[64];
+} hashstruct;
+
+std::vector<hashstruct*> dialogList;
+std::vector<hashstruct*> menuList;
+std::vector<hashstruct*> stringList; // will be the largest of the lot
+std::vector<hashstruct*> customList; // should be very few of this
+#endif
+
+// have section header (text or int id)
+// then the hash and then the id that's related the hash eg the dialog resource id
+
+void ReadHashFileDetails(char* data, DWORD datalen)
+{
+#if 0
+ char* p = data, *s = p, *t = 0, *u;
+ while(s && *s)
+ {
+ // is it the start of a block that we've just gotten to...
+ if(*s == '@' || *s == '#')
+ {
+ int id = -1;
+ char id_str[32] = {0};
+ u = s = CharNext(s);
+ if(!*s){break;}
+
+ // advance to the end of the line to get the block identifier
+ // would need to use the @ or # to process the type used
+ // ie if a type 5 then only use on dialog loading calls
+ while(u && *u && *u != '\n'){u = CharNext(u);}
+ if(*u == '\n'){u = CharNext(u);*CharPrev(p,u) = 0;}
+ if(!*u){break;}
+
+ // identifier of the block is found here :)
+ if(*s)
+ {
+ id = atoi(s);
+ if(!id)
+ {
+ lstrcpyn(id_str, s, sizeof(id_str));
+ }
+ }
+ *CharPrev(p,u) = '\n';
+
+ while(s && *s && (*s != '@' && *s != '#'))
+ {
+ int end = 0;
+
+ while(s && *s && *s != '\n'){s = CharNext(s);}
+ if(*s == '\n'){s = CharNext(s);}
+ // if nothing else then need to abort (since we don't want to do bad things)
+ // and have to take into account where in the buffer we are otherwise we can
+ // end up going into the next part of the dll/exe resource data due to how
+ // it is all stored/handled in them (ie butted up against each other)
+ if(!*s || s >= p+datalen){break;}
+
+ t = s;
+ // do a check after we've advanced to the start of a new line
+ // so that we can see if we've hit a new resource type block
+ if(*s == '@' || *s == '#')
+ {
+ s = CharPrev(p,s);
+ break;
+ }
+
+ // scan through to the start of the second part of the <hash:id> block
+ while(t && *t && *t != ':')
+ {
+ t = CharNext(t);
+ }
+
+ if(*t == ':')
+ {
+ t = CharNext(t);
+ *CharPrev(p,t) = 0;
+ }
+
+ // scan through to the end of the line so that we then have the id
+ u = t;
+ while(u && *u && *u != '\n')
+ {
+ u = CharNext(u);
+ }
+
+ if(*u == '\n')
+ {
+ u = CharNext(u);
+ *CharPrev(p,u) = 0;
+ }
+
+ // hash and identifier of the entry is found here :)
+ // -> need to check how it works with IDD_CRASHDLG$()
+ if(*s)
+ {
+ hashstruct* tempList = reinterpret_cast<hashstruct*>(calloc(1, sizeof(hashstruct)));
+ ZeroMemory(tempList,sizeof(hashstruct));
+
+ /*if(*t == 1) wsprintf(a,"%s %d (%s)\n", s, *t, t+1);
+ else wsprintf(a,"%s %s (%d)\n", s, t+1, *t);*/
+ if(*t == 1) // int_id
+ lstrcpyn(tempList->str, t+1, sizeof(tempList->str));
+ else // string_id
+ lstrcpyn(tempList->str, t+1, *t/*sizeof(tempList->str)*/);
+
+ lstrcpyn(tempList->hash, s, sizeof(tempList->hash));
+ if(id) tempList->id = id;
+
+ switch(id)
+ {
+ case RT_MENU:
+ {
+ menuList.push_back(tempList);
+ }
+ break;
+ case RT_DIALOG:
+ {
+ dialogList.push_back(tempList);
+ }
+ break;
+ case RT_STRING:
+ {
+ stringList.push_back(tempList);
+ }
+ break;
+ default:
+ // only do if there's no id from atoi (indicates a custom resource id)
+ if(!id)
+ {
+ lstrcpyn(tempList->id_str, id_str, sizeof(tempList->id_str));
+ customList.push_back(tempList);
+ }
+ break;
+ }
+
+ {
+ char zz[100] = {0};
+ StringCchPrintf(zz,100,"ID: '%s' %d\t%s %s\n",
+ tempList->id_str, tempList->id,
+ tempList->hash, tempList->str);
+ OutputDebugString(zz);
+ }
+ }
+ *CharPrev(p,u) = '\n';
+ s = CharPrev(p,u);
+ }
+ }
+ s = CharNext(s);
+ }
+#endif
+}
+
+int GetImageHashData(HINSTANCE imageInstance)
+{
+ DWORD datalen = 0;
+ void* data = langManager->LoadResourceFromFile(imageInstance,imageInstance,L"HASH",L"HASH",&datalen);
+ ReadHashFileDetails((char*)data,datalen);
+ UnlockResource(data);
+ FreeResource(data);
+ return 0;
+}
+
+#ifdef _DEBUG
+static void CheckLangThread()
+{
+ if (mainThreadId != GetCurrentThreadId())
+ {
+// DebugBreak();
+ /**
+ ** If you hit this breakpoint, it's because you tried to use WASABI_API_LANG->GetString on another thread,
+ ** without supplying your own buffer.
+ ** You really don't want to be doing that.
+ ** Hit alt+7, check what function is calling GetString/GetStringW and go fix it.
+ ** Now.
+ **/
+ }
+}
+
+#else
+#define CheckLangThread()
+#endif
+
+char *getString(UINT uID, char *str, size_t maxlen)
+{
+ return langManager->GetString(language_pack_instance,hMainInstance, uID, str, maxlen);
+}
+
+int LPMessageBox(HWND parent, UINT idMessage, UINT idTitle, UINT type)
+{
+ wchar_t message[32768] = {0};
+ wchar_t title[256] = {0};
+
+ // TODO consider exposing something in the winamp.lng file so we can follow this where possible as it should allow for a localised messagebox as long as the OS supports the language
+ // return MessageBoxExW(parent,getStringW(idMessage,message,32768),getStringW(idTitle,title,256),type,MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH));
+ return MessageBoxW(parent,getStringW(idMessage,message,32768),getStringW(idTitle,title,256),type);
+}
+
+char* Language::GetString(HINSTANCE hinst, HINSTANCE owner, UINT uID, char *str, size_t maxlen)
+{
+ __declspec(thread) static char *buf;
+ if (!str)
+ {
+ CheckLangThread();
+ if (!buf)
+ buf = (char *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
+ str = buf;
+ maxlen = LANG_STATIC_BUFFER_SIZE;
+ }
+
+ // sometimes we need to ignore things i.e. accessing on closing, etc
+ if (((unsigned long)str >= 65536) && !LoadStringA((started ? hinst : owner), uID, str, (int)maxlen))
+ {
+ if (hinst == owner || !LoadStringA(owner, uID, str, (int)maxlen))
+ {
+ lstrcpynA(str, "Error loading string", (int)maxlen);
+ }
+ }
+ return str;
+}
+
+wchar_t *getStringW(UINT uID, wchar_t *str, size_t maxlen)
+{
+ return langManager->GetStringW(language_pack_instance,hMainInstance, uID, str, maxlen);
+}
+
+wchar_t* Language::GetStringW(HINSTANCE hinst, HINSTANCE owner, UINT uID, wchar_t *str, size_t maxlen)
+{
+ __declspec(thread) static wchar_t *buf;
+ if (!str)
+ {
+ CheckLangThread();
+ if (!buf)
+ buf = (wchar_t *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
+ str = buf;
+ maxlen = LANG_STATIC_BUFFER_SIZE;
+ }
+
+ // sometimes we need to ignore things i.e. accessing on closing, etc
+ if (((unsigned long)str >= 65536) && !LoadStringW((started ? hinst : owner), uID, str, (int)maxlen))
+ {
+ if (hinst == owner || !LoadStringW(owner, uID, str, (int)maxlen))
+ {
+ lstrcpynW(str, L"Error loading string", (int)maxlen);
+ }
+ }
+ return str;
+}
+
+char* Language::GetStringFromGUID(const GUID guid, HINSTANCE owner, UINT uID, char *str, size_t maxlen)
+{
+ __declspec(thread) static char *buf;
+ if (!str)
+ {
+ CheckLangThread();
+ if (!buf)
+ buf = (char *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
+ str = buf;
+ maxlen = LANG_STATIC_BUFFER_SIZE;
+ }
+
+ HINSTANCE tl = FindDllHandleByGUID(guid);
+ if(!tl) tl = owner;
+
+ // sometimes we need to ignore things i.e. accessing on closing, etc
+ if (((unsigned long)str >= 65536) && !LoadStringA((started ? tl : owner), uID, str, (int)maxlen))
+ {
+ if (!LoadStringA(owner, uID, str, (int)maxlen))
+ {
+ lstrcpynA(str, "Error loading string", (int)maxlen);
+ }
+ }
+ return str;
+}
+
+wchar_t* Language::GetStringFromGUIDW(const GUID guid, HINSTANCE owner, UINT uID, wchar_t *str, size_t maxlen)
+{
+ __declspec(thread) static wchar_t *buf;
+ if (!str)
+ {
+ CheckLangThread();
+ if (!buf)
+ buf = (wchar_t *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
+ str = buf;
+ maxlen = LANG_STATIC_BUFFER_SIZE;
+ }
+
+ HINSTANCE tl = FindDllHandleByGUID(guid);
+ if(!tl) tl = owner;
+
+ // sometimes we need to ignore things i.e. accessing on closing, etc
+ if (((unsigned long)str >= 65536) && !LoadStringW((started ? tl : owner), uID, str, (int) maxlen))
+ {
+ if (!LoadStringW(owner, uID, str, (int) maxlen))
+ {
+ lstrcpynW(str, L"Error loading string", (int) maxlen);
+ }
+ }
+ return str;
+}
+
+const wchar_t *Language::GetLanguageFolder()
+{
+ return (LANGTEMPDIR[0] ? LANGTEMPDIR : lang_directory);
+}
+
+void* Language::LoadResourceFromFileW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpType, LPCWSTR lpName, DWORD* size)
+{
+ HINSTANCE hmod = hinst;
+ HRSRC rsrc = FindResourceW(hmod, lpName, lpType);
+ if(!rsrc)
+ {
+ hmod = owner;
+ rsrc = FindResourceW(hmod, lpName, lpType);
+ }
+ if(rsrc)
+ {
+ HGLOBAL resourceHandle = LoadResource(hmod, rsrc);
+ if(size){*size = SizeofResource(hmod, rsrc);}
+ return LockResource(resourceHandle);
+ }
+ return 0;
+}
+
+void* Language::LoadResourceFromFile(HINSTANCE hinst, HINSTANCE owner, LPCTSTR lpType, LPCTSTR lpName, DWORD* size)
+{
+ HINSTANCE hmod = hinst;
+ HRSRC rsrc = FindResource(hmod, lpName, lpType);
+ if(!rsrc)
+ {
+ hmod = owner;
+ rsrc = FindResource(hmod, lpName, lpType);
+ }
+ if(rsrc)
+ {
+ HGLOBAL resourceHandle = LoadResource(hmod, rsrc);
+ if(size){*size = SizeofResource(hmod, rsrc);}
+ return LockResource(resourceHandle);
+ }
+ return 0;
+}
+
+const wchar_t *Language::GetLanguageIdentifier( int mode )
+{
+ static wchar_t id_str[ 9 ] = { 0 };
+ id_str[ 0 ] = 0;
+ // 5.58 fix - was returning en-US on all calls to this via load_extra_lng(..)
+ // make sure to try to use a loaded winamp.lng as load_extra_lng(..) relies on
+ // this for the path to use but calls it before getStringW(..) will work fully
+ GetStringFromGUIDW( WinampLangGUID, hMainInstance, LANG_PACK_LANG_ID, id_str, 9 );
+
+ if ( !_wcsicmp( id_str, L"Error l" ) )
+ {
+ id_str[ 0 ] = 0;
+ }
+
+ if ( mode && id_str[ 0 ] )
+ {
+ wchar_t *iStr = id_str;
+
+ while ( iStr && *iStr && *iStr != L'-' )
+ {
+ iStr = CharNextW( iStr );
+ }
+
+ if ( iStr && *iStr == '-' )
+ {
+ iStr = CharNextW( iStr );
+ *CharPrevW( id_str, iStr ) = 0;
+ }
+
+ if ( mode == LANG_LANG_CODE )
+ return id_str;
+ else if ( mode == LANG_COUNTRY_CODE )
+ return iStr;
+ }
+
+ return ( id_str[ 0 ] ? id_str : 0 );
+}
+
+HWND Language::CreateLDialogParam( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ HWND hwnd = (HWND)CreateDialogParamA( localised, MAKEINTRESOURCEA( id ), parent, proc, param );
+ if ( !hwnd && localised != original )
+ hwnd = (HWND)CreateDialogParamA( original, MAKEINTRESOURCEA( id ), parent, proc, param );
+ return hwnd;
+}
+
+HWND Language::CreateLDialogParamW( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ HWND hwnd = (HWND)CreateDialogParamW( localised, MAKEINTRESOURCEW( id ), parent, proc, param );
+ if ( !hwnd && localised != original )
+ hwnd = (HWND)CreateDialogParamW( original, MAKEINTRESOURCEW( id ), parent, proc, param );
+ return hwnd;
+}
+
+INT_PTR Language::LDialogBoxParam( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ INT_PTR ret = DialogBoxParamA( localised, MAKEINTRESOURCEA( id ), parent, proc, param );
+ if ( ( ret == -1 && GetLastError() != ERROR_SUCCESS ) && localised != original )
+ ret = DialogBoxParamA( original, MAKEINTRESOURCEA( id ), parent, proc, param );
+ return ret;
+}
+
+INT_PTR Language::LDialogBoxParamW( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ INT_PTR ret = DialogBoxParamW( localised, MAKEINTRESOURCEW( id ), parent, proc, param );
+ if ( ( ret == -1 && GetLastError() != ERROR_SUCCESS ) && localised != original )
+ ret = DialogBoxParamW( original, MAKEINTRESOURCEW( id ), parent, proc, param );
+ return ret;
+}
+
+HWND LPCreateDialogParam( int id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ return langManager->CreateLDialogParam( language_pack_instance, hMainInstance, id, parent, proc, param );
+}
+
+HWND LPCreateDialogParamW( int id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ return langManager->CreateLDialogParamW( language_pack_instance, hMainInstance, id, parent, proc, param );
+}
+
+INT_PTR LPDialogBoxParam( int id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ return langManager->LDialogBoxParam( language_pack_instance, hMainInstance, id, parent, proc, param );
+}
+
+INT_PTR LPDialogBoxParamW( int id, HWND parent, DLGPROC proc, LPARAM param )
+{
+ return langManager->LDialogBoxParamW( language_pack_instance, hMainInstance, id, parent, proc, param );
+}
+
+HMENU Language::LoadLMenu( HINSTANCE localised, HINSTANCE original, UINT id )
+{
+ HMENU menu = LoadMenuA( localised, MAKEINTRESOURCEA( id ) );
+ if ( !menu && localised != original )
+ menu = LoadMenuA( original, MAKEINTRESOURCEA( id ) );
+
+ return menu;
+}
+
+HMENU Language::LoadLMenuW(HINSTANCE localised, HINSTANCE original, UINT id)
+{
+ HMENU menu = LoadMenuW(localised, MAKEINTRESOURCEW(id));
+ if (!menu && localised != original)
+ menu = LoadMenuW(original, MAKEINTRESOURCEW(id));
+ return menu;
+}
+
+HACCEL Language::LoadAcceleratorsA(HINSTANCE hinst, HINSTANCE owner, LPCSTR lpTableName)
+{
+ HACCEL hAccel = ::LoadAcceleratorsA(hinst, lpTableName);
+ if (!hAccel && hinst != owner)
+ hAccel = ::LoadAcceleratorsA(owner, lpTableName);
+ return hAccel;
+}
+
+HACCEL Language::LoadAcceleratorsW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpTableName)
+{
+ HACCEL hAccel = ::LoadAcceleratorsW(hinst, lpTableName);
+ if (!hAccel && hinst != owner)
+ hAccel = ::LoadAcceleratorsW(owner, lpTableName);
+ return hAccel;
+}
+
+// Implemented in 5.58+
+// when we're loading a language pack we really need to specify if we're
+// going to require correct use of the user's locale setting so that the
+// output of certain text ie '%+6.1f' uses the correct decimal separator
+// ref: http://msdn.microsoft.com/en-us/library/aa246453%28VS.60%29.aspx
+BOOL Language::UseUserNumericLocale(void)
+{
+ wchar_t tmp[4] = {0}, lang[4] = {0}, ctry[4] = {0};
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, 4);
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, ctry, 4);
+
+ // do this check to ensure that the we only change the locale
+ // if the language pack and the user locale identifiers match
+ if(!_wcsicmp(lang, GetLanguageIdentifier(LANG_LANG_CODE)) &&
+ !_wcsicmp(ctry, GetLanguageIdentifier(LANG_COUNTRY_CODE)) &&
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, tmp, 4))
+ {
+ _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
+ // now we set the functions to use the user's numeric locale
+ return !!_wsetlocale(LC_NUMERIC,tmp);
+ }
+ return FALSE;
+}
+
+_locale_t Language::Get_C_NumericLocale(void)
+{
+ __declspec(thread) static _locale_t C_locale;
+ if(!C_locale) C_locale = _create_locale(LC_NUMERIC, "C");
+ return C_locale;
+}
+
+// Implemented in 5.64+
+wchar_t* Language::FormattedSizeString(wchar_t *pszDest, int cchDest, __int64 size)
+{
+ if (!pszDest) return 0;
+ size_t remaining = cchDest;
+ DWORD part = 0;
+ pszDest[0] = 0x00;
+
+ if (size < 1024)
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS,
+ L"%u %s", (DWORD)(size >> 10) + ((((DWORD)(size))&1023) ? 1: 0),
+ getStringW(IDS_BYTES, NULL, 0));
+ }
+ else if (size < 1048576)
+ {
+ part = ((((DWORD)(size))&1023)*100) >> 10;
+ if (part > 0)
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
+ (DWORD)(size >> 10), part, getStringW(geno ? IDS_KB : IDS_KIB, NULL, 0));
+ }
+ else
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
+ (DWORD)(size >> 10), getStringW(geno ? IDS_KB : IDS_KIB, NULL, 0));
+ }
+ }
+ else if (size < 1073741824)
+ {
+ part = ((((DWORD)(size >> 10))&1023)*100) >> 10;
+ if (part > 0)
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
+ (DWORD)(size >> 20), part, getStringW(geno ? IDS_MB : IDS_MIB, NULL, 0));
+ }
+ else
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
+ (DWORD)(size >> 20), getStringW(geno ? IDS_MB : IDS_MIB, NULL, 0));
+ }
+ }
+ else if (size < 1099511627776)
+ {
+ part = ((((DWORD)(size >> 20))&1023)*100) >> 10;
+ if (part > 0)
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
+ (DWORD)(size >> 30), part, getStringW(geno ? IDS_GB : IDS_GIB, NULL, 0));
+ }
+ else
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
+ (DWORD)(size >> 30), getStringW(geno ? IDS_GB : IDS_GIB, NULL, 0));
+ }
+ }
+ else
+ {
+ part = ((((DWORD)(size >> 30))&1023)*100) >> 10;
+ if (part > 0)
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
+ (DWORD)(size >> 40), part, getStringW(geno ? IDS_TB : IDS_TIB, NULL, 0));
+ }
+ else
+ {
+ StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
+ (DWORD)(size >> 40), getStringW(geno ? IDS_TB : IDS_TIB, NULL, 0));
+ }
+ }
+
+
+ return pszDest;
+}
+
+HMENU LPLoadMenu(UINT id)
+{
+ return langManager->LoadLMenu(language_pack_instance, hMainInstance, id);
+}
+
+
+void Lang_CleanupZip(void)
+{
+ if (!LANGTEMPDIR[0]) return ;
+ if (_cleanupDirW(LANGTEMPDIR))
+ {
+ char str[78] = {0};
+ StringCchPrintfA(str,78,"lang_clean_up%ws",szAppName);
+ _w_s(str, 0);
+ }
+}
+
+
+// attempt to cleanup the last extracted temp folder for a wlz incase Winamp crashed on exit
+void Lang_CleanupAfterCrash(void)
+{
+ wchar_t buf[1024] = {0};
+ char str[78] = {0};
+ StringCchPrintfA(str,78,"lang_clean_up%ws",szAppName);
+ _r_sW(str, buf, sizeof(buf));
+ if (buf[0])
+ {
+ _cleanupDirW(buf);
+ _w_s(str, 0);
+ }
+}
+
+static int load_extra_lng(BOOL force)
+{
+ int is_wlz = 0;
+ if (langManager)
+ {
+ const wchar_t *lang_identifier = langManager->GetLanguageIdentifier(LANG_IDENT_STR);
+ if (lang_identifier || force)
+ {
+ wchar_t extra_lang_path[MAX_PATH] = {0};
+ wchar_t lng_file[MAX_PATH] = {0};
+
+ if (!force)
+ PathCombineW(extra_lang_path, LANGDIR, lang_identifier);
+ else
+ lstrcpynW(extra_lang_path, lang_directory, MAX_PATH);
+
+ PathCombineW(lng_file, extra_lang_path, L"*.lng");
+ WIN32_FIND_DATAW find_data = {0};
+ HANDLE h = FindFirstFileW(lng_file, &find_data);
+
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ PathCombineW(lng_file, extra_lang_path, find_data.cFileName);
+ is_wlz = 1;
+ winampLangStruct* templng = reinterpret_cast<winampLangStruct*>(calloc(1, sizeof(winampLangStruct)));
+ templng->module = _wcsdup(lng_file);
+
+ bool exception = (!lstrcmpiW(templng->module, L"omBrowser.lng") || !lstrcmpiW(templng->module, L"ml_online.lng"));
+
+ // the plain LoadLibrary(..) generally works though as we only want to
+ // load the lng files for resources (and that some people's lng files
+ // can generally end up being corrupted after a few edits), we instead
+ // try to load as an image / data file (so doesn't re-map things, etc)
+ templng->hDllInstance = LoadLibraryExW(lng_file, NULL, (!exception ? LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE : 0));
+ // incase of running on an older OS, try it as a plain LoadLibrary(..)
+ if (!templng->hDllInstance) templng->hDllInstance = LoadLibraryW(lng_file);
+ if (templng->hDllInstance)
+ {
+ wchar_t s[39] = {0};
+ if(LoadStringW(templng->hDllInstance, LANG_DLL_GUID_STRING_ID, s, 39))
+ {
+ templng->external = 1;
+ templng->guidstr = _wcsdup(s);
+ GetImageHashData(templng->hDllInstance);
+ }
+ // only keep if it's a valid lng dll ie doesn't have load issues
+ lnglist.push_back(templng);
+ }
+ }
+ while (FindNextFileW(h, &find_data));
+ FindClose(h);
+ }
+ }
+ }
+ return is_wlz;
+}
+
+
+// return 1 if we're working from a wlz otherwise return 0
+int extract_wlz_to_dir(wchar_t* readme_only_wlz_extraction, BOOL *skip)
+{
+ int is_wlz = 0;
+ if (config_langpack[0] || readme_only_wlz_extraction && readme_only_wlz_extraction[0])
+ {
+ wchar_t* langpack = (readme_only_wlz_extraction?readme_only_wlz_extraction:config_langpack),
+ tempdirbuf[MAX_PATH] = {0}, *TEMPDIR = LANGTEMPDIR;
+
+ if (_wcsicmp(extensionW(langpack), L"zip") && _wcsicmp(extensionW(langpack), L"wlz"))
+ {
+ if (PathIsFileSpecW(langpack) || PathIsRelativeW(langpack))
+ PathCombineW(lang_directory, LANGDIR, langpack);
+ else
+ StringCchCopyW(lang_directory, MAX_PATH, langpack);
+
+ is_wlz = load_extra_lng(TRUE);
+ if (skip) *skip = is_wlz;
+ }
+ else
+ {
+ wchar_t dirmask[MAX_PATH*4] = {0};
+ char str[78] = {0};
+ unzFile f = {0};
+
+ // make sure that we use a different folder from the current wlz temp folder otherwise we have issues
+ if(readme_only_wlz_extraction){
+ wchar_t buf[MAX_PATH] = {0};
+ GetTempPathW(MAX_PATH, buf);
+ GetTempFileNameW(buf, L"WLZ", GetTickCount(), tempdirbuf);
+ TEMPDIR = tempdirbuf;
+ }
+
+ CreateDirectoryW(TEMPDIR, NULL);
+ StringCchPrintfA(str,78,"lang_clean_up%ws",szAppName);
+ if(!readme_only_wlz_extraction){
+ StringCchCopyW(lang_directory, MAX_PATH, TEMPDIR);
+ _w_sW(str, TEMPDIR);
+ }
+
+ if (PathIsFileSpecW(langpack)|| PathIsRelativeW(langpack))
+ PathCombineW(dirmask, LANGDIR, langpack);
+ else
+ StringCchCopyW(dirmask, MAX_PATH*4, langpack);
+
+ // now we're going to extract, if doing a temp extraction then set the path into the passed buffer
+ if(readme_only_wlz_extraction){
+ StringCchCopyW(readme_only_wlz_extraction, MAX_PATH, TEMPDIR);
+ }
+
+ f = unzOpen(AutoCharFn(dirmask));
+ if (f)
+ {
+ if (unzGoToFirstFile(f) == UNZ_OK)
+ {
+ OVERLAPPED asyncIO = {0};
+ int isNT = (GetVersion() < 0x80000000);
+ if (isNT)
+ {
+ asyncIO.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
+ asyncIO.OffsetHigh = 0;
+ }
+ do
+ {
+ char filename[MAX_PATH] = {0}, *fn = 0, *p = 0;
+ if (isNT)
+ SetEvent(asyncIO.hEvent);
+ unzGetCurrentFileInfo(f, NULL, filename, sizeof(filename), NULL, 0, NULL, 0);
+
+ //Only extract the file-types that could be in a skin
+ //If we don't filter here it's a security hole
+
+ // expand out folders if we've got a freeform based folder
+ if(!_strnicmp(filename,"freeform\\",9) || !_strnicmp(filename,"freeform/",9))
+ fn = filename;
+ // otherwise just extract to the root of the temp directory
+ else
+ fn = scanstr_back(filename, "\\/", filename - 1) + 1;
+
+ p = extension(fn);
+ // TODO: really should enum image loaders so we only extract supported image files
+ if (!_stricmp(p, "lng") || !_stricmp(p, "ini") || !_stricmp(p, "txt") ||
+ !_stricmp(p, "png") || !_stricmp(p, "bmp") || !_stricmp(p, "gif") ||
+ !_stricmp(p, "jpg") || !_stricmp(p, "xml") || !_stricmp(p, "htm") ||
+ // not too keen on dll in there but that's how the GN dlls are named
+ !_stricmp(p, "dll"))
+ {
+ if (unzOpenCurrentFile(f) == UNZ_OK)
+ {
+ PathCombineW(dirmask, TEMPDIR, AutoWide(fn));
+ CreateDirectoryForFileW(dirmask, TEMPDIR);
+
+ HANDLE fp = CreateFileW(dirmask, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | (isNT ? FILE_FLAG_OVERLAPPED : 0), NULL);
+ if (fp != INVALID_HANDLE_VALUE)
+ {
+ int l = 0, pos = 0, bufNum=0;
+
+ #define LANG_ZIP_BUFFER_SIZE 2048
+ char buf[LANG_ZIP_BUFFER_SIZE*2] = {0};
+ int success = 1;
+ do
+ {
+ DWORD written = 0;
+ bufNum = !bufNum;
+ l = unzReadCurrentFile(f, buf+LANG_ZIP_BUFFER_SIZE*bufNum, LANG_ZIP_BUFFER_SIZE);
+ if (!l)
+ unzCloseCurrentFile(f);
+ if (isNT)
+ {
+ WaitForSingleObject(asyncIO.hEvent, INFINITE);
+ if (l > 0)
+ {
+ asyncIO.Offset = pos;
+ if (WriteFile(fp, buf+LANG_ZIP_BUFFER_SIZE*bufNum, l, NULL, &asyncIO) == FALSE
+ && GetLastError() != ERROR_IO_PENDING)
+ {
+ success=0;
+ }
+ pos += l;
+ }
+ }
+ else
+ {
+ if (l > 0)
+ {
+ if (WriteFile(fp, buf+LANG_ZIP_BUFFER_SIZE*bufNum, l, &written, NULL) == FALSE)
+ success = 0;
+ }
+ }
+ } while (l > 0 && success);
+
+ CloseHandle(fp);
+
+ // cache information about the extracted lng files
+ if(!_stricmp(p, "lng") && !readme_only_wlz_extraction)
+ {
+ is_wlz = 1;
+ winampLangStruct* templng = reinterpret_cast<winampLangStruct*>(calloc(1, sizeof(winampLangStruct)));
+ templng->module = AutoWideDup(filename);
+
+ bool exception = (!lstrcmpiW(templng->module, L"omBrowser.lng") || !lstrcmpiW(templng->module, L"ml_online.lng"));
+
+ // the plain LoadLibrary(..) generally works though as we only want to
+ // load the lng files for resources (and that some people's lng files
+ // can generally end up being corrupted after a few edits), we instead
+ // try to load as an image / data file (so doesn't re-map things, etc)
+ templng->hDllInstance = LoadLibraryExW(dirmask, NULL, (!exception ? LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE : 0));
+ if (!templng->hDllInstance) templng->hDllInstance = LoadLibraryW(dirmask);
+ if (templng->hDllInstance)
+ {
+ wchar_t s[39] = {0};
+ if(LoadStringW(templng->hDllInstance, LANG_DLL_GUID_STRING_ID, s, 39))
+ {
+ templng->guidstr = _wcsdup(s);
+ GetImageHashData(templng->hDllInstance);
+ }
+ // only keep if it's a valid lng dll ie doesn't have load issues
+ lnglist.push_back(templng);
+ }
+ }
+ }
+ }
+ }
+ }
+ while (unzGoToNextFile(f) == UNZ_OK);
+ if (isNT && asyncIO.hEvent)
+ {
+ CloseHandle(asyncIO.hEvent);
+ }
+ }
+ unzClose(f);
+ }
+ }
+ }
+ else lang_directory[0] = 0;
+
+ return is_wlz;
+}
+
+
+HINSTANCE Language::FindDllHandleByGUID(const GUID guid)
+{
+ wchar_t gs[40] = {0};
+ getGUIDstr(guid,gs);
+
+ for ( winampLangStruct *l_lng : lnglist )
+ {
+ if( l_lng->guidstr && *l_lng->guidstr && !_wcsnicmp(gs, l_lng->guidstr, 38))
+ return l_lng->hDllInstance;
+ }
+
+ return NULL;
+}
+
+
+HINSTANCE Language::FindDllHandleByString(const char* _str)
+{
+ AutoWide str__(_str);
+ const wchar_t *str = str__;
+ if(str && *str)
+ {
+ for ( winampLangStruct *l_lng : lnglist )
+ {
+ if ( l_lng->module && *l_lng->module && !_wcsnicmp( l_lng->module, str, lstrlenW( str ) ) )
+ return l_lng->hDllInstance;
+ }
+ }
+ return NULL;
+}
+
+
+HINSTANCE Language::FindDllHandleByStringW(const wchar_t* _str)
+{
+ AutoChar str__(_str);
+ const wchar_t *str = _str;
+ if(str && *str)
+ {
+ for ( winampLangStruct *l_lng : lnglist )
+ {
+ if( l_lng->module && *l_lng->module && !_wcsnicmp( l_lng->module, str, lstrlenW(str)))
+ return l_lng->hDllInstance;
+ }
+ }
+ return NULL;
+}
+
+
+HINSTANCE Lang_InitLangSupport(HINSTANCE hinst, const GUID guid)
+{
+ geno = _r_i("geno", 1);
+ started = 1;
+ return langManager->StartLanguageSupport(hinst, guid);
+}
+
+
+void Lang_FollowUserDecimalLocale(void)
+{
+ langManager->UseUserNumericLocale();
+}
+
+
+// use this to load based on the module specified so that we make sure
+// we've got the correct hinstance based on lng file or default handle
+HINSTANCE Language::StartLanguageSupport(HINSTANCE hinstance, const GUID guid)
+{
+ if (!g_safeMode)
+ {
+ HWND agent = FindWindowW(L"WinampAgentMain", NULL);
+ wchar_t winampaLngPath[MAX_PATH] = {0};
+ int is_wlz = 0;
+
+ // if we find Winamp Agent running then we need to tell it
+ // to unload it's winampa.lng for what we're about to do..
+ if (IsWindow(agent) && !already_extracted)
+ {
+ SendMessageW(agent, WM_USER + 16, 1, 0);
+ }
+
+ // always remove winampa.lng just incase we crashed and it leaves things out of synch
+ if(!already_extracted){
+ StringCchPrintfW(winampaLngPath, MAX_PATH, L"%s\\winampa.lng", CONFIGDIR);
+ DeleteFileW(winampaLngPath);
+ }
+
+ config_load_langpack_var();
+ if(!already_extracted)
+ {
+ BOOL skip = FALSE;
+ already_extracted = 1;
+ prev_wlz_ex_state = is_wlz = extract_wlz_to_dir(0, &skip);
+ if (!skip) load_extra_lng(FALSE);
+ else LANGTEMPDIR[0] = 0;
+ }
+ else
+ {
+ is_wlz = prev_wlz_ex_state;
+ agent = 0;
+ }
+
+ // make sure that we don't try and load the exe/dll being localised as the lng dll
+ wchar_t modulename[MAX_PATH] = {0}, *p = 0;
+ GetModuleFileNameW(hinstance, modulename, MAX_PATH);
+ p = scanstr_backW(modulename, L"\\/", NULL);
+ if(p) p = CharNextW(p);
+
+ // if is_wlz != 0 then we can attempt to use the wlz extracted files otherwise
+ // (for the time being) we drop back to the older lng pack system
+ // either way we still need to make sure that what we're using is valid
+ if (config_langpack[0] && is_wlz)
+ {
+ HMODULE h = langManager->FindDllHandleByGUID(guid);
+ if(!h) // possible fallback usage if things failed to work on guid look up
+ { // though wouldn't be reliable if people change the lng file names
+ wchar_t tmpfile[MAX_PATH], *t = 0;
+ lstrcpynW(tmpfile,p,MAX_PATH);
+ t = scanstr_backW(tmpfile, L".", NULL);
+ lstrcpynW(t,L".lng",MAX_PATH);
+ h = langManager->FindDllHandleByStringW(tmpfile);
+ }
+
+ if (h)
+ {
+ // if the wlz was able to be loaded (as we believe at this point)
+ // then we see if Winamp Agent is running and tell it to refresh
+ // it's version of winampa.lng once we've copied into %inidir%
+ if (IsWindow(agent))
+ {
+ // copy from the wlz folder to the settings folder
+ wchar_t winampaWlzPath[MAX_PATH] = {0};
+ StringCchPrintfW(winampaWlzPath, MAX_PATH, L"%s\\winampa.lng", lang_directory);
+ CopyFileW(winampaWlzPath,winampaLngPath,FALSE);
+ SendMessageW(agent, WM_USER + 16, 0, 0);
+ }
+
+ // if we get here then we've managed to load the language pack
+ // (still could be invalid but that's generally from failed dll files)
+ return h;
+ }
+ }
+ }
+
+ // make sure we return the passed hinstance incase of failure to load/invalid lng file/etc
+ return hinstance;
+}
+
+
+void Lang_EndLangSupport(void)
+{
+ started = 0;
+
+ // need to fully clean up things here including unloading of the langpack
+ HINSTANCE old_language_pack_instance = language_pack_instance;
+ if(language_pack_instance != hMainInstance)
+ {
+ FreeLibrary(language_pack_instance);
+ language_pack_instance = hMainInstance;
+ }
+
+ for ( winampLangStruct *l_lng : lnglist )
+ {
+ if( l_lng->module)
+ {
+ free( l_lng->module);
+ l_lng->module = 0;
+ }
+
+ if( l_lng->guidstr)
+ {
+ free( l_lng->guidstr);
+ l_lng->guidstr = 0;
+ }
+
+ // this check is to prevent trying to re-free the winamp.lng (as it's done earlier)
+ // as well as anything which is not in the temp folder to avoid any unloading issues
+ if ( !l_lng->external && l_lng->hDllInstance && ( l_lng->hDllInstance != old_language_pack_instance ) )
+ {
+ FreeLibrary( l_lng->hDllInstance );
+ l_lng->hDllInstance = 0;
+ }
+ }
+
+ lnglist.clear();
+ prev_wlz_ex_state = already_extracted = 0;
+}
+
+
+HINSTANCE Lang_FakeWinampLangHInst(HINSTANCE adjustedHInst){
+ HINSTANCE previousHInst = language_pack_instance;
+ language_pack_instance = adjustedHInst;
+ started = !!adjustedHInst;
+ return previousHInst;
+}
+
+
+void Lang_LocaliseAgentOnTheFly(BOOL refresh){
+ // if we need to refresh then attempt to use the winampa.lng from the
+ // current language pack if one is present and has been extracted so
+ // we test to see if we've extracted a language pack already
+ if(already_extracted){
+ HWND agent = FindWindowW(L"WinampAgentMain", NULL);
+ wchar_t winampaLngPath[MAX_PATH] = {0};
+
+ // if we find Winamp Agent running then we need to tell it
+ // to unload it's winampa.lng for what we're about to do...
+ // although this is likely to be a new load, doing this will
+ // help to ensure that things are unloaded incase of issues
+ if(IsWindow(agent)){
+ SendMessageW(agent, WM_USER + 16, 1, 0);
+ }
+
+ // always remove winampa.lng just incase we crashed and it leaves things out of synch
+ StringCchPrintfW(winampaLngPath, MAX_PATH, L"%s\\winampa.lng", CONFIGDIR);
+ DeleteFileW(winampaLngPath);
+
+ if(refresh){
+ wchar_t winampaWlzPath[MAX_PATH] = {0};
+ StringCchPrintfW(winampaWlzPath, MAX_PATH, L"%s\\winampa.lng", lang_directory);
+ CopyFileW(winampaWlzPath,winampaLngPath,FALSE);
+ SendMessageW(agent, WM_USER + 16, 0, 0);
+ }
+ }
+}
+
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS Language
+START_DISPATCH;
+CB( API_LANGUAGE_GETSTRING, GetString )
+CB( API_LANGUAGE_GETSTRINGW, GetStringW )
+CB( API_LANGUAGE_GETSTRINGFROMGUID, GetStringFromGUID )
+CB( API_LANGUAGE_GETSTRINGFROMGUIDW, GetStringFromGUIDW )
+CB( API_LANGUAGE_GETHINSTANCEBYGUID, FindDllHandleByGUID )
+CB( API_LANGUAGE_GETHINSTANCEBYNAME, FindDllHandleByString )
+CB( API_LANGUAGE_GETHINSTANCEBYNAMEW, FindDllHandleByStringW )
+CB( API_LANGUAGE_STARTUP, StartLanguageSupport )
+CB( API_LANGUAGE_GETLANGUAGEFOLDER, GetLanguageFolder )
+CB( API_LANGUAGE_CREATELDIALOGPARAM, CreateLDialogParam )
+CB( API_LANGUAGE_LDIALOGBOXPARAM, LDialogBoxParam )
+CB( API_LANGUAGE_LOADLMENU, LoadLMenu )
+CB( API_LANGUAGE_CREATELDIALOGPARAMW, CreateLDialogParamW )
+CB( API_LANGUAGE_LDIALOGBOXPARAMW, LDialogBoxParamW )
+CB( API_LANGUAGE_LOADLMENUW, LoadLMenuW )
+CB( API_LANGUAGE_GETLANGUAGEIDENTIFIER, GetLanguageIdentifier )
+CB( API_LANGUAGE_LOADRESOURCEFROMFILEA, LoadResourceFromFile )
+CB( API_LANGUAGE_LOADRESOURCEFROMFILEW, LoadResourceFromFileW )
+CB( API_LANGUAGE_LOADACCELERATORSA, LoadAcceleratorsA )
+CB( API_LANGUAGE_LOADACCELERATORSW, LoadAcceleratorsW )
+CB( API_LANGUAGE_USEUSERNUMERICLOCALE, UseUserNumericLocale )
+CB( API_LANGUAGE_GET_C_NUMERICLOCALE, Get_C_NumericLocale )
+CB( API_LANGUAGE_FORMATTEDSIZESTRING, FormattedSizeString )
+END_DISPATCH \ No newline at end of file
diff --git a/Src/Winamp/language.h b/Src/Winamp/language.h
new file mode 100644
index 00000000..43d1d39f
--- /dev/null
+++ b/Src/Winamp/language.h
@@ -0,0 +1,54 @@
+#ifndef NULLSOFT_WINAMP_LANGUAGE_H
+#define NULLSOFT_WINAMP_LANGUAGE_H
+
+#include "../Agave/Language/api_language.h"
+
+class Language : public api_language
+{
+public:
+ static const char *getServiceName() { return "Language API"; }
+ static const GUID getServiceGuid() { return languageApiGUID; }
+public:
+ char *GetString(HINSTANCE hinst, HINSTANCE owner, UINT uID, char *str=NULL, size_t maxlen=0);
+ wchar_t *GetStringW(HINSTANCE hinst, HINSTANCE owner, UINT uID, wchar_t *str=NULL, size_t maxlen=0);
+ char *GetStringFromGUID(const GUID guid, HINSTANCE owner, UINT uID, char *str=NULL, size_t maxlen=0);
+ wchar_t *GetStringFromGUIDW(const GUID guid, HINSTANCE owner, UINT uID, wchar_t *str=NULL, size_t maxlen=0);
+
+ HINSTANCE FindDllHandleByGUID(const GUID guid);
+ HINSTANCE FindDllHandleByString(const char* str);
+ HINSTANCE FindDllHandleByStringW(const wchar_t* str);
+ HINSTANCE StartLanguageSupport(HINSTANCE hinstance, const GUID guid);
+
+ const wchar_t *GetLanguageFolder();
+
+ const wchar_t *GetLanguageIdentifier(int mode);
+
+ HWND CreateLDialogParam(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param);
+ HWND CreateLDialogParamW(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param);
+
+ INT_PTR LDialogBoxParam(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param);
+ INT_PTR LDialogBoxParamW(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param);
+
+ HMENU LoadLMenu(HINSTANCE localised, HINSTANCE original, UINT id);
+ HMENU LoadLMenuW(HINSTANCE localised, HINSTANCE original, UINT id);
+
+ HACCEL LoadAcceleratorsA(HINSTANCE hinst, HINSTANCE owner, LPCSTR lpTableName);
+ HACCEL LoadAcceleratorsW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpTableName);
+
+ void* LoadResourceFromFile(HINSTANCE hinst, HINSTANCE owner, LPCTSTR lpType, LPCTSTR lpName, DWORD* size);
+ void* LoadResourceFromFileW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpType, LPCWSTR lpName, DWORD* size);
+
+ BOOL UseUserNumericLocale();
+ _locale_t Get_C_NumericLocale();
+
+ wchar_t* FormattedSizeString(wchar_t *out, int cchLen, __int64 size);
+
+protected:
+ RECVS_DISPATCH;
+};
+
+extern Language *langManager;
+
+#define LANG_STATIC_BUFFER_SIZE 1024
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/linklist.cpp b/Src/Winamp/linklist.cpp
new file mode 100644
index 00000000..6416f773
--- /dev/null
+++ b/Src/Winamp/linklist.cpp
@@ -0,0 +1,94 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+
+
+
+#if 0
+void ll_update(HWND hwndDlg)
+{
+ char TEMPFILE2[MAX_PATH] = {0};
+ char buf[1024] = {0};
+ int success=0;
+ lstrcpyn(TEMPFILE2,TEMP_FILE, MAX_PATH-1); // -1 because we strcat a "0"
+
+ lstrcat(TEMPFILE2,"0");
+ {
+ char url[512] = {0};
+ int c='y',r='n';
+ {
+ FILE *fp = fopen(LINKFILE,"rt");
+ if (fp)
+ {
+ fclose(fp);
+ c='n';
+ }
+ }
+ wsprintf(url,"http://client.winamp.com/update/updatelinks.jhtml?i=%c&v=%s&r=%c",
+ c,
+ app_version,r);
+ if (!httpRetrieveFile(hwndDlg,url,TEMPFILE2,getString(IDS_DLINK_GETTING,NULL,0)))
+ {
+ int st=0;
+ FILE *fp = fopen(TEMPFILE2,"rt");
+ char bnav[1024]="";
+ char d_bloc[128]="DefBrowseLoc";
+ if (*config_browserbrand)
+ {
+ lstrcat(d_bloc,"_");
+ lstrcat(d_bloc,config_browserbrand);
+ }
+ lstrcat(d_bloc," ");
+ if (fp)
+ {
+ while (!feof(fp))
+ {
+ fgets(buf,sizeof(buf),fp);
+ if (!strcmp(buf,"Winamp Links File v1.0\n")) st|=1;
+ if (!strncmp(buf,"EndFile",7)) st|=2;
+ if (!_strnicmp(buf,d_bloc,lstrlen(d_bloc)))
+ {
+ lstrcpyn(bnav, buf+lstrlen(d_bloc), 1024);
+ }
+ }
+ fclose(fp);
+ }
+ if (st==3)
+ {
+ DeleteFile(LINKFILE);
+ MoveFile(TEMPFILE2,LINKFILE);
+ success=1;
+ }
+ if (success)
+ {
+ char str[256]="";
+ char *s="http://client.winamp.com/update/mb.html";
+ GetPrivateProfileString("Winamp","MBDefLoc",s,str,sizeof(str),INI_FILE);
+ if (_strnicmp(str,"http://",7)) lstrcpy(str,s);
+ httpRetrieveFile(hwndDlg,str,MBFILE,getString(IDS_DLINK_GETTING,NULL,0));
+
+ if (strcmp(str,s)) mbctl_navigate(str,str);
+ else if (isInetAvailable())
+ {
+ char *t;
+ if (bnav[0] && (t=strstr(bnav," ")))
+ {
+ *t++=0;
+ mbctl_navigate(bnav,t);
+ }
+ else mbctl_navigate("http://client.winamp.com/browser/","Winamp Minibrowser");
+ }
+ else mbctl_navigate(MBFILE,"Winamp Minibrowser");
+ }
+ }
+ DeleteFile(TEMPFILE2);
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/main.cpp b/Src/Winamp/main.cpp
new file mode 100644
index 00000000..b92dda2d
--- /dev/null
+++ b/Src/Winamp/main.cpp
@@ -0,0 +1,1892 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename: main.cpp
+ ** Project: Winamp
+ ** Description: Winamp initialization code
+ ** Author: Justin Frankel
+ ** Created: April 1997
+ **/
+
+#include "main.h"
+#include <windowsx.h>
+
+#include "../Agave/Language/lang.h"
+#include <stdarg.h>
+#include "vis.h"
+#include "fft.h"
+#include "gen.h"
+#include "../nu/ns_wc.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "menuv5.h"
+#include "../Plugins/General/gen_ml/ml.h"
+#include "wa_dlg.h"
+#include "strutil.h"
+#include "./setup/setupfactory.h"
+#include "./commandLink.h"
+#include "AppRefCount.h"
+#include <unknwn.h>
+#include <shlwapi.h>
+#include <shobjidl.h>
+
+#include "WAT/WAT.h"
+
+#ifndef WM_DWMSENDICONICTHUMBNAIL
+#define WM_DWMSENDICONICTHUMBNAIL 0x0323
+#endif
+#include "Agave/Language/api_language.h"
+
+#ifndef WM_DWMSENDICONICLIVEPREVIEWBITMAP
+#define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326
+#endif
+
+#ifndef THBN_CLICKED
+#define THBN_CLICKED 0x1800
+#endif
+
+typedef HRESULT( WINAPI *CHANGEWINDOWMESSAGEFILTER )( UINT message, DWORD dwFlag );
+static HMODULE user32Lib = 0;
+static CHANGEWINDOWMESSAGEFILTER changeWMFilter;
+static BOOL changeWMLoadTried = FALSE;
+
+//#define BENSKI_TEST_WM_PRINTCLIENT
+static UINT WM_TASKBARCREATED;
+static UINT WM_TASKBARBUTTONCREATED;
+
+LARGE_INTEGER freq;
+UINT g_scrollMsg;
+UINT songChangeBroadcastMessage = 0;
+int g_noreg;
+int disable_skin_borders = 0;
+int no_notify_play = 0;
+int last_no_notify_play = 0;
+int main_delta_carryover = 0;
+int g_restartonquit = 0;
+char g_audiocdletter[ 4 ] = { 0 };
+int g_audiocdletters = 0;
+const char app_name[] = "Winamp", app_version[] = APP_VERSION, app_version_string[] = APP_VERSION_STRING; // application name and version strings
+int g_fullstop;
+char *app_date = __DATE__;
+int g_stopaftercur;
+int is_install;
+HWND hTooltipWindow, hEQTooltipWindow, hVideoTooltipWindow, hPLTooltipWindow;
+HWND hMainWindow = NULL; // main window
+HWND hEQWindow, hPLWindow, /*hMBWindow, */hVideoWindow, hExternalVisWindow = NULL;
+
+HWND g_dialog_box_parent = NULL; // used by IPC_SETDIALOGBOXPARENT (FG, 5/19/03)
+HINSTANCE language_pack_instance;
+HINSTANCE hMainInstance; // program instance
+HANDLE hMainThread; // main thread handle
+DWORD mainThreadId; // main thread ID
+HMENU main_menu = 0, top_menu = 0, g_submenus_bookmarks1 = 0,
+g_submenus_bookmarks2 = 0, g_submenus_skins1 = 0,
+g_submenus_skins2 = 0, g_submenus_vis = 0,
+g_submenus_options = 0, g_submenus_lang = 0,
+g_submenus_play = 0;
+
+int g_submenus_lang_id = 0;
+int g_video_numaudiotracks = 1;
+int g_video_curaudiotrack = 0;
+
+int bStartPlaying = 0;
+int paused = 0;
+int playing = 0;
+wchar_t caption[ CAPTION_SIZE ] = { 0 }; // current program caption
+wchar_t FileName[ FILENAME_SIZE ] = { 0 }; // current file name
+wchar_t FileTitle[ FILETITLE_SIZE ] = { 0 }; // current file title
+wchar_t FileTitleNum[ FILETITLE_SIZE ] = { 0 }; // current file title + track position
+int eggstat = 0; // used for easter eggs
+int g_srate, g_brate, g_nch, g_srate_exact;
+int last_brate = -1;
+int g_need_titleupd = 0;
+int g_need_infoupd = 0;
+int g_SkinTop, g_BookmarkTop, g_LangTop;
+int g_mm_optionsbase_adj = 0; //used by IPC_ADJUST_OPTIONSMENUPOS
+int g_mm_ffwindowsbase_adj = 0; //used by IPC_ADJUST_FFWINDOWSMENUPOS
+int g_mm_ffoptionsbase_adj = 0; //used by IPC_ADJUST_FFOPTIONSMENUPOS
+int g_has_video_plugin = 0;
+int g_no_video_loaded = 0; //filled in by in_init
+
+char playlist_custom_font[ 128 ] = { 0 };
+wchar_t playlist_custom_fontW[ 128 ] = { 0 };
+int config_custom_plfont = 1;
+int disable_skin_cursors = 0;
+int vis_fullscreen = 0;
+
+struct ITaskbarList3 *pTaskbar3 = NULL;
+
+static LRESULT Main_OnSysCommand( HWND hwnd, UINT cmd, int x, int y );
+
+HWND find_otherwinamp( wchar_t * );
+
+#undef HANDLE_WM_NCACTIVATE
+#define HANDLE_WM_NCACTIVATE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (BOOL)(wParam), (HWND)(lParam), 0L)
+
+int stat_isit = 1; // used for faster version checkig
+wchar_t szAppName[ 64 ] = { 0 }; // window class name, generated on the fly.
+
+EXTERN_C BOOL eggTyping = FALSE;
+static char eggstr[] = "NULLSOFT";
+
+UINT USER_CONSENT_EVENT_ID = 123456;
+
+int g_exit_disabled = 0;
+int g_safeMode = 0;
+HANDLE g_hEventRunning;
+int bNoHwndOther = 0;
+
+static void CreateEQPresets()
+{
+ if ( !PathFileExistsW( EQDIR1 ) )
+ {
+ int x;
+ struct
+ {
+ char *s;
+ unsigned char tab[ 10 ];
+ }
+ eqsets[] =
+ {
+ {"Classical", {31, 31, 31, 31, 31, 31, 44, 44, 44, 48}},
+ {"Club", {31, 31, 26, 22, 22, 22, 26, 31, 31, 31}},
+ {"Dance", {16, 20, 28, 32, 32, 42, 44, 44, 32, 32}},
+ {"Flat", {31, 31, 31, 31, 31, 31, 31, 31, 31, 31}},
+ {"Laptop speakers/headphones", {24, 14, 23, 38, 36, 29, 24, 16, 11, 8}},
+ {"Large hall", {15, 15, 22, 22, 31, 40, 40, 40, 31, 31}},
+ {"Party", {20, 20, 31, 31, 31, 31, 31, 31, 20, 20}},
+ {"Pop", {35, 24, 20, 19, 23, 34, 36, 36, 35, 35}},
+ {"Reggae", {31, 31, 33, 42, 31, 21, 21, 31, 31, 31}},
+ {"Rock", {19, 24, 41, 45, 38, 25, 17, 14, 14, 14}},
+ {"Soft", {24, 29, 34, 36, 34, 25, 18, 16, 14, 12}},
+ {"Ska", {36, 40, 39, 33, 25, 22, 17, 16, 14, 16}},
+ {"Full Bass", {16, 16, 16, 22, 29, 39, 46, 49, 50, 50}},
+ {"Soft Rock", {25, 25, 28, 33, 39, 41, 38, 33, 27, 17}},
+ {"Full Treble", {48, 48, 48, 39, 27, 14, 6, 6, 6, 4}},
+ {"Full Bass & Treble", {20, 22, 31, 44, 40, 29, 18, 14, 12, 12}},
+ {"Live", {40, 31, 25, 23, 22, 22, 25, 27, 27, 28}},
+ {"Techno", {19, 22, 31, 41, 40, 31, 19, 16, 16, 17}},
+ };
+
+ for ( x = 0; x < sizeof( eqsets ) / sizeof( eqsets[ 0 ] ); x++ )
+ writeEQfile_init( EQDIR1, eqsets[ x ].s, eqsets[ x ].tab );
+ }
+}
+
+void BuildAppName()
+{
+ StringCchCopyW( szAppName, 64, L"Winamp v1.x" );
+ StringCchPrintfW( caption, CAPTION_SIZE, L"%S %S", app_name, app_version_string );
+}
+
+static void CALLBACK DisplayUserConsentMessageBox( HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD time )
+{
+ KillTimer( hMainWindow, USER_CONSENT_EVENT_ID );
+ if ( config_user_consent_join_channels != -1 )
+ {
+ return;
+ }
+
+ wchar_t titleStr[ 32 ] = { 0 };
+ int msgboxID = MessageBoxW(
+ NULL,
+ WASABI_API_LNGSTRINGW( IDS_RC_CHANNEL_MESSAGE ),
+ WASABI_API_LNGSTRINGW_BUF( IDS_RC_CHANNEL_TITLE, titleStr, 32 ),
+ MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1
+ );
+
+ switch ( msgboxID )
+ {
+ case IDYES:
+ config_user_consent_join_channels = 1;
+ config_newverchk_rc = 1;
+ config_newverchk = 1;
+ break;
+ case IDNO:
+ config_user_consent_join_channels = 0;
+ config_newverchk_rc = 0;
+ config_newverchk = 1;
+ break;
+ }
+}
+
+// creates (but does not show) main window
+int CreateMainWindow()
+{
+ if ( !IsWindow( hMainWindow ) )
+ {
+ WNDCLASSW wcW = { 0 };
+
+ wcW.style = CS_DBLCLKS;
+ wcW.lpfnWndProc = Main_WndProc;
+ wcW.hInstance = hMainInstance;
+ wcW.hIcon = LoadIconW( hMainInstance, MAKEINTRESOURCE( ICON_XP ) );
+ wcW.hCursor = NULL;
+ wcW.lpszClassName = szAppName;
+
+ if ( !RegisterClassW( &wcW ) )
+ return 0;
+
+ if ( !CreateWindowExW( WS_EX_ACCEPTFILES, szAppName, L"Winamp", WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_BORDER | WS_CAPTION,
+ config_wx, config_wy, 0, 0, // WM_CREATE will size it
+ NULL, NULL, hMainInstance, NULL ) )
+ {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+wchar_t *getGUIDstr( const GUID guid, wchar_t *target )
+{
+ StringCchPrintfW( target, 40, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\0",
+ (int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
+ (int)guid.Data4[ 0 ], (int)guid.Data4[ 1 ], (int)guid.Data4[ 2 ], (int)guid.Data4[ 3 ],
+ (int)guid.Data4[ 4 ], (int)guid.Data4[ 5 ], (int)guid.Data4[ 6 ], (int)guid.Data4[ 7 ] );
+ return target;
+}
+
+BOOL parseMessageCommands( HWND hwnd_other, int bCommand, int bCmdParam )
+{
+ if ( LOWORD( bCommand ) ) // attempt to send the action to it
+ {
+ if ( HIWORD( bCommand ) == 1 )
+ {
+ SendMessageW( hwnd_other, WM_WA_IPC, bCmdParam, MAKELPARAM( LOWORD( bCommand ), 0 ) );
+ return TRUE;
+ }
+ else if ( HIWORD( bCommand ) == 2 )
+ {
+ // these need some additional processing which is easier to do once we're loaded
+ if ( LOWORD( bCommand ) == EQ_PANLEFT || LOWORD( bCommand ) == EQ_PANRIGHT ||
+ LOWORD( bCommand ) == IPC_SETPANNING )
+ {
+ int pan = IPC_GETPANNING( hwnd_other );
+ if ( LOWORD( bCommand ) == EQ_PANLEFT ) pan -= 12;
+ else if ( LOWORD( bCommand ) == EQ_PANRIGHT ) pan += 12;
+ else pan = bCmdParam;
+
+ if ( pan < -127 ) pan = -127;
+ if ( pan > 127 ) pan = 127;
+
+ SendMessageW( hwnd_other, WM_WA_IPC, pan, IPC_SETPANNING );
+ }
+ else if ( LOWORD( bCommand ) == IPC_ISPLAYING )
+ {
+ int command = SendMessageW( hwnd_other, WM_WA_IPC, 0, IPC_ISPLAYING );
+ switch ( command )
+ {
+ case 1: // playing so need to pause
+ command = WINAMP_BUTTON3;
+ break;
+ default: // stopped so start playing
+ command = WINAMP_BUTTON2;
+ break;
+ }
+ SendMessageW( hwnd_other, WM_COMMAND, command, 0 );
+ }
+ return TRUE;
+ }
+ else
+ {
+ SendMessageW( hwnd_other, WM_COMMAND, bCommand, 0 );
+
+ if ( LOWORD( bCommand ) == WINAMP_JUMPFILE )
+ {
+ // TODO need to make this locale independant...
+ HWND jumpWnd = FindWindowW( NULL, L"Jump to file" );
+ if ( IsWindow( jumpWnd ) )
+ {
+ SetForegroundWindow( jumpWnd );
+ }
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static int PassToOtherWinamp( wchar_t *lpszCmdParam, HWND hwnd_other, int bAdd, int bBookmark, int bHandle, int bCommand, int bCmdParam )
+{
+ // if we have command line params, pass to other winamp window
+ if ( lpszCmdParam && *lpszCmdParam )
+ {
+ int skinExit = 0;
+ int bC = 0;
+ HANDLE hSem = NULL;
+ HINSTANCE existingWLZ = 0, templng = 0;
+ DWORD_PTR vn = 0;
+
+ // check if we're using a language pack with the already open winamp process
+ // and if so then we're going to use the winamp.lng from it on the messagebox
+ // only if we had a success and the other winamp returned the correct value
+ // within the timeout period (can't be having it lock up so revert if needed)
+ if ( SendMessageTimeout( hwnd_other, WM_WA_IPC, 1, IPC_GETLANGUAGEPACKINSTANCE, SMTO_NORMAL, 5000, &vn ) && !vn )
+ {
+ DWORD processid = 0;
+ HANDLE hwaProcess = NULL;
+ SIZE_T bread = 0;
+ wchar_t lng_path_copy[ MAX_PATH ] = { 0 }, dirmask[ MAX_PATH ] = { 0 }, gs[ 40 ] = { 0 };
+ WIN32_FIND_DATAW d = { 0 };
+
+ GetWindowThreadProcessId( hwnd_other, &processid );
+ hwaProcess = OpenProcess( PROCESS_VM_READ, FALSE, processid );
+ ReadProcessMemory( hwaProcess, (wchar_t *)SendMessageW( hwnd_other, WM_WA_IPC, 3, IPC_GETLANGUAGEPACKINSTANCE ), lng_path_copy, MAX_PATH, &bread );
+ CloseHandle( hwaProcess );
+
+ getGUIDstr( WinampLangGUID, gs );
+ PathCombineW( dirmask, lng_path_copy, L"*.lng" );
+ HANDLE h = FindFirstFileW( dirmask, &d );
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ PathCombineW( dirmask, lng_path_copy, d.cFileName );
+ templng = LoadLibraryExW( dirmask, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE );
+ if ( !templng ) templng = LoadLibraryW( dirmask );
+ if ( templng )
+ {
+ wchar_t s[ 39 ] = { 0 };
+ if ( LoadStringW( templng, LANG_DLL_GUID_STRING_ID, s, 39 ) )
+ {
+ if ( !_wcsnicmp( gs, s, 38 ) )
+ {
+ existingWLZ = Lang_FakeWinampLangHInst( templng );
+ }
+ else
+ FreeLibrary( templng );
+ }
+ else
+ FreeLibrary( templng );
+ }
+ } while ( FindNextFileW( h, &d ) );
+ FindClose( h );
+ }
+ }
+
+ lpszCmdParam = CheckSkin( lpszCmdParam, hwnd_other, &skinExit );
+ if ( skinExit )
+ {
+ // restore the language pack settings now that we've done the override and clean up as needed
+ if ( existingWLZ )
+ {
+ Lang_FakeWinampLangHInst( existingWLZ );
+ FreeLibrary( templng );
+ }
+ return TRUE;
+ }
+
+ skinExit = 0;
+ lpszCmdParam = CheckLang( lpszCmdParam, hwnd_other, &skinExit );
+ // restore the language pack settings now that we've done the override and clean up as needed
+ if ( existingWLZ )
+ {
+ Lang_FakeWinampLangHInst( existingWLZ );
+ FreeLibrary( templng );
+ }
+
+ if ( skinExit )
+ return TRUE;
+
+ hSem = CreateSemaphoreA( 0, 0, 65535, "WinampExplorerHack1" );
+
+ if ( hSem && GetLastError() != ERROR_ALREADY_EXISTS )
+ {
+ bC = 1;
+ if ( !bAdd && !bBookmark && !bHandle )
+ {
+ SendMessageW( hwnd_other, WM_WA_IPC, 0, IPC_DELETE_INT );
+ }
+ }
+ if ( hSem )
+ {
+ ReleaseSemaphore( hSem, 1, NULL );
+ if ( bBookmark )
+ {
+ static wchar_t tmp[ MAX_PATH ];
+ StringCchPrintfW( tmp, MAX_PATH, L"/BOOKMARK %s", lpszCmdParam );
+ lpszCmdParam = tmp;
+ }
+ else if ( bHandle )
+ {
+ static wchar_t tmp[ MAX_PATH ];
+ StringCchPrintfW( tmp, MAX_PATH, L"/HANDLE %s", lpszCmdParam );
+ lpszCmdParam = tmp;
+ }
+ parseCmdLine( lpszCmdParam, hwnd_other );
+
+ WaitForSingleObject( hSem, 5000 );
+ if ( bC )
+ {
+ int n = 500;
+ if ( !bAdd && !bBookmark && !bHandle ) SendMessageW( hwnd_other, WM_WA_IPC, 0, IPC_STARTPLAY_INT );
+ Sleep( 200 );
+ for ( ;;)
+ {
+ if ( WaitForSingleObject( hSem, 100 ) == WAIT_TIMEOUT )
+ {
+ if ( WaitForSingleObject( hSem, 900 ) == WAIT_TIMEOUT )
+ {
+ break;
+ }
+ else
+ {
+ ReleaseSemaphore( hSem, 1, NULL );
+ n--;
+ }
+ }
+ else
+ {
+ ReleaseSemaphore( hSem, 1, NULL );
+ Sleep( 100 );
+ n--;
+ }
+ }
+ }
+ CloseHandle( hSem );
+ }
+ }
+ else
+ {
+ if ( !parseMessageCommands( hwnd_other, bCommand, bCmdParam ) )
+ {
+ ShowWindow( hwnd_other, SW_RESTORE );
+ SetForegroundWindow( hwnd_other );
+ }
+ }
+ return TRUE;
+}
+
+DWORD CALLBACK MainThread( LPVOID param );
+extern wchar_t vidoutbuf_save[ 1024 ];
+static LPWSTR lpszCmdParam = 0;
+static int bAdd = 0, bBookmark = 0,
+bHandle = 0, bCommand = 0,
+bCmdParam = 0, bAllowCompat = 0;
+
+void ShowSafeModeMessage( int mode )
+{
+ if ( g_safeMode && ( g_safeMode != 3 ) )
+ {
+ wchar_t title[ 256 ] = { 0 }, message[ 512 ] = { 0 };
+ MSGBOXPARAMSW msgbx = { sizeof( MSGBOXPARAMSW ),0 };
+ if ( !mode )
+ {
+ msgbx.lpszText = getStringW( ( g_safeMode == 2 ? IDS_SAFE_MODE_ALL : IDS_SAFE_MODE_NORMAL ), message, 512 );
+ msgbx.lpszCaption = getStringW( IDS_START_SAFE_MODE, title, 256 );
+ }
+ else
+ {
+ msgbx.lpszText = getStringW( IDS_FAILED_SAFE_MODE_MSG, message, 512 );
+ msgbx.lpszCaption = getStringW( IDS_FAILED_SAFE_MODE, title, 256 );
+ }
+ msgbx.lpszIcon = MAKEINTRESOURCEW( 102 );
+ msgbx.hInstance = hMainInstance;
+ msgbx.dwStyle = MB_USERICON;
+ MessageBoxIndirectW( &msgbx );
+ }
+}
+
+#ifdef BETA
+time_t inline get_compile_time( char const *time )
+{
+ char s_month[ 5 ] = { 0 };
+ int day = 0, year = 0;
+ struct tm t = { 0 };
+ static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+ sscanf( time, "%s %d %d", s_month, &day, &year );
+
+ t.tm_mon = ( ( strstr( month_names, s_month ) - month_names ) / 3 );
+ t.tm_mday = day;
+ t.tm_year = year - 1900;
+ t.tm_isdst = -1;
+
+ return mktime( &t );
+}
+#endif
+
+int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR unused /*lpszCmdParam*/, int nCmdShow )
+{
+ INITCOMMONCONTROLSEX icex = { sizeof( icex ), ICC_WIN95_CLASSES | ICC_DATE_CLASSES };
+ InitCommonControlsEx( &icex );
+ QueryPerformanceFrequency( &freq );
+
+#if 0
+#ifdef BETA
+ // gives ~4 weeks from a build compile to when it'll show this (should be enough time)
+ time_t now = time( 0 ), compile = get_compile_time( app_date );
+ struct tm *tn = localtime( &now );
+ tn->tm_sec = tn->tm_min = tn->tm_hour = 0;
+ now = mktime( tn );
+
+ if ( ( now - compile ) >= 2678400 )
+ {
+ /* Skip the executable name in the commandline */
+ /* and check for /UNREG which we will allow so */
+ /* an expired beta can be uninstalled properly */
+ lpszCmdParam = GetCommandLineW();
+ lpszCmdParam = FindNextCommand( lpszCmdParam );
+ ParseParametersExpired( lpszCmdParam );
+
+ MSGBOXPARAMSW msgbx = {
+ sizeof( MSGBOXPARAMSW ),
+ 0,
+ GetModuleHandle( NULL ),
+ L"This beta version of Winamp is now over 4 weeks old.\n\n"
+ L"Please update to the latest Winamp version available.",
+ L"Winamp Beta Expired",
+ MB_USERICON,
+ MAKEINTRESOURCEW( 102 ),
+ 0, 0, 0
+ };
+ MessageBoxIndirectW( &msgbx );
+ ShellExecuteW( NULL, L"open", L"http://www.winamp.com/media-player", NULL, NULL, SW_SHOWNORMAL );
+ return 0;
+ }
+#endif
+#endif
+
+ DWORD threadId = 0, res = 0;
+ HANDLE mainThread = nullptr;
+ int cmdShow = nCmdShow;
+
+ /*void *refCounter = */InitAppRefCounterObject( GetCurrentThreadId() );
+ //SHSetInstanceExplorer((IUnknown *)refCounter);
+
+ SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );
+
+ // don't load from working directory !!!!!
+ // requires XP SP3+
+ SetDllDirectoryW( L"" );
+
+ GetModuleFileNameW( NULL, SHAREDDIR, MAX_PATH );
+ PathRemoveFileSpecW( SHAREDDIR );
+ PathAppendW( SHAREDDIR, L"Shared" );
+ // load supporting dlls from the Winamp\Shared directory
+ SetDllDirectoryW( SHAREDDIR );
+
+ hMainInstance = hInstance;
+
+ /* Skip the executable name in the commandline */
+ lpszCmdParam = GetCommandLineW();
+ lpszCmdParam = FindNextCommand( lpszCmdParam );
+
+ BuildAppName();
+
+ init_config();
+ LoadPathsIni();
+ lpszCmdParam = ParseParameters( lpszCmdParam, &bAdd, &bBookmark, &bHandle, &cmdShow, &bCommand, &bCmdParam, &bAllowCompat );
+
+ setup_config();
+
+ // ensure we've got things set up as needed for safe mode being always on so we
+ // don't incorrectly prompt about entering it from using IPC_RESTARTSAFEWINAMP.
+ int mode = _r_i( "allowcompat", 0 );
+ if ( mode ) bAllowCompat = 1;
+
+ if ( !bAllowCompat && read_compatmode() )
+ {
+ MSGBOXPARAMSW msgbx = {
+ sizeof( MSGBOXPARAMSW ),
+ 0,
+ GetModuleHandle( NULL ),
+ L"Winamp appears to have been started with Windows program compatibility mode enabled.\n\n"
+ L"This is not a recommended way to run Winamp as it can often cause problems with how Winamp works e.g. causing it to randomly crash."
+ L"\n\n\nAre you sure you want to continue to run Winamp like this?\n\n\n"
+ L"If you choose 'No', you can disable this by right-clicking winamp.exe, choosing 'Properties' and selecting the 'Compatibility' tab, "
+ L"followed by unchecking 'Run this program in compatibility mode for:' and run Winamp again.",
+ L"Winamp",
+ MB_USERICON | MB_YESNO | MB_DEFBUTTON2,
+ MAKEINTRESOURCEW( 102 ),
+ 0, 0, 0
+ };
+ if ( MessageBoxIndirectW( &msgbx ) == IDNO )
+ {
+ return 0;
+ }
+ }
+
+
+ CoInitializeEx( 0, COINIT_MULTITHREADED );
+
+ // ensure we've got things set up as needed for safe mode being always on so we
+ // don't incorrectly prompt about entering it from using IPC_RESTARTSAFEWINAMP.
+ mode = _r_i( "safemode", 0 );
+ if ( mode ) g_safeMode = 3;
+
+ if ( 0 == ( 128 & is_install ) )
+ {
+ HWND hwnd_other = find_otherwinamp( lpszCmdParam );
+ if ( IsWindow( hwnd_other ) )
+ {
+ // unable to start safe mode so inform the user
+ ShowSafeModeMessage( 1 );
+ int x = PassToOtherWinamp( lpszCmdParam, hwnd_other, bAdd, bBookmark, bHandle, bCommand, bCmdParam );
+ CoUninitialize();
+ return x;
+ }
+ }
+
+ // unable to start safe mode so inform the user
+ ShowSafeModeMessage( 0 );
+
+ mainThread = CreateThread( 0, 0, MainThread, (LPVOID)cmdShow, 0, &threadId );
+
+ while ( !AppRefCount_CanQuit() )
+ {
+ DWORD dwStatus = MsgWaitForMultipleObjectsEx( 1, &mainThread, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE );
+ if ( dwStatus == WAIT_OBJECT_0 + 1 )
+ {
+ MSG msg;
+ while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
+ {
+ if ( msg.message == WM_QUIT )
+ return msg.wParam;
+ DispatchMessage( &msg );
+ }
+ }
+ else if ( dwStatus == WAIT_OBJECT_0 )
+ {
+ GetExitCodeThread( mainThread, &res );
+ CloseHandle( mainThread );
+ AppRefCount_Release();
+ }
+ }
+ return 0;
+}
+
+static BOOL LoadWMFilter()
+{
+ if ( !changeWMLoadTried )
+ {
+ user32Lib = LoadLibraryA( "user32.dll" );
+ if ( user32Lib )
+ changeWMFilter = (CHANGEWINDOWMESSAGEFILTER)GetProcAddress( user32Lib, "ChangeWindowMessageFilter" );
+
+ changeWMLoadTried = TRUE;
+ }
+
+ return user32Lib && changeWMFilter;
+}
+
+VOID CALLBACK PrefsShowProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
+{
+ KillTimer( hwnd, idEvent );
+
+ if ( IsWindow( prefs_hwnd ) )
+ SetForegroundWindow( prefs_hwnd );
+}
+
+void load_gen_crasher()
+{
+ // this will load gen_crasher.dll as applicable (included in beta builds but not release mode by default)
+ // with extra checks to ensure it's 'valid' (as can be) so we could drop it into release builds as needed
+ wchar_t crasherDll[ MAX_PATH ] = { 0 };
+ PathCombineW( crasherDll, PLUGINDIR, L"gen_crasher.dll" );
+ HMODULE hm = LoadLibraryW( crasherDll );
+ if ( hm )
+ {
+ int( __cdecl * StartHandler )( wchar_t *iniPath ) = NULL;
+ *(FARPROC *)&StartHandler = GetProcAddress( hm, "StartHandler" );
+ if ( StartHandler )
+ {
+ wchar_t iniPath[ MAX_PATH ] = { 0 };
+ if ( SUCCEEDED( StringCchPrintfW( iniPath, MAX_PATH, L"%s\\Plugins", CONFIGDIR ) ) )
+ {
+ winampGeneralPurposePluginGetter pr = (winampGeneralPurposePluginGetter)GetProcAddress( hm, "winampGetGeneralPurposePlugin" );
+ if ( pr )
+ {
+ winampGeneralPurposePlugin *plugin = pr();
+ if ( plugin && plugin->version == GPPHDR_VER_U )
+ {
+ char desc[ 128 ] = { 0 };
+ lstrcpynA( desc, plugin->description, sizeof( desc ) );
+ if ( desc[ 0 ] && !memcmp( desc, "nullsoft(", 9 ) )
+ {
+ char *p = strrchr( desc, ')' );
+ if ( p )
+ {
+ *p = 0;
+ if ( !_wcsicmp( L"gen_crasher.dll", AutoWide( desc + 9 ) ) )
+ {
+ StartHandler( iniPath );
+ }
+ else
+ FreeLibrary( hm );
+ }
+ else
+ FreeLibrary( hm );
+ }
+ else
+ FreeLibrary( hm );
+ }
+ else
+ FreeLibrary( hm );
+ }
+ else
+ FreeLibrary( hm );
+ }
+ else
+ FreeLibrary( hm );
+ }
+ else
+ FreeLibrary( hm );
+ }
+}
+
+DWORD CALLBACK MainThread( LPVOID param )
+{
+ language_pack_instance = hMainInstance;
+
+ playlistStr[ 0 ] = 0;
+ playlistStr[ 18 ] = 0; // keep the last byte null terminated (and don't overwrite) so we can be smoewhat thread-safe (may have junk data, but it won't read outside the array)
+
+ vidoutbuf_save[ 0 ] = 0;
+ vidoutbuf_save[ 1023 ] = 0; // keep the last byte null terminated (and don't overwrite) so we can be smoewhat thread-safe (may have junk data, but it won't read outside the array)
+
+ mainThreadId = GetCurrentThreadId();
+ DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS );
+
+ InitializeCriticalSection( &embedcs );
+
+ CoInitialize( 0 );
+ Wasabi_Load();
+ plstring_init();
+ /*Browser_Create();*/
+
+
+ // check if it's gen_crasher.dll that's being removed and skip loading it so uninstall will work
+ bool skip_crasher = false;
+ wchar_t buf[ 1024 ] = { 0 };
+ _r_sW( "remove_genplug", buf, 1024 );
+ if ( buf[ 0 ] )
+ skip_crasher = !wcsicmp( PathFindFileNameW( buf ), L"gen_crasher.dll" );
+
+ if ( !skip_crasher )
+ load_gen_crasher();
+
+
+ if ( ( 128 & is_install ) || ( !g_noreg && GetPrivateProfileIntW( L"WinampReg", L"NeedReg", 1, INI_FILE ) ) )
+ {
+ is_install = 128; // nothing else
+ Setup_RegisterService();
+ }
+
+ draw_firstinit();
+
+ WM_TASKBARCREATED = RegisterWindowMessageA( "TaskbarCreated" );
+ g_scrollMsg = RegisterWindowMessageA( "MSWHEEL_ROLLMSG" );
+ WM_TASKBARBUTTONCREATED = RegisterWindowMessageW( L"TaskbarButtonCreated" );
+
+ if ( LoadWMFilter() )
+ {
+ changeWMFilter( WM_TASKBARBUTTONCREATED, 1/*MSGFLT_ADD*/ );
+ changeWMFilter( WM_DWMSENDICONICTHUMBNAIL, 1/*MSGFLT_ADD*/ );
+ changeWMFilter( WM_DWMSENDICONICLIVEPREVIEWBITMAP, 1/*MSGFLT_ADD*/ );
+ changeWMFilter( WM_COMMAND, 1/*MSGFLT_ADD*/ ); //for thumbnail toolbar buttons
+ }
+
+ CommandLink_RegisterClass( hMainInstance );
+
+ Skin_CleanupAfterCrash();
+ Lang_CleanupAfterCrash();
+
+ {
+ int langExit = 0;
+ lpszCmdParam = CheckLang( lpszCmdParam, 0, &langExit );
+ if ( langExit )
+ {
+ Lang_EndLangSupport();
+ Lang_CleanupZip();
+ return TRUE;
+ }
+ }
+
+ if ( !g_safeMode )
+ {
+ language_pack_instance = Lang_InitLangSupport( hMainInstance, WinampLangGUID );
+ Lang_FollowUserDecimalLocale();
+ }
+
+ if ( bBookmark )
+ {
+ w5s_init();
+
+ if ( !in_init() )
+ {
+ w5s_deinit();
+ Wasabi_Unload();
+ RemoveRegistrar();
+ CoUninitialize();
+ ExitProcess( 0 );
+ }
+
+ Bookmark_AddCommandline( lpszCmdParam );
+ in_deinit();
+ w5s_deinit();
+ Wasabi_Unload();
+ RemoveRegistrar();
+ CoUninitialize();
+ ExitProcess( 0 );
+ }
+
+ {
+ int skinExit = 0;
+ lpszCmdParam = CheckSkin( lpszCmdParam, 0, &skinExit );
+ if ( skinExit )
+ {
+ return TRUE;
+ }
+ }
+
+ {
+ // remove general purpose plug-in (if set)
+ wchar_t buf[ 1024 ] = { 0 };
+ _r_sW( "remove_genplug", buf, 1024 );
+ if ( buf[ 0 ] )
+ {
+ IFileTypeRegistrar *registrar = 0;
+ if ( GetRegistrar( &registrar, true ) == 0 && registrar )
+ {
+ registrar->DeleteItem( buf );
+ // if gen_crasher is requested to remove, also remove reporter.exe
+ if ( skip_crasher )
+ {
+ GetModuleFileNameW( NULL, buf, MAX_PATH );
+ PathRemoveFileSpecW( buf );
+ PathCombineW( buf, buf, L"reporter.exe" );
+ registrar->DeleteItem( buf );
+ }
+ registrar->Release();
+ }
+
+ _w_s( "remove_genplug", 0 );
+ }
+ }
+
+ fft_init();
+ SpectralAnalyzer_Create();
+ JSAPI1_Initialize();
+ stats_init();
+
+ w5s_init();
+
+
+ if ( !in_init() )
+ {
+ w5s_deinit();
+ Wasabi_Unload();
+ RemoveRegistrar();
+ CoUninitialize();
+ ExitProcess( 0 );
+ }
+
+ out_init();
+ vis_init();
+
+ if ( lpszCmdParam && *lpszCmdParam && !bAdd && !bHandle )
+ config_read( 1 );
+ else
+ config_read( 0 );
+
+ CreateEQPresets();
+
+ if ( is_install )
+ DoInstall( is_install );
+
+ reg_associated_filetypes( 0 );
+
+ if ( config_splash ) splashDlg( SPLASH_DELAY ); // display splash screen if desired
+
+ PlayList_getcurrent( FileName, FileTitle, FileTitleNum ); // update filename and filetitle if a list was loaded
+
+ songChangeBroadcastMessage = RegisterWindowMessageW( L"WinampSongChange" );
+
+ if ( !InitApplication( hMainInstance ) )
+ {
+ LPMessageBox( NULL, IDS_ERRORINIT, IDS_ERROR, MB_OK );
+ return FALSE;
+ }
+
+ if ( !InitInstance( hMainInstance, (int)param ) )
+ {
+ LPMessageBox( NULL, IDS_ERRORINIT, IDS_ERROR, MB_OK );
+ return FALSE;
+ }
+
+ if ( !bHandle )
+ {
+ if ( *lpszCmdParam ) // if command line parameters, parse them
+ {
+ parseCmdLine( lpszCmdParam, 0 );
+ plEditRefresh();
+ {
+ if ( config_shuffle )
+ PlayList_randpos( -BIGINT );
+
+ if ( !bAdd )
+ bStartPlaying = 1;
+ }
+ }
+ else // otherwise, we're using our loaded playlist
+ {
+ if ( config_shuffle ) PlayList_randpos( -BIGINT );
+ PlayList_getcurrent( FileName, FileTitle, FileTitleNum );
+ }
+ }
+
+ //SetCurrentDirectoryW(config_cwd);
+
+ plEditSelect( PlayList_getPosition() );
+
+ Ole_initDragDrop();
+
+ if ( !( GetAsyncKeyState( VK_RCONTROL ) & 0x8000 ) || !( GetAsyncKeyState( VK_LCONTROL ) & 0x8000 ) )
+ {
+ load_genplugins(); // load general purpose plugins
+
+ if ( !Skin_Check_Modern_Support() )
+ {
+ wchar_t msg[ 512 ] = { 0 };
+ StringCchPrintfW( msg, 512, getStringW( IDS_NO_MODERN_SKIN_SUPPORT, NULL, 0 ), config_skin );
+ MessageBoxW( NULL, msg, getStringW( IDS_SKIN_LOAD_ERROR, NULL, 0 ), MB_ICONWARNING | MB_OK | MB_TOPMOST );
+ }
+ }
+
+ //disable video menu if no video plugins are present or configured as disabled
+ if ( !g_has_video_plugin )
+ {
+ RemoveMenu( main_menu, WINAMP_OPTIONS_VIDEO, MF_BYCOMMAND );
+ RemoveMenu( GetSubMenu( v5_top_menu, 3 ), WINAMP_OPTIONS_VIDEO, MF_BYCOMMAND );
+ g_mm_optionsbase_adj -= 1;
+ }
+
+ set_aot( 0 ); // in case our gen plugins did anything fun
+ set_priority();
+
+ {
+ int v = _r_i( "show_prefs", 0 );
+ if ( v != 0 )
+ {
+ if ( v > 0 ) prefs_last_page = v;
+ _w_i( "show_prefs", 0 );
+ PostMessageW( hMainWindow, WM_COMMAND, WINAMP_OPTIONS_PREFS, 0 );
+ SetTimer( hMainWindow, 969, 1, PrefsShowProc );
+ }
+ }
+
+ if ( bStartPlaying )
+ {
+ PlayList_getcurrent( FileName, FileTitle, FileTitleNum );
+ SendMessageW( hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0 );
+ //SendMessageW(hMainWindow,WM_WA_IPC,0,IPC_STARTPLAY);
+ draw_paint( NULL );
+ }
+
+ WADlg_init( hMainWindow );
+
+ SetTimer( hMainWindow, USER_CONSENT_EVENT_ID, 5000, DisplayUserConsentMessageBox );
+
+#ifdef BENSKI_TEST_WM_PRINTCLIENT
+ SetTimer( hMainWindow, 9999, 10000, 0 );
+#endif
+
+ if ( bHandle && *lpszCmdParam )
+ PostMessageW( hMainWindow, WM_WA_IPC, (WPARAM)lpszCmdParam, IPC_HANDLE_URI );
+
+ parseMessageCommands( hMainWindow, bCommand, bCmdParam );
+
+ WPARAM exitParam = WinampMessageLoop();
+ JSAPI1_Uninitialize();
+
+ unload_genplugins();
+ w5s_deinit();
+
+ stats_save();
+ SpectralAnalyzer_Destroy();
+
+ /*Browser_Destroy();*/
+ //RaiseException(0x0000DEAD,0,0,0);
+
+ Ole_uninitDragDrop();
+
+ if ( g_restartonquit )
+ {
+ char buf[ MAX_PATH ] = "\"";
+ STARTUPINFO si = { sizeof( si ), };
+ PROCESS_INFORMATION pi;
+ GetModuleFileNameA( NULL, buf + 1, sizeof( buf ) - 1 );
+ StringCchCatA( buf, MAX_PATH, "\"" );
+
+ if ( g_restartonquit == 2 )
+ StringCchCatA( buf, MAX_PATH, " /SAFE=1" );
+
+ CreateProcessA( NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, (LPSTARTUPINFOA)&si, &pi );
+ }
+
+ RemoveRegistrar();
+ Wasabi_Unload();
+ CoUninitialize();
+ return exitParam;
+} // WinMain
+
+void MoveOffscreen( HWND hwnd )
+{
+ RECT r;
+ GetWindowRect( hwnd, &r );
+ SetWindowPos( hwnd, 0, r.left, OFFSCREEN_Y_POS, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
+}
+
+int g_showcode, deferring_show = 0;
+
+#include "../Plugins/General/gen_ml/ml_ipc.h"
+
+extern librarySendToMenuStruct mainSendTo = { 0 };
+
+// used to delay / filter out quick IPC_SETDIALOGBOXPARENT messages
+// to try to prevent the aero-peek buttons failing / part loading
+#define AEROPEEKLOAD 0xC0DE+5
+VOID CALLBACK TaskButtonCreated( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
+{
+ KillTimer( hwnd, idEvent );
+ OnTaskbarButtonCreated( TRUE );
+}
+
+void UpdateAudioCDMenus( HMENU hmenu )
+{
+ wchar_t buf[ 32 ] = { 0 };
+ if ( IsMenu( hmenu ) && in_get_extended_fileinfoW( L"cda://", L"ext_cdda", buf, ARRAYSIZE( buf ) ) && buf[ 0 ] == L'1' )
+ {
+ for ( int i = 0; i < 5; i++ )
+ {
+ DeleteMenu( hmenu, ID_MAIN_PLAY_AUDIOCD + i, MF_BYCOMMAND );
+ }
+
+ MENUITEMINFOW i = { sizeof( i ), MIIM_TYPE | MIIM_DATA | MIIM_ID, MFT_STRING, };
+ i.wID = ID_MAIN_PLAY_AUDIOCD;
+
+ DWORD drives = GetLogicalDrives();
+ g_audiocdletters = 0;
+
+ int need_sep = 1;
+ for ( int drivemask = 0; drivemask < 32; drivemask++ )
+ {
+ if ( drives & ( 1 << drivemask ) )
+ {
+ int old_error_mode = SetErrorMode( SEM_FAILCRITICALERRORS );
+ wchar_t str[ 64 ] = { 0 }, tmp[ 64 ] = { 0 }, vol_buf[ 40 ] = { 0 }, empty[ 64 ] = { 0 };
+ DWORD system_flags = 0, max_file_len = 0;
+ char c = ( 'A' + drivemask );
+ StringCchPrintfW( str, 64, L"%c:\\", c );
+
+ if ( GetDriveTypeW( str ) == DRIVE_CDROM )
+ {
+ if ( need_sep )
+ {
+ MENUITEMINFO i2 = { sizeof( i2 ), MIIM_TYPE | MIIM_ID, MFT_SEPARATOR, };
+ i2.wID = ID_MAIN_PLAY_AUDIOCD_SEP;
+ InsertMenuItem( hmenu, 4, TRUE, &i2 );
+ need_sep = 0;
+ }
+
+ GetVolumeInformationW( str, vol_buf, ARRAYSIZE( vol_buf ), 0, &max_file_len, &system_flags, 0, 0 );
+ SetErrorMode( old_error_mode );
+
+ StringCchPrintfW( str, 256, getStringW( IDS_AUDIO_CD, tmp, 64 ), c, ( vol_buf[ 0 ] ? vol_buf : getStringW( IDS_EMPTY, empty, 64 ) ) );
+
+ g_audiocdletter[ g_audiocdletters ] = c;
+ i.dwTypeData = str;
+ i.cch = (UINT)wcslen( str );
+ InsertMenuItemW( hmenu, 4 + g_audiocdletters, TRUE, &i );
+ i.wID++;
+
+ g_audiocdletters++;
+ if ( g_audiocdletters == 4 )
+ break;
+ }
+ }
+ }
+ }
+}
+
+// Main Winamp window procedure
+// we use message crackers when available, write our own for the ones that aren't
+LRESULT CALLBACK Main_WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ if ( uMsg == g_scrollMsg )
+ {
+ wParam <<= 16;
+ uMsg = WM_MOUSEWHEEL;
+ }
+
+ if ( uMsg == WM_TASKBARCREATED )
+ {
+ if ( systray_intray )
+ {
+ systray_restore();
+ systray_minimize( caption );
+ }
+ return 0;
+ }
+
+ if ( uMsg == WM_TASKBARBUTTONCREATED )
+ {
+ OnTaskbarButtonCreated( TRUE );
+ KillTimer( hMainWindow, AEROPEEKLOAD );
+ SetTimer( hMainWindow, AEROPEEKLOAD, 250, TaskButtonCreated );
+ return 0;
+ }
+
+ if ( IsDirectMouseWheelMessage( uMsg ) != FALSE )
+ {
+ SendMessageW( hwnd, WM_MOUSEWHEEL, wParam, lParam );
+ return TRUE;
+ }
+
+ switch ( uMsg )
+ {
+ case WM_INITMENUPOPUP:
+ {
+ HMENU hMenu = (HMENU)wParam;
+ if ( wParam && hMenu == mainSendTo.build_hMenu && mainSendTo.mode == 1 )
+ {
+ int IPC_LIBRARY_SENDTOMENU = wa_register_ipc( ( WPARAM ) & "LibrarySendToMenu" );
+ if ( IPC_LIBRARY_SENDTOMENU > 65536 && SendMessageW( hMainWindow, WM_WA_IPC, (WPARAM)&mainSendTo, IPC_LIBRARY_SENDTOMENU ) == 0xffffffff )
+ mainSendTo.mode = 2;
+ }
+
+ if ( config_usecursors && !disable_skin_cursors )
+ {
+ if ( Skin_Cursors[ 2 ] )
+ SetCursor( Skin_Cursors[ 2 ] );
+ else
+ SetCursor( LoadCursorW( NULL, IDC_ARROW ) );
+ }
+ else
+ SetCursor( LoadCursorW( NULL, IDC_ARROW ) );
+
+ if ( hMenu == main_menu )
+ {
+ MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
+ l_menu_info.fMask = MIIM_TYPE;
+ l_menu_info.fType = MFT_STRING;
+ l_menu_info.dwTypeData = getStringW( IDS_WINAMP_MENUITEM, NULL, 0 );
+ l_menu_info.cch = (UINT)wcslen( l_menu_info.dwTypeData );
+ SetMenuItemInfoW( main_menu, 0, TRUE, &l_menu_info );
+ EnableMenuItem( main_menu, WINAMP_FILE_QUIT, MF_BYCOMMAND | ( g_exit_disabled ? MF_GRAYED : MF_ENABLED ) );
+ }
+ else if ( hMenu == g_submenus_play )
+ {
+ UpdateAudioCDMenus( g_submenus_play );
+ }
+ else if ( hMenu == g_submenus_bookmarks1 || hMenu == g_submenus_bookmarks2 )
+ {
+ MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
+ FILE *fp = 0;
+ int a = 34768;
+ int offs = 3;
+ int count = GetMenuItemCount( hMenu ) + 1;
+ if ( hMenu != g_submenus_bookmarks1 )
+ offs = 0;
+
+ l_menu_info.fMask = MIIM_TYPE | MIIM_DATA | MIIM_ID;
+ l_menu_info.fType = MFT_STRING;
+ l_menu_info.wID = 34768;
+
+ // this will remove the "(no bookmarks)" item from Main menu->Play->Bookmsrk
+ // if it still exists -> removed as of 5.55 since we handle the menu better.
+ if ( !offs ) RemoveMenu( hMenu, ID_MAIN_PLAY_BOOKMARK_NONE, MF_BYCOMMAND );
+
+ // remove all of the items we might have added - do by command for certainty
+ while ( count )
+ {
+ if ( !RemoveMenu( hMenu, a++, MF_BYCOMMAND ) ) break;
+ count--;
+ }
+
+ fp = _wfopen( BOOKMARKFILE8, L"rt" );
+ if ( fp )
+ {
+ while ( 1 )
+ {
+ char ft[ 4096 ] = { 0 }, fn[ MAX_PATH ] = { 0 };
+ fgets( fn, MAX_PATH, fp );
+ if ( feof( fp ) ) break;
+ fgets( ft, 4096, fp );
+ if ( feof( fp ) ) break;
+ if ( ft[ 0 ] && fn[ 0 ] )
+ {
+ if ( fn[ lstrlenA( fn ) - 1 ] == '\n' ) fn[ lstrlenA( fn ) - 1 ] = 0;
+ if ( ft[ lstrlenA( ft ) - 1 ] == '\n' ) ft[ lstrlenA( ft ) - 1 ] = 0;
+ if ( ft[ 0 ] && fn[ 0 ] )
+ {
+ l_menu_info.dwTypeData = AutoWideDup( ft, CP_UTF8 );
+ l_menu_info.cch = lstrlenW( l_menu_info.dwTypeData );
+ RemoveMenu( hMenu, l_menu_info.wID, MF_BYCOMMAND );
+ InsertMenuItemW( hMenu, l_menu_info.wID + offs - 34768, TRUE, &l_menu_info );
+ l_menu_info.wID++;
+ }
+ }
+ }
+ fclose( fp );
+ }
+
+ g_BookmarkTop = l_menu_info.wID;
+
+ // put in a place holder item if there were no read bookmarks
+ if ( g_BookmarkTop == 34768 )
+ {
+ l_menu_info.dwTypeData = getStringW( IDS_NO_BOOKMARKS, NULL, 0 );
+ l_menu_info.cch = lstrlenW( l_menu_info.dwTypeData );
+ InsertMenuItemW( hMenu, l_menu_info.wID + offs - 34768, TRUE, &l_menu_info );
+ EnableMenuItem( hMenu, l_menu_info.wID, MF_BYCOMMAND | MF_GRAYED );
+ }
+ }
+ else if ( hMenu == g_submenus_skins1 || hMenu == g_submenus_skins2 )
+ {
+ MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
+ HANDLE h;
+ WIN32_FIND_DATAW d = { 0 };
+ wchar_t dirmask[ MAX_PATH ] = { 0 };
+
+ l_menu_info.fMask = MIIM_TYPE | MIIM_DATA | MIIM_ID | MIIM_STATE;
+ l_menu_info.fType = MFT_STRING;
+ l_menu_info.wID = 32768;
+ PathCombineW( dirmask, SKINDIR, L"*" );
+
+ if ( !config_skin[ 0 ] )
+ CheckMenuItem( hMenu, 32767, MF_CHECKED );
+ else
+ CheckMenuItem( hMenu, 32767, MF_UNCHECKED );
+
+ h = FindFirstFileW( dirmask, &d );
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ int a = 0, mod_got = 0, bento_got = 0, checked = 0;
+ do
+ {
+ if ( !wcscmp( d.cFileName, L"." ) || !wcscmp( d.cFileName, L".." ) ) continue;
+ if ( ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ||
+ !_wcsicmp( extensionW( d.cFileName ), L"zip" ) ||
+ !_wcsicmp( extensionW( d.cFileName ), L"wal" ) ||
+ !_wcsicmp( extensionW( d.cFileName ), L"wsz" ) )
+ {
+ if ( !_wcsicmp( config_skin, d.cFileName ) )
+ {
+ l_menu_info.fState = MFS_CHECKED | MFS_ENABLED;
+ checked = 1;
+ }
+ else
+ {
+ l_menu_info.fState = MFS_UNCHECKED | MFS_ENABLED;
+ }
+
+ if ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ l_menu_info.dwItemData = 0;
+ else
+ {
+ if ( !_wcsicmp( extensionW( d.cFileName ), L"zip" ) )
+ l_menu_info.dwItemData = 1;
+ else if ( !_wcsicmp( extensionW( d.cFileName ), L"wal" ) )
+ l_menu_info.dwItemData = 4;
+ else
+ l_menu_info.dwItemData = 2;
+ extensionW( d.cFileName )[ -1 ] = 0;
+ }
+
+ l_menu_info.dwTypeData = d.cFileName;
+ l_menu_info.cch = (UINT)wcslen( d.cFileName );
+ if ( !a )
+ if ( !RemoveMenu( hMenu, l_menu_info.wID + 4 - 32768, MF_BYPOSITION ) )
+ a = 1;
+
+ if ( !l_menu_info.dwItemData && !_wcsicmp( d.cFileName, MODERN_SKIN_NAME ) )
+ {
+ mod_got = 1;
+ InsertMenuItemW( hMenu, 4, TRUE, &l_menu_info );
+ }
+ else if ( !_wcsicmp( d.cFileName, BENTO_SKIN_NAME ) )
+ {
+ // place below classic + modern (if it exists)
+ bento_got = 1;
+ InsertMenuItemW( hMenu, 4 + mod_got, TRUE, &l_menu_info );
+ }
+ else if ( !_wcsicmp( d.cFileName, BIG_BENTO_SKIN_NAME ) )
+ {
+ // place below classic + modern + normal bento (if it exists)
+ InsertMenuItemW( hMenu, 4 + mod_got + bento_got, TRUE, &l_menu_info );
+ }
+ else
+ InsertMenuItemW( hMenu, l_menu_info.wID + 4 - 32768, TRUE, &l_menu_info );
+
+ l_menu_info.wID++;
+ }
+ } while ( l_menu_info.wID < 34700 && FindNextFileW( h, &d ) );
+ FindClose( h );
+ g_SkinTop = l_menu_info.wID;
+ while ( !a ) if ( !RemoveMenu( hMenu, l_menu_info.wID++ + 4 - 32768, MF_BYPOSITION ) ) a = 1;
+ if ( !checked ) CheckMenuItem( hMenu, 32767, MF_CHECKED );
+ }
+ }
+ else if ( ( hMenu == g_submenus_lang ) && config_wlz_menu )
+ {
+ MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
+ HANDLE h;
+ WIN32_FIND_DATAW d = { 0 };
+ wchar_t dirmask[ MAX_PATH ] = { 0 };
+
+ l_menu_info.fMask = MIIM_TYPE | MIIM_DATA | MIIM_ID | MIIM_STATE;
+ l_menu_info.fType = MFT_STRING;
+ l_menu_info.wID = 34700;
+ PathCombineW( dirmask, LANGDIR, L"*" );
+
+ l_menu_info.dwTypeData = L"English (US)";
+ l_menu_info.cch = (UINT)wcslen( l_menu_info.dwTypeData );
+ InsertMenuItemW( hMenu, l_menu_info.wID - 34700, TRUE, &l_menu_info );
+ l_menu_info.wID++;
+
+ CheckMenuItem( hMenu, 34700, ( !config_langpack[ 0 ] ? MF_CHECKED : MF_UNCHECKED ) );
+
+ h = FindFirstFileW( dirmask, &d );
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ int a = 0, checked = 0;
+ do
+ {
+ if ( !wcscmp( d.cFileName, L"." ) || !wcscmp( d.cFileName, L".." ) ) continue;
+
+ if ( ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ||
+ !_wcsicmp( extensionW( d.cFileName ), L"zip" ) ||
+ !_wcsicmp( extensionW( d.cFileName ), L"wlz" ) )
+ {
+
+ if ( !_wcsicmp( config_langpack, d.cFileName ) )
+ {
+ l_menu_info.fState = MFS_CHECKED | MFS_ENABLED;
+ checked = 1;
+ }
+ else
+ {
+ l_menu_info.fState = MFS_UNCHECKED | MFS_ENABLED;
+ }
+
+ if ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+ wchar_t check[ MAX_PATH ] = { 0 };
+ PathCombineW( check, LANGDIR, d.cFileName );
+ PathCombineW( check, check, L"winamp.lng" );
+
+ if ( !PathFileExistsW( check ) )
+ continue;
+
+ l_menu_info.dwItemData = 0;
+ }
+ else
+ {
+ if ( !_wcsicmp( extensionW( d.cFileName ), L"zip" ) )
+ l_menu_info.dwItemData = 1;
+ else
+ l_menu_info.dwItemData = 2;
+
+ extensionW( d.cFileName )[ -1 ] = 0;
+ }
+
+ l_menu_info.dwTypeData = d.cFileName;
+ l_menu_info.cch = (UINT)wcslen( d.cFileName );
+
+ if ( !a )
+ if ( !RemoveMenu( hMenu, l_menu_info.wID - 34700, MF_BYPOSITION ) )
+ a = 1;
+
+ InsertMenuItemW( hMenu, l_menu_info.wID - 34700, TRUE, &l_menu_info );
+ l_menu_info.wID++;
+ }
+ } while ( l_menu_info.wID < 34800 && FindNextFileW( h, &d ) );
+
+ FindClose( h );
+ g_LangTop = l_menu_info.wID;
+ while ( !a )
+ if ( !RemoveMenu( hMenu, l_menu_info.wID++ - 34700, MF_BYPOSITION ) )
+ a = 1;
+
+ if ( !checked )
+ CheckMenuItem( hMenu, 34700, MF_CHECKED );
+ }
+ }
+ break;
+ }
+ case WM_DISPLAYCHANGE:
+ Main_OnDisplayChange( hwnd );
+ break;
+ case WM_WA_SYSTRAY:
+ return ( Main_OnWASystray( hwnd, (int)LOWORD( lParam ) ) ? 0 : -1L );
+ case WM_WA_MPEG_EOF:
+ return ( Main_OnWAMPEGEOF( hwnd ) ? 0 : -1L ); // sent by decode thread
+ case WM_WA_IPC:
+ return ( Main_OnIPC( hwnd, lParam, (int)(DWORD)wParam ) );
+
+ HANDLE_MSG( hwnd, WM_COMMAND, Main_OnCommand );
+ HANDLE_MSG( hwnd, WM_SYSCOMMAND, Main_OnSysCommand );
+ HANDLE_MSG( hwnd, WM_CREATE, Main_OnCreate );
+ HANDLE_MSG( hwnd, WM_QUERYNEWPALETTE, Main_OnQueryNewPalette );
+ HANDLE_MSG( hwnd, WM_PALETTECHANGED, Main_OnPaletteChanged );
+ HANDLE_MSG( hwnd, WM_SIZE, Main_OnSize );
+ HANDLE_MSG( hwnd, WM_DROPFILES, Main_OnDropFiles );
+ HANDLE_MSG( hwnd, WM_TIMER, Main_OnTimer );
+ HANDLE_MSG( hwnd, WM_PAINT, draw_paint );
+ case WM_PRINTCLIENT:
+ draw_printclient( (HDC)wParam, lParam );
+ return 0;
+
+ HANDLE_MSG( hwnd, WM_RBUTTONUP, Main_OnRButtonUp );
+ HANDLE_MSG( hwnd, WM_LBUTTONDBLCLK, Main_OnLButtonDblClk );
+ HANDLE_MSG( hwnd, WM_LBUTTONUP, Main_OnLButtonUp );
+ HANDLE_MSG( hwnd, WM_LBUTTONDOWN, Main_OnLButtonDown );
+ HANDLE_MSG( hwnd, WM_MOUSEMOVE, Main_OnMouseMove );
+ case WM_CONTEXTMENU:
+ SendMessageW( hwnd, WM_COMMAND, WINAMP_MAINMENU, 0 );
+ return 0;
+ case WM_CAPTURECHANGED:
+ return Main_OnCaptureChanged( (HWND)lParam );
+
+ HANDLE_MSG( hwnd, WM_DESTROY, Main_OnDestroy );
+ HANDLE_MSG( hwnd, WM_CLOSE, Main_OnClose );
+ case WM_NCACTIVATE:
+ {
+ LRESULT result = (LRESULT)(DWORD)(BOOL)(Main_OnNCActivate)( ( hwnd ), (BOOL)( wParam ), (HWND)( lParam ), 0L );
+ if ( IsIconic( hwnd ) )
+ break;
+ else
+ return result;
+ }
+ case WM_NCHITTEST:
+ if ( IsIconic( hwnd ) )
+ break;
+ return (LRESULT)(DWORD)(UINT)(Main_OnNCHitTest)( ( hwnd ), (int)(short)LOWORD( lParam ), (int)(short)HIWORD( lParam ) );
+ case WM_NCCALCSIZE:
+ if ( IsIconic( hwnd ) )
+ break;
+ return (LRESULT)(DWORD)(UINT)Main_OnNCCalcSize( hwnd, (BOOL)wParam, (NCCALCSIZE_PARAMS *)lParam );
+
+ HANDLE_MSG( hwnd, WM_ENDSESSION, Main_OnEndSession );
+ case WM_QUERYENDSESSION:
+ return !!SendMessageW( hwnd, WM_WA_IPC, 0, IPC_HOOK_OKTOQUIT );
+ case WM_KEYDOWN:
+ {
+ static int pos;
+ TCHAR buf[ 2 ] = { (TCHAR)wParam, 0 };
+ CharUpperBuff( buf, 1 );
+
+ if ( buf[ 0 ] == eggstr[ pos ] )
+ {
+ eggTyping = TRUE;
+ if ( !eggstr[ ++pos ] )
+ {
+ eggTyping = FALSE;
+ eggstat = !eggstat;
+ pos = 0;
+ draw_tbar( 1, config_windowshade, eggstat );
+ }
+ }
+ else
+ pos = 0;
+
+ break;
+ }
+ case WM_NCPAINT:
+ return 0;
+ case WM_COPYDATA:
+ return Main_OnCopyData( (HWND)wParam, (COPYDATASTRUCT *)lParam );
+ case WM_GETTEXT:
+ return Main_OnGetText( (wchar_t *)lParam, (int)wParam );
+ case WM_NOTIFY:
+ {
+ LPTOOLTIPTEXTW tt = (LPTOOLTIPTEXTW)lParam;
+ if ( tt->hdr.hwndFrom = hTooltipWindow )
+ {
+ switch ( tt->hdr.code )
+ {
+ case TTN_SHOW:
+ SetWindowPos( tt->hdr.hwndFrom, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
+ break;
+ case TTN_NEEDTEXTW:
+ {
+ LPTOOLTIPTEXTW tt = (LPTOOLTIPTEXTW)lParam;
+ wchar_t booga[ 81 ] = { 0 };
+ GetWindowTextW( hwnd, booga, 79 );
+ booga[ 79 ] = 0;
+ StringCchCopyW( tt->szText, 80, booga );
+ tt->lpszText = tt->szText;
+ return 0;
+ }
+ }
+ }
+ break;
+ }
+ case WM_SETFOCUS:
+ if ( !config_mw_open )
+ {
+ if ( config_pe_open )
+ SetForegroundWindow( hPLWindow );
+ else if ( config_eq_open )
+ SetForegroundWindow( hEQWindow );
+ // else if (config_mb_open) SetForegroundWindow(hMBWindow);
+ else if ( config_video_open )
+ SetForegroundWindow( hVideoWindow );
+ else
+ {
+ EnterCriticalSection( &embedcs );
+ {
+ embedWindowState *p = embedwndlist;
+ while ( p )
+ {
+ if ( IsWindowVisible( p->me ) )
+ {
+ SetForegroundWindow( p->me );
+ break;
+ }
+
+ p = p->link;
+ }
+ }
+
+ LeaveCriticalSection( &embedcs );
+ }
+ }
+
+ break;
+ case WM_KILLFOCUS:
+ {
+ if ( !config_mw_open )
+ {
+ if ( config_pe_open )
+ SetForegroundWindow( hPLWindow );
+ else if ( config_eq_open )
+ SetForegroundWindow( hEQWindow );
+ // else if (config_mb_open) SetForegroundWindow(hMBWindow);
+ else if ( config_video_open )
+ SetForegroundWindow( hVideoWindow );
+ else
+ {
+ EnterCriticalSection( &embedcs );
+ {
+ embedWindowState *p = embedwndlist;
+ while ( p )
+ {
+ if ( IsWindowVisible( p->me ) )
+ {
+ SetForegroundWindow( p->me );
+ break;
+ }
+
+ p = p->link;
+ }
+ }
+
+ LeaveCriticalSection( &embedcs );
+ }
+ }
+
+
+ break;
+ }
+ case WM_MOUSEWHEEL:
+ {
+ // because some people don't like it
+ if ( config_nomwheel )
+ break;
+
+ int zDelta = GET_WHEEL_DELTA_WPARAM( wParam ), dLines;
+ // if the delta changes then ignore prior carryover
+ // hopefully this will go with the expected action.
+ if ( zDelta < 0 && main_delta_carryover > 0 || zDelta > 0 && main_delta_carryover < 0 )
+ main_delta_carryover = 0;
+ // otherwise add on the carryover from the prior message
+ else
+ zDelta += main_delta_carryover;
+
+ if ( 0 == ( MK_MBUTTON & LOWORD( wParam ) ) )
+ zDelta *= 2;
+
+ dLines = zDelta / WHEEL_DELTA;
+ main_delta_carryover = zDelta - dLines * WHEEL_DELTA;
+
+ if ( 0 != dLines )
+ {
+ zDelta = ( dLines > 0 ) ? dLines : -dLines;
+
+ if ( 0 != ( MK_MBUTTON & LOWORD( wParam ) ) )
+ {
+ if ( dLines >= 0 )
+ dLines = WINAMP_FFWD5S;
+ else
+ dLines = WINAMP_REW5S;
+ }
+ else
+ {
+ if ( dLines >= 0 )
+ dLines = WINAMP_VOLUMEUP;
+ else
+ dLines = WINAMP_VOLUMEDOWN;
+ }
+
+ while ( zDelta-- )
+ {
+ SendMessageW( hwnd, WM_COMMAND, dLines, 0 );
+ }
+ }
+ break;
+ }
+ case WM_DWMSENDICONICTHUMBNAIL:
+ {
+ int x = HIWORD( lParam );
+ int y = LOWORD( lParam );
+ OnIconicThumbnail( x, y );
+ }
+ break;
+#if 0
+ case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
+ {
+ //MessageBoxA(NULL, "winamp/live", "winamp/live", MB_OK);
+ OnThumbnailPreview();
+ }
+ break;
+#endif
+ case WM_MOVE:
+#if 0
+ if ( (int)LOWORD( lParam ) < 32768 && (int)HIWORD( lParam ) < 32768 )
+ {
+ if (/*(int)LOWORD(lParam) != 3000 && */(int)HIWORD( lParam ) != OFFSCREEN_Y_POS )
+ {
+ if ( (int)LOWORD( lParam ) != config_wx ||
+ (int)HIWORD( lParam ) != config_wy )
+ if ( config_keeponscreen & 1 )
+ {
+ config_wx = (int)LOWORD( lParam );
+ config_wy = (int)HIWORD( lParam );
+ set_aot( 1 );
+ }
+ }
+ }
+#endif
+ break;
+ case WM_SETCURSOR:
+
+ switch ( HIWORD( lParam ) )
+ {
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_XBUTTONDOWN:
+ DisabledWindow_OnMouseClick( hwnd );
+ break;
+ }
+ if ( config_usecursors && !disable_skin_cursors )
+ {
+ if ( (HWND)wParam == hMainWindow && HIWORD( lParam ) == WM_MOUSEMOVE )
+ ui_handlecursor();
+
+ return TRUE;
+ }
+ else
+ SetCursor( LoadCursorW( NULL, IDC_ARROW ) );
+
+ break;
+ }
+
+ return ( DefWindowProcW( hwnd, uMsg, wParam, lParam ) );
+}
+
+static LRESULT Main_OnSysCommand( HWND hwnd, UINT cmd, int x, int y )
+{
+ // char buf[512];
+ // wsprintf(buf,"got WM_SYSCOMMAND %08x\n",cmd);
+ // OutputDebugString(buf);
+ // video
+ if ( ( ( cmd & 0xfff0 ) == SC_SCREENSAVE || ( cmd & 0xfff0 ) == SC_MONITORPOWER ) && config_video_noss && video_isVideoPlaying() )
+ {
+ return -1;
+ }
+
+ if ( !Main_OnCommand( hwnd, cmd, (HWND)x, (UINT)y ) )
+ FORWARD_WM_SYSCOMMAND( hwnd, cmd, x, y, DefWindowProcW );
+ return 1;
+}
+
+static LRESULT WINAPI browseCheckBoxProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( uMsg )
+ {
+ case WM_INITDIALOG:
+ {
+ if ( !( config_rofiob & 2 ) )
+ CheckDlgButton( hwndDlg, IDC_CHECK1, BST_CHECKED );
+
+ break;
+ }
+ case WM_COMMAND:
+ {
+ if ( LOWORD( wParam ) == IDC_CHECK1 )
+ {
+ config_rofiob &= ~2;
+ if ( !IsDlgButtonChecked( hwndDlg, IDC_CHECK1 ) )
+ config_rofiob |= 2;
+
+ config_write( 0 );
+ }
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+BOOL CALLBACK browseEnumProc( HWND hwnd, LPARAM lParam )
+{
+ char cl[ 32 ] = { 0 };
+ GetClassNameA( hwnd, cl, ARRAYSIZE( cl ) );
+ if ( !lstrcmpiA( cl, WC_TREEVIEWA ) )
+ {
+ PostMessageW( hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection( hwnd ) );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int CALLBACK WINAPI BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData )
+{
+ switch ( uMsg )
+ {
+ case BFFM_INITIALIZED:
+ {
+ SetWindowTextW( hwnd, getStringW( ( !lpData ? IDS_OPENDIR : IDS_ADD_FOLDER ), NULL, 0 ) );
+ SendMessageW( hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)config_cwd );
+
+ HWND h = FindWindowExW( hwnd, NULL, NULL, L"__foo" );
+ if ( h )
+ ShowWindow( h, SW_HIDE );
+
+ h = LPCreateDialogW( IDD_BROWSE_RECDLG, hwnd, browseCheckBoxProc );
+
+ SetWindowPos( h, 0, 4, 4, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+ ShowWindow( h, SW_SHOWNA );
+
+ // this is not nice but it fixes the selection not working correctly on all OSes
+ EnumChildWindows( hwnd, browseEnumProc, 0 );
+ }
+ }
+
+ return 0;
+}
+
+LRESULT sendMlIpc( int msg, WPARAM param )
+{
+ static LRESULT IPC_GETMLWINDOW;
+ static HWND mlwnd;
+
+ if ( !IPC_GETMLWINDOW ) IPC_GETMLWINDOW = wa_register_ipc( ( WPARAM ) & "LibraryGetWnd" );
+ if ( !mlwnd || (int)mlwnd == 1 )
+ mlwnd = (HWND)SendMessageW( hMainWindow, WM_WA_IPC, 0, IPC_GETMLWINDOW );
+
+ if ( param == 0 && msg == 0 ) return (LRESULT)mlwnd;
+
+ if ( IsWindow( mlwnd ) )
+ return SendMessageW( mlwnd, WM_ML_IPC, param, msg );
+
+ return 0;
+}
+
+void tealike_crappy_code( unsigned long v[ 2 ], unsigned long k[ 4 ] )
+{
+ unsigned long y = v[ 0 ], z = v[ 1 ], sum = 0, /* set up */
+ delta = 0x9e3779b9UL, n = 32; /* key schedule constant*/
+
+ while ( n-- > 0 )
+ {
+ /* basic cycle start */
+ sum += delta;
+ y += ( ( z << 4 ) + k[ 0 ] ) ^ ( z + sum ) ^ ( ( z >> 5 ) + k[ 1 ] );
+ z += ( ( y << 4 ) + k[ 2 ] ) ^ ( y + sum ) ^ ( ( y >> 5 ) + k[ 3 ] ); /* end cycle */
+ }
+ v[ 0 ] = y; v[ 1 ] = z;
+}
+
+// command line parsing, for IPC or normal modes
+// goes to a lot of trouble to look for "'s.
+
+HWND find_otherwinamp( wchar_t *cmdline )
+{
+ int y = 0;
+ wchar_t buf[ MAX_PATH ] = { 0 };
+
+ StringCchPrintfW( buf, MAX_PATH, L"%s_%x_CLASS", szAppName, APP_VERSION_NUM );
+again:
+ g_hEventRunning = CreateEventW( 0, 1, 0, buf );
+ if ( g_hEventRunning && GetLastError() == ERROR_ALREADY_EXISTS )
+ {
+ int x;
+ CloseHandle( g_hEventRunning );
+ g_hEventRunning = 0;
+ // check for window for 4s, then give up
+ if ( !bNoHwndOther && ( !config_minst || *cmdline ) ) for ( x = 0; x < 40; x++ )
+ {
+ HWND lhwnd = NULL;
+ int failed = 0;
+ while ( ( lhwnd = FindWindowExW( NULL, lhwnd, szAppName, NULL ) ) )
+ {
+ DWORD_PTR vn = 0; //APP_VERSION_NUM
+ if ( lhwnd == hMainWindow )
+ continue;
+ if ( !SendMessageTimeout( lhwnd, WM_WA_IPC, 0, IPC_GETVERSION, SMTO_NORMAL, 5000, &vn ) )
+ {
+ failed = 1;
+ }
+ else if ( vn == APP_VERSION_NUM ) return lhwnd;
+ }
+ if ( failed ) return NULL; // no valid winamp windows, but one that fucked up
+
+ Sleep( 100 );
+ }
+ if ( y++ < 20 ) goto again;
+ }
+ return NULL;
+}
+
+
+// returns 0 if showing/hiding sould be aborted
+int Ipc_WindowToggle( INT_PTR which, INT_PTR how )
+{
+ return SendMessageW( hMainWindow, WM_WA_IPC, which, how ? IPC_CB_ONSHOWWND : IPC_CB_ONHIDEWND );
+}
+//}
+
+#ifdef BENSKI_TEST_WM_PRINTCLIENT
+static void PrintWindow( HWND hWnd )
+{
+ HDC hDCMem = CreateCompatibleDC( NULL );
+ HBITMAP hBmp = NULL;
+ RECT rect;
+
+ GetWindowRect( hWnd, &rect );
+ {
+ HDC hDC = GetDC( hWnd );
+ hBmp = CreateCompatibleBitmap( hDC, rect.right - rect.left, rect.bottom - rect.top );
+ ReleaseDC( hWnd, hDC );
+ }
+ {
+ HGDIOBJ hOld = SelectObject( hDCMem, hBmp );
+ SendMessageW( hWnd, WM_PRINT, (WPARAM)hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED );
+
+ SelectObject( hDCMem, hOld );
+ }
+ DeleteObject( hDCMem );
+
+ OpenClipboard( hWnd );
+
+ EmptyClipboard();
+ SetClipboardData( CF_BITMAP, hBmp );
+ CloseClipboard();
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/main.hpp b/Src/Winamp/main.hpp
new file mode 100644
index 00000000..baefbdc4
--- /dev/null
+++ b/Src/Winamp/main.hpp
@@ -0,0 +1,4 @@
+#pragma once
+
+/* C++ specific includes should go here */
+
diff --git a/Src/Winamp/main_buttons.cpp b/Src/Winamp/main_buttons.cpp
new file mode 100644
index 00000000..93290517
--- /dev/null
+++ b/Src/Winamp/main_buttons.cpp
@@ -0,0 +1,241 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "resource.h"
+extern "C" extern int g_stopaftercur;
+
+// button 1 (prev) functions
+int Main_OnButton1(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ if (id == WINAMP_BUTTON1_SHIFT) SendMessageW(hwnd, WM_COMMAND, WINAMP_REW5S, 0);
+ else if (id == WINAMP_BUTTON1_CTRL)
+ {
+ PlayList_setposition(0);
+ if (config_shuffle) PlayList_randpos( -BIGINT);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ if (playing) StartPlaying();
+ else StopPlaying(0);
+ }
+ else
+ {
+ int nitem = SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GET_PREVIOUS_PLITEM);
+ if (nitem != -1)
+ {
+ PlayList_setposition(nitem);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ }
+ else
+ {
+ int s = 1;
+ if (!config_shuffle && PlayList_advance( -1) < 0)
+ {
+ s = 0;
+ if (config_repeat)
+ {
+ s = 1;
+ PlayList_advance(BIGINT);
+ }
+ }
+ if (s)
+ {
+ if (PlayList_getlength())
+ {
+ if (config_shuffle)
+ {
+ if (PlayList_randpos( -1)) return 1;
+ }
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ if (playing)
+ {
+ StopPlaying(0);
+ StartPlaying();
+ }
+ else StopPlaying(0);
+ }
+ }
+ }
+ }
+ return 1;
+} // Main_OnButton1
+
+// button 2 (play) functions
+int Main_OnButton2(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ PlayList_resetcurrent();
+ if (!playing)
+ {
+ if (!no_notify_play)
+ {
+ FileName[0] = 0;
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ }
+ if (id == WINAMP_BUTTON2_CTRL)
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_LOC, 0);
+ else if (!FileName[0] || id == WINAMP_BUTTON2_SHIFT)
+ {
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_PLAY, 0);
+ }
+ else
+ {
+ StartPlaying();
+ }
+ }
+ else
+ {
+ if (id == WINAMP_BUTTON2_CTRL)
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_LOC, 0);
+ else if (id == WINAMP_BUTTON2_SHIFT)
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_PLAY, 0);
+ else if (paused) UnPausePlaying();
+ else
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ }
+ }
+ return 1;
+} // Main_OnButton2
+
+// button 3 (pause) functions
+int Main_OnButton3(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ if (playing)
+ {
+ if (paused) UnPausePlaying();
+ else PausePlaying();
+ }
+ return 1;
+}
+
+// button 4 (stop) functions
+int Main_OnButton4(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ if (playing)
+ {
+ if (id == WINAMP_BUTTON4_CTRL)
+ {
+ HMENU m;
+ int r;
+ g_stopaftercur = !g_stopaftercur;
+ r = g_stopaftercur ? MF_CHECKED : MF_UNCHECKED;
+ CheckMenuItem(main_menu, WINAMP_BUTTON4_CTRL, r);
+ m = GetSubMenu(top_menu, 3);
+ CheckMenuItem(m, WINAMP_BUTTON4_CTRL, r);
+ return 1;
+ }
+ if (id == WINAMP_BUTTON4_SHIFT && !paused)
+ {
+// double v=0;
+ int x = 256;
+
+ int v = config_volume;
+// double v = (double)(int)config_volume;
+ //double dv;// = -v / 256.;//(double)x;
+ int delay = 8;//2000 / x;
+// v = (double)config_volume;
+ //dv = -v / 256.;
+ while (x--)
+ {
+ if (v < 0) v = 0;
+ in_setvol((int)v);
+ // v += dv;
+ v--;
+ Sleep(delay);
+ }
+ Sleep(100);
+ PausePlaying();
+ in_flush(in_getouttime());
+ in_setvol(config_volume);
+
+ }
+
+ StopPlaying(0);
+ }
+ return 1;
+}
+
+// button 5 (next) fucntions
+int Main_OnButton5(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ if (id == WINAMP_BUTTON5_SHIFT)
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FFWD5S, 0);
+ else if (id == WINAMP_BUTTON5_CTRL)
+ {
+ PlayList_setposition(BIGINT);
+ if (config_shuffle)
+ {
+ PlayList_randpos( -BIGINT);
+ PlayList_randpos(PlayList_getlength() - 1);
+ }
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ if (playing) StartPlaying();
+ else StopPlaying(0);
+ }
+ else
+ {
+ int nitem = SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GET_NEXT_PLITEM);
+ if (nitem != -1)
+ {
+ PlayList_setposition(nitem);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ StartPlaying();
+ }
+ else if (!config_shuffle && PlayList_advance(1) < 0)
+ {
+ if (config_repeat)
+ {
+ PlayList_setposition(0);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ if (playing)
+ {
+ StopPlaying(0);
+ StartPlaying();
+ }
+ else StopPlaying(0);
+ }
+ }
+ else
+ {
+ if (!PlayList_getlength()) return 1;
+ if (config_shuffle)
+ {
+ int lp = PlayList_getPosition();
+ int q = PlayList_randpos(1);
+ if (q || PlayList_getlength() == 1)
+ {
+ if (!config_repeat) return 1;
+ PlayList_randpos( -BIGINT);
+ }
+ if (PlayList_getPosition() == lp && PlayList_getlength() > 1)
+ {
+ PlayList_randpos(1);
+ }
+ }
+ else
+ {
+ // 5.64 - if pledit is cleared, shuffle is off & we're playing
+ // then we set playing to go back to the start of the playlist
+ // as we get complaints it'll go to #2 instead of #1 as shown.
+ if (plcleared)
+ {
+ plcleared = 0;
+ PlayList_setposition(0);
+ }
+ }
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ if (playing)
+ {
+ StopPlaying(0);
+ StartPlaying();
+ }
+ else StopPlaying(0);
+ }
+ }
+ return 1;
+} // Main_OnButton5() \ No newline at end of file
diff --git a/Src/Winamp/main_close.cpp b/Src/Winamp/main_close.cpp
new file mode 100644
index 00000000..53f06f87
--- /dev/null
+++ b/Src/Winamp/main_close.cpp
@@ -0,0 +1,111 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "wa_dlg.h"
+#include "./api.h"
+
+// Destroy handler
+ int Main_OnDestroy(HWND hwnd)
+{
+ if (NULL != WASABI_API_APP) WASABI_API_APP->app_unregisterGlobalWindow(hwnd);
+ if (g_main_created)
+ {
+ SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS);
+ Main_OnEndSession(NULL,TRUE);
+ PostQuitMessage(0);
+ }
+ return 1;
+}
+
+int Main_OnClose(HWND hwnd)
+{
+ if (g_exit_disabled)
+ {
+ if (NULL != WASABI_API_APP)
+ WASABI_API_APP->main_cancelShutdown();
+ return 0;
+ }
+ ReleaseCapture();
+
+ if (!SendMessageW(hwnd,WM_WA_IPC,0,IPC_HOOK_OKTOQUIT))
+ {
+ if (NULL != WASABI_API_APP)
+ WASABI_API_APP->main_cancelShutdown();
+ return 0;
+ }
+
+ if (playing) StopPlaying(1);
+ sa_setthread(-1);
+ vis_stop();
+ dsp_quit();
+
+ if (pTaskbar3 != NULL)
+ pTaskbar3->Release();
+ pTaskbar3=0;
+
+ if (toolbarIcons)
+ ImageList_Destroy(toolbarIcons);
+ toolbarIcons = 0;
+
+ DestroyWindow(hwnd);
+ return 0;
+}
+
+void Main_OnEndSession(HWND hwnd, BOOL fEnding)
+{
+ // TODO try to make this match normal shutdown...
+ if (fEnding)
+ {
+ EndFullscreenAppMonitor();
+ if (playing) StopPlaying(1);
+ sa_setthread(-1);
+ vis_stop();
+ dsp_quit();
+
+ if (!hwnd && systray_intray) systray_restore();
+
+ hEQWindow=hPLWindow=/*hMBWindow=*/hVideoWindow=0;
+ hVisWindow=0;
+ hPLVisWindow=0;
+
+ draw_kill();
+
+ draw_finalquit();
+ WADlg_close();
+ Skin_CleanupZip();
+
+ // is possible the prefs window was open but has already been destroyed
+ // so don't use IsWindow(..) here and instead just look if its non-null
+ if (prefs_hwnd)
+ {
+ prefs_hwnd = 0;
+ config_write(2);
+ }
+ else config_write(1);
+
+ stats_write();
+ PlayList_destroy();
+ PlayList_randpos(-666);
+ DestroyMenu(top_menu);
+
+ if (hwnd) unload_genplugins();
+ out_deinit();
+ in_deinit();
+
+ Lang_EndLangSupport();
+ Lang_CleanupZip();
+
+ // if we're working on a delayed saving of language pack change then now
+ if(config_langpack2[0]){
+ // if < is the buffer contents then we're setting it back to the base support
+ if(config_langpack2[0] == '<') config_langpack2[0] = 0;
+ lstrcpynW(config_langpack,config_langpack2,MAX_PATH);
+ config_save_langpack_var();
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/main_command.cpp b/Src/Winamp/main_command.cpp
new file mode 100644
index 00000000..f0dd272b
--- /dev/null
+++ b/Src/Winamp/main_command.cpp
@@ -0,0 +1,916 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "../Plugins/General/gen_crasher/GetWinVer.h"
+#include "resource.h"
+#include "../Plugins/General/gen_ml/ml.h"
+#include "../nu/AutoWide.h"
+#include "api.h"
+#include "ExplorerFindFile.h"
+#include <assert.h>
+#include "vis.h"
+LRESULT sendMlIpc(int msg, WPARAM param);
+int g_open_ml_item_in_pe = 0;
+EXTERN_C BOOL eggTyping;
+
+void showLibrary()
+{
+ SendMessageW(hMainWindow, WM_COMMAND, ID_FILE_SHOWLIBRARY, 0);
+}
+
+static void ToggleWindowShade_PL()
+{
+ if (config_pe_height == 14)
+ {
+ if (config_pe_height_ws < 116) config_pe_height_ws = 116;
+ config_pe_height = config_pe_height_ws;
+ config_pe_height_ws = 0;
+ }
+ else
+ {
+ config_pe_height_ws = config_pe_height;
+ config_pe_height = 14;
+ }
+ set_aot(1);
+}
+
+static void ToggleWindowShade_EQ()
+{
+ config_eq_ws = !config_eq_ws;
+ set_aot(1);
+ draw_eq_tbar(GetForegroundWindow() == hEQWindow ? 1 : (config_hilite ? 0 : 1));
+}
+
+static void ToggleWindowShade_Main()
+{
+ config_windowshade = !config_windowshade;
+ set_aot(1);
+ draw_tbar(1, config_windowshade, eggstat);
+ SendMessageW(hMainWindow, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ sa_setthread(config_sa);
+}
+
+// Big nasty command handler.
+// it calls Main_OnButtonX() for the button controls
+LRESULT Main_OnCommand(HWND hwnd, int wID, HWND hwndCtl, UINT codeNotify)
+{
+ if (codeNotify == THBN_CLICKED && !atti_present)
+ {
+ switch (wID)
+ {
+ case 0: //previous
+ {
+ wID = WINAMP_BUTTON1;
+ }
+ break;
+ case 1: //play
+ {
+ wID = WINAMP_BUTTON2;
+ }
+ break;
+ case 2: //pause
+ {
+ wID = WINAMP_BUTTON3;
+ }
+ break;
+ case 3: //stop
+ {
+ wID = WINAMP_BUTTON4;
+ }
+ break;
+ case 4: //next
+ {
+ wID = WINAMP_BUTTON5;
+ }
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ if (1 == codeNotify && eggTyping)
+ {
+ BYTE kb[256] = {0};
+ if(GetKeyboardState(kb))
+ {
+ for (INT i = 0x30; i < 0x87; i++)
+ {
+ if (0 != (0x80 & kb[i]))
+ SendMessageW(hwnd, WM_KEYDOWN, i, 0L);
+
+ }
+ if (0 != (0x80 & kb[0x20]))
+ SendMessageW(hwnd, WM_KEYDOWN, 0x20, 0L);
+ }
+ }
+
+ if (LOWORD(wID) >= 34768 && LOWORD(wID) < g_BookmarkTop)
+ {
+ FILE *fp = _wfopen(BOOKMARKFILE8, L"rt");
+ if (fp)
+ {
+ int x = 0, id = LOWORD(wID)-34768;
+ for (;;)
+ {
+ char ft[4096] = {0}, fn[MAX_PATH] = {0};
+ fgets(fn, MAX_PATH, fp);
+ if (feof(fp)) break;
+ fgets(ft, 4096, fp);
+ if (feof(fp)) break;
+ if (ft[0] && fn[0])
+ {
+ if (fn[lstrlenA(fn) - 1] == '\n') fn[lstrlenA(fn) - 1] = 0;
+ if (ft[lstrlenA(ft) - 1] == '\n') ft[lstrlenA(ft) - 1] = 0;
+ if (ft[0] && fn[0])
+ {
+ if (x++ == id)
+ {
+ // this will track the gen_ml or main play/enqueue setting
+ // done as something which koopa requested back in 09/2011
+ // including following 'shift' to invert the default mode.
+ int addtolist, enqplay = 0;
+ if (got_ml)
+ {
+ enqplay = GetPrivateProfileIntW(L"MLEnqPlay", L"enqueuedef", -1, INI_FILE);
+ if (enqplay != -1)
+ {
+ addtolist = (!!enqplay) ^ (!!(GetAsyncKeyState(VK_SHIFT)&0x8000));
+ }
+ else
+ {
+ addtolist = (!!GetPrivateProfileIntW(L"gen_ml_config", L"enqueuedef", 0, ML_INI_FILE)) ^ (!!(GetAsyncKeyState(VK_SHIFT)&0x8000));
+ }
+ }
+ else
+ addtolist = (!!config_addtolist) ^ (!!(GetAsyncKeyState(VK_SHIFT)&0x8000));
+
+ if(!addtolist) PlayList_delete();
+ PlayList_appendthing(AutoWideDup(fn, CP_UTF8), 0, 0);
+ if(!addtolist)
+ {
+ if (config_shuffle) PlayList_setposition(PlayList_getNextPosition());
+ else PlayList_setposition(0);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ }
+ else
+ {
+ if (enqplay == 2) PlayList_setposition(PlayList_getlength());
+ }
+ plEditRefresh();
+ if(!addtolist || enqplay == 2)
+ StartPlaying();
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ }
+ return 1;
+ }
+
+ if (LOWORD(wID) >= 32767 && LOWORD(wID) < g_SkinTop)
+ {
+ wchar_t curfilename[MAX_PATH] = {0};
+ int id = LOWORD(wID);
+ if (id >= 32768)
+ {
+ MENUITEMINFOW mi = {sizeof(mi), MIIM_DATA | MIIM_TYPE, MFT_STRING};
+ mi.dwTypeData = curfilename;
+ mi.cch = MAX_PATH;
+ GetMenuItemInfoW(main_menu, id, FALSE, &mi);
+ if (mi.dwItemData == 1)
+ StringCchCatW(curfilename, MAX_PATH, L".zip");
+ else if (mi.dwItemData == 2)
+ StringCchCatW(curfilename, MAX_PATH, L".wsz");
+ else if (mi.dwItemData == 4)
+ StringCchCatW(curfilename, MAX_PATH, L".wal");
+ }
+
+ if (_wcsicmp(config_skin, curfilename))
+ {
+ StringCchCopyW(config_skin, MAX_PATH, curfilename);
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_REFRESHSKIN, 0);
+ if (prefs_last_page == 40 && IsWindow(prefs_hwnd))
+ {
+ prefs_last_page = 0;
+ prefs_dialog(1);
+ prefs_last_page = 40;
+ prefs_dialog(1);
+ }
+ }
+ return 1;
+ }
+
+ if (LOWORD(wID) >= 34700 && LOWORD(wID) < g_LangTop && config_wlz_menu)
+ {
+ wchar_t curfilename[MAX_PATH]={0};
+ int id = LOWORD(wID);
+ if (id >= 34701)
+ {
+ MENUITEMINFOW mi = {sizeof(mi), MIIM_DATA | MIIM_TYPE, MFT_STRING};
+ mi.dwTypeData = curfilename;
+ mi.cch = MAX_PATH;
+ GetMenuItemInfoW(main_menu, id, FALSE, &mi);
+
+ if (mi.dwItemData == 1)
+ StringCchCatW(curfilename, MAX_PATH, L".zip");
+ else if (mi.dwItemData == 2)
+ StringCchCatW(curfilename, MAX_PATH, L".wlz");
+ }
+
+ if (_wcsicmp(config_langpack, curfilename))
+ {
+ LangSwitchToLangPrompt(hMainWindow, curfilename);
+ }
+ return 1;
+ }
+
+ if (LOWORD(wID) >= 45000 && LOWORD(wID) < 55000)
+ {
+ int id = LOWORD(wID);
+ HWND mlhwnd = (HWND)sendMlIpc(0, 0);
+ if (mlhwnd != NULL)
+ {
+ if (!g_open_ml_item_in_pe && !IsWindowVisible(mlhwnd))
+ SendMessageW(hMainWindow, WM_COMMAND, ID_FILE_SHOWLIBRARY, 0);
+
+ // should switching the ml view to the target be disabled if we only want to play the playlist entry in the pe ?
+ if (!g_open_ml_item_in_pe)
+ SendMessageW(mlhwnd, WM_ML_IPC, id - 45000, ML_IPC_SETCURTREEITEM);
+ }
+ return 1;
+ }
+
+ switch (LOWORD(wID))
+ {
+ case ID_HELP_HELPTOPICS:
+ myOpenURL(hwnd, L"https://help.winamp.com/hc/sections/8103009633300-Winamp-Desktop-Player-");
+ break;
+ case ID_HELP_FEEDBACK:
+ {
+ wchar_t url[512] = {0}, winVer[32] = {0}, build[32] = {0};
+ int nWinVer = 0;
+ GetWinVer(winVer, &nWinVer, build);
+ // May 2022 - this services url is dead and we currently don't have a replacement
+ StringCchPrintfW(url, 512, L"http://services.winamp.com/redirect/support?reason=Feedback&subject=Winamp Feedback&product=Winamp Desktop&v=%s Build %d&platform=%s (%s)",
+ WIDEN(APP_VERSION), BUILD_NUMBER, winVer, build);
+ myOpenURL(hwnd, url);
+ break;
+ }
+ case ID_VIS_NEXT:
+ case ID_VIS_PREV:
+ case ID_VIS_RANDOM:
+ case ID_VIS_FS:
+ case ID_VIS_CFG:
+ case ID_VIS_MENU:
+ if (hExternalVisWindow != NULL)
+ SendMessageW(hExternalVisWindow, WM_COMMAND, LOWORD(wID) | (codeNotify << 16), 0);
+ break;
+ case EQ_ENABLE:
+ case IDM_EQ_LOADPRE:
+ case IDM_EQ_LOADMP3:
+ case IDM_EQ_LOADDEFAULT:
+ case ID_LOAD_EQF:
+ case IDM_EQ_SAVEPRE:
+ case IDM_EQ_SAVEMP3:
+ case IDM_EQ_SAVEDEFAULT:
+ case ID_SAVE_EQF:
+ case IDM_EQ_DELPRE:
+ case IDM_EQ_DELMP3:
+ return SendMessageW(hEQWindow, WM_COMMAND, LOWORD(wID), 0);
+ case ID_POST_PLAY_PLAYLIST: g_open_ml_item_in_pe = 0; return 0;
+ case ID_MAIN_PLAY_AUDIOCD:
+ case ID_MAIN_PLAY_AUDIOCD2:
+ case ID_MAIN_PLAY_AUDIOCD3:
+ case ID_MAIN_PLAY_AUDIOCD4:
+ if (g_audiocdletter[LOWORD(wID) - ID_MAIN_PLAY_AUDIOCD])
+ {
+ wchar_t s[32] = {0};
+ StopPlaying(0);
+ StringCchPrintfW(s, 32, L"cda://%c", g_audiocdletter[LOWORD(wID) - ID_MAIN_PLAY_AUDIOCD]);
+ PlayList_delete();
+ PlayList_appendthing(s, 0, 0);
+ BeginPlayback();
+ plEditRefresh();
+ }
+ return 1;
+ case ID_PE_OPEN:
+ {
+ if (!playlist_open(g_dialog_box_parent ? g_dialog_box_parent : hMainWindow)) break;
+ }
+ return 1;
+ case ID_PE_SAVEAS:
+ savepls(DIALOG_PARENT(hMainWindow));
+ return 1;
+ case WINAMP_EDIT_BOOKMARKS:
+ MessageBoxW(hwnd, getStringW(IDS_ML_MISSING_FOR_BOOKMARKS,NULL,0), L"Winamp", MB_OK);
+ return 1;
+ case WINAMP_MAKECURBOOKMARK:
+ {
+ wchar_t fn[FILENAME_SIZE] = {0}, ft[FILETITLE_SIZE] = {0};
+ PlayList_getitem2W(PlayList_getPosition(), fn, ft);
+ Bookmark_additem(fn, ft);
+ }
+ return 1;
+ case WINAMP_LIGHTNING_CLICK: about_dialog(); return 1;
+ case WINAMP_NEW_INSTANCE:
+ {
+ char buf[MAX_PATH] = "\"";
+ STARTUPINFO si = {sizeof(si), };
+ PROCESS_INFORMATION pi;
+ GetModuleFileNameA(NULL, buf + 1, sizeof(buf) - 1);
+ StringCchCatA(buf, MAX_PATH, "\" /NEW");
+ config_write(1);
+ CreateProcessA(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL,(LPSTARTUPINFOA)&si, &pi);
+ }
+ return 1;
+#if 0
+ case WINAMP_VIS_OPTIONS:
+ {
+ extern int last_classic_skin_page;
+ last_classic_skin_page = 1;
+ prefs_last_page = 22;
+ prefs_dialog(1);
+ }
+ return 1;
+#endif
+ case WINAMP_REFRESHSKIN:
+ {
+ g_skinloadedmanually = 1;
+ SendMessageW(hwnd, WM_DISPLAYCHANGE, 0, 0);
+ g_skinloadedmanually = 0;
+ }
+ if (config_pe_open) InvalidateRect(hPLWindow, NULL, FALSE);
+#if 0
+ if (config_mb_open)
+ {
+ RECT r;
+ r.left = 0;r.top = 0;r.right = 11;r.bottom = config_mb_height;
+ InvalidateRect(hMBWindow, &r, FALSE);
+ r.left = 11;r.top = 0;r.right = config_mb_width;r.bottom = 20;
+ InvalidateRect(hMBWindow, &r, FALSE);
+ r.left = config_mb_width - 8;r.top = 20;r.right = config_mb_width;r.bottom = config_mb_height;
+ InvalidateRect(hMBWindow, &r, FALSE);
+ r.left = 11;r.top = config_mb_height - 38;r.right = config_mb_width - 8;r.bottom = config_mb_height;
+ InvalidateRect(hMBWindow, &r, FALSE);
+ }
+#endif
+ if (config_eq_open) InvalidateRect(hEQWindow, NULL, FALSE);
+ if (config_video_open) InvalidateRect(hVideoWindow, NULL, FALSE);
+ // plugin wnds get the WM_DISPLAYCHANGE which is all they need
+ return 1;
+ case WINAMP_SELSKIN:
+ prefs_last_page = 40;
+ prefs_dialog(1);
+ return 1;
+ case WINAMP_VISPLUGIN:
+ if (vis_running()) vis_stop();
+ else vis_start(hMainWindow, NULL);
+ return 1;
+ case WINAMP_PLGSETUP:
+ prefs_last_page = 33;
+ prefs_dialog(1);
+ return 1;
+ case WINAMP_TOGGLE_AUTOSCROLL:
+ config_autoscrollname ^= 1;
+ if (config_autoscrollname == 1) SetTimer(hwnd, UPDATE_DISPLAY_TIMER + 1, 200, NULL);
+ else if (config_autoscrollname == 0)
+ {
+ KillTimer(hwnd, UPDATE_DISPLAY_TIMER + 1);
+ ui_songposition = 0;
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ return 1;
+ case WINAMP_EDIT_ID3:
+ if (FileName[0]) in_infobox(DIALOG_PARENT(hMainWindow), FileName);
+ return 1;
+ case WINAMP_OPTIONS_WINDOWSHADE_PL: // toggle windowshade
+ ToggleWindowShade_PL();
+ return 1;
+ case WINAMP_OPTIONS_WINDOWSHADE_EQ:
+ ToggleWindowShade_EQ();
+ return 1;
+ case WINAMP_OPTIONS_WINDOWSHADE: // toggle windowshade
+ ToggleWindowShade_Main();
+ return 1;
+ case WINAMP_OPTIONS_WINDOWSHADE_GLOBAL: // toggle windowshade
+ {
+ HWND hFocus = GetForegroundWindow();
+ if (hFocus == hPLWindow || IsChild(hFocus, hPLWindow))
+ ToggleWindowShade_PL();
+ else if (hFocus == hEQWindow || IsChild(hFocus, hEQWindow))
+ ToggleWindowShade_EQ();
+ else
+ ToggleWindowShade_Main();
+ }
+ return 1;
+ case ID_PE_CLOSE:
+ case WINAMP_MAIN_WINDOW:
+ config_mw_open = !config_mw_open;
+ if (config_mw_open)
+ {
+ if (config_pe_open && config_pe_width >= 350 && config_pe_height != 14)
+ {
+ RECT r = {config_pe_width - 150 - 75, config_pe_height - 26, r.left + 77, r.top + 16};
+ InvalidateRect(hPLWindow, &r, FALSE);
+ }
+ }
+ else
+ {
+ MoveOffscreen(hwnd);
+ }
+ //sa_setthread(-1);
+ CheckMenuItem(main_menu, WINAMP_MAIN_WINDOW, config_mw_open ? MF_CHECKED : MF_UNCHECKED);
+ set_aot(0);
+
+ Ipc_WindowToggle(IPC_CB_WND_MAIN, config_mw_open);
+
+ case WINAMP_NEXT_WINDOW:
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *p = embedwndlist;
+ int x;
+ int state = 0;
+ for (x = 0; ; x ++)
+ {
+ HWND dockwnd = NULL;
+ int vis = 0;
+ if ( x == 0 )
+ {
+ dockwnd = hMainWindow;
+ vis = config_mw_open;
+ }
+ else if ( x == 1 )
+ {
+ dockwnd = hEQWindow;
+ vis = config_eq_open;
+ }
+ else if ( x == 2 )
+ {
+ dockwnd = hPLWindow;
+ vis = config_pe_open;
+ }
+//else if (x == 3) { /*dockwnd = hMBWindow; vis = 0;*/ } // config_mb_open; }
+ else if ( x == 4 )
+ {
+ dockwnd = hVideoWindow;
+ vis = config_video_open;
+ }
+ else
+ {
+ if ( !p )
+ {
+ if ( state == 1 )
+ {
+ p = embedwndlist;
+ x = -1;
+ state = 2;
+ continue;
+ }
+ else
+ break;
+ }
+ dockwnd = p->me;
+ vis = IsWindowVisible( p->me );
+ }
+
+ if (!state)
+ {
+ HWND fg = GetForegroundWindow();
+ if (fg == dockwnd || IsChild(dockwnd, fg))
+ {
+ state = 1;
+ }
+ }
+ else if (vis)
+ {
+ SetForegroundWindow(dockwnd);
+ break;
+ }
+
+ // changed for 5.58 to cope with x == 3 as this can otherwise cause
+ // one embedwnd to stay as the active window irrespective of doing
+ // additional ctrl+tab actions as it was not wanting to handle x==3
+ if (x == 3 || x > 4)
+ p = p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+ return 1;
+ case WINAMP_HELP_ABOUT: // about box
+ about_dialog();
+ return 1;
+ case WINAMP_PE_SEARCH:
+ case WINAMP_JUMPFILE:
+ jump_file_dialog(hMainWindow);
+ return 1;
+ case WINAMP_TOGGLE_LIBRARY:
+ sendMlIpc(ML_IPC_TOGGLE_VISIBLE, 0);
+ return 1;
+ case WINAMP_JUMP:
+ if (playing && in_mod && in_mod->is_seekable)
+ {
+ jump_dialog(hMainWindow);
+ }
+ return 1;
+ case WINAMP_FFWD5S: // left and right arrows, fastforward and rewind by 5 seconds
+ case WINAMP_REW5S:
+ {
+ int i;
+ if (!in_mod || !in_mod->is_seekable || PlayList_ishidden(PlayList_getPosition())) return 1;
+ if (LOWORD(wID) == WINAMP_FFWD5S) i = 5000;
+ else i = -5000;
+ if (playing)
+ {
+ int t;
+ t = in_getouttime() + i;
+ if (t < 0) t = 0;
+ if (in_seek(t) < 0)
+ SendMessageW(hwnd, WM_WA_MPEG_EOF, 0, 0);
+ else
+ {
+ ui_drawtime(in_getouttime() / 1000, 0);
+ }
+ }
+ }
+ return 1;
+ case WINAMP_MAINMENU: // alt-f for mainmenu
+ {
+ POINT p = { 6, 13 };
+ if (config_dsize)
+ {
+ p.x *= 2;
+ p.y *= 2;
+ }
+ ClientToScreen(hwnd, &p);
+ if ( /*p.x > 3000 || */p.y > OFFSCREEN_Y_POS && p.y < (OFFSCREEN_Y_POS + 2000) )
+ GetCursorPos(&p);
+ DoTrackPopup(main_menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ }
+ return 1;
+ case WINAMP_PREVSONG:
+ {
+ int s = 1;
+ if (!config_shuffle && PlayList_advance( -1) < 0)
+ {
+ s = 0;
+ if (config_repeat)
+ {
+ s = 1;
+ PlayList_advance(BIGINT);
+ }
+ }
+ if (s)
+ {
+ if (PlayList_getlength())
+ {
+ if (config_shuffle)
+ {
+ if (PlayList_randpos( -1)) return 1;
+ }
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ if (playing)
+ {
+ StopPlaying(0);
+ StartPlaying();
+ }
+ else StopPlaying(0);
+ }
+ }
+ }
+ return 0;
+ case WINAMP_BUTTON1_SHIFT: // button 1 (previous), sent from either windowshade,
+ case WINAMP_BUTTON1_CTRL: // keyboard shortcut, or normal buttons (ui.c)
+ case WINAMP_BUTTON1:
+ return (Main_OnButton1(hwnd, LOWORD(wID), hwndCtl, codeNotify));
+ case WINAMP_BUTTON2_SHIFT: // button 2 (play)
+ case WINAMP_BUTTON2_CTRL:
+ case WINAMP_BUTTON2:
+ return (Main_OnButton2(hwnd, LOWORD(wID), hwndCtl, codeNotify));
+ case WINAMP_BUTTON3: // button 3 (pause)
+ return (Main_OnButton3(hwnd, LOWORD(wID), hwndCtl, codeNotify));
+ case WINAMP_BUTTON4_CTRL: // button 4 (stop)
+ case WINAMP_BUTTON4_SHIFT: // button 4 (stop)
+ case WINAMP_BUTTON4:
+ return (Main_OnButton4(hwnd, LOWORD(wID), hwndCtl, codeNotify));
+ case WINAMP_BUTTON5_CTRL: // button 5 (next)
+ case WINAMP_BUTTON5_SHIFT: // button 5 (next)
+ case WINAMP_BUTTON5:
+ return (Main_OnButton5(hwnd, LOWORD(wID), hwndCtl, codeNotify));
+ case WINAMP_FILE_QUIT: // keyboard Alt-X or menu option
+ if (g_exit_disabled) return 0;
+ SendMessageW(hwnd, WM_CLOSE, 0, 0);
+ return 1;
+ case WINAMP_FILE_LOC: // open location
+ getNewLocation(1, DIALOG_PARENT(hwnd));
+ plEditRefresh();
+ return 1;
+ case WINAMP_FILE_PLAY: // open file(s)
+ getNewFile(1, /*NULL*/DIALOG_PARENT(hwnd), 0);
+ plEditRefresh();
+ return 1;
+ case WINAMP_FILE_DIR: // open directory
+ {
+ BROWSEINFOW bi = {0};
+ wchar_t name[MAX_PATH] = {0};
+ bi.hwndOwner = DIALOG_PARENT(hwnd);
+ bi.pszDisplayName = name;
+ bi.lpszTitle = L"__foo";
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist)
+ {
+ wchar_t path[MAX_PATH] = {0};
+ SHGetPathFromIDListW( idlist, path );
+ Shell_Free(idlist);
+ WASABI_API_APP->path_setWorkingPath(path);
+ PlayList_delete();
+ PlayList_adddir(path, (config_rofiob&2) ? 0 : 1);
+ if (config_rofiob&1) PlayList_sort(2, 0);
+ BeginPlayback();
+ plEditRefresh();
+ }
+ }
+ return 1;
+ case WINAMP_OPTIONS_PREFS: // open preferences
+ prefs_dialog(0);
+ return 1;
+ case WINAMP_OPTIONS_AOT: // toggle always on top
+ config_aot = !config_aot;
+ set_aot(0);
+ return 1;
+ case WINAMP_OPTIONS_DSIZE: // toggle doublesize mode
+ config_dsize = !config_dsize;
+ if (!config_bifont && config_bifont_alt) draw_reinit_plfont(1);
+ set_aot(1);
+ return 1;
+ case WINAMP_OPTIONS_EASYMOVE: // toggle easymove (easy window moving)
+ config_easymove = !config_easymove;
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_EASYMOVE, config_easymove ? MF_CHECKED : MF_UNCHECKED);
+ return 1;
+ case WINAMP_FILE_SHUFFLE: // toggle shuffle (and draw button)
+ config_shuffle = !config_shuffle;
+ CheckMenuItem(main_menu, WINAMP_FILE_SHUFFLE, config_shuffle ? MF_CHECKED : MF_UNCHECKED);
+ draw_shuffle(config_shuffle, 0);
+ if (config_shuffle) PlayList_updaterandpos();
+ if (config_shuffle && !playing)
+ {
+ PlayList_randpos( -BIGINT);
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ //draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ draw_songname(getStringW((config_shuffle ? IDS_SHUFFLE_ON : IDS_SHUFFLE_OFF), NULL, 0), &ui_songposition, -2);
+ return 1;
+ case WINAMP_FILE_REPEAT: // toggle repeat
+ {
+ config_repeat = !config_repeat;
+ CheckMenuItem(main_menu, WINAMP_FILE_REPEAT, config_repeat ? MF_CHECKED : MF_UNCHECKED);
+ draw_repeat(config_repeat, 0);
+
+ UINT id = 0;
+ if (!config_repeat) id = IDS_REPEAT_OFF;
+ else if (config_repeat && config_pladv) id = IDS_REPEAT_PL;
+ else if (config_repeat && !config_pladv) id = IDS_REPEAT_TRACK;
+ if (id) draw_songname(getStringW(id, NULL, 0), &ui_songposition, -2);
+ return 1;
+ }
+ case WINAMP_FILE_MANUALPLADVANCE: // toggle manual playlist advance
+ {
+ config_pladv = !config_pladv;
+ UpdateManualAdvanceState();
+
+ UINT id = 0;
+ if (!config_repeat) id = (config_pladv ? IDS_MAN_ADV_OFF : IDS_MAN_ADV_ON);
+ else if (config_repeat && config_pladv) id = IDS_REPEAT_PL;
+ else if (config_repeat && !config_pladv) id = IDS_REPEAT_TRACK;
+ if (id) draw_songname(getStringW(id, NULL, 0), &ui_songposition, -2);
+ return 1;
+ }
+ case WINAMP_OPTIONS_EQ: // toggle EQ window
+ eq_dialog(hwnd,0);
+ return 1;
+ case WINAMP_OPTIONS_PLEDIT: // toggle playlist editor
+ // if we get a 2 then it came from gen_ff so that we can work around a docking/position issue
+ pleditDlg(hwnd,codeNotify==2);
+ return 1;
+ case WINAMP_OPTIONS_VIDEO:
+ config_video_open ? HideVideoWindow(1) : ShowVideoWindow(0);
+ return 1;
+ case WINAMP_OPTIONS_TOGTIME:
+ config_timeleftmode = !config_timeleftmode;
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_ELAPSED, config_timeleftmode ? MF_UNCHECKED : MF_CHECKED);
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_REMAINING, config_timeleftmode ? MF_CHECKED : MF_UNCHECKED);
+ SendMessageW(hwnd, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ return 1;
+ case WINAMP_OPTIONS_ELAPSED: // set time mode to elapsed
+ config_timeleftmode = 0;
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_ELAPSED, MF_CHECKED);
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_REMAINING, MF_UNCHECKED);
+ SendMessageW(hwnd, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ return 1;
+ case WINAMP_OPTIONS_REMAINING: // set time mode to remaining
+ config_timeleftmode = 1;
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_ELAPSED, MF_UNCHECKED);
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_REMAINING, MF_CHECKED);
+ SendMessageW(hwnd, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ return 1;
+ case WINAMP_VOLUMEUP: // increase volume by ~2%
+ case WINAMP_VOLUMEDOWN: // decrease volume by ~2%
+ if (LOWORD(wID) == WINAMP_VOLUMEUP)
+ {
+ if (config_volume <= 251) config_volume += 4;
+ else config_volume = 255;
+ }
+ else
+ {
+ if (config_volume > 3) config_volume -= 4;
+ else config_volume = 0;
+ }
+
+ in_setvol(config_volume);
+ draw_volumebar(config_volume, 0);
+ update_volume_text(-2);
+ return 1;
+ case WINAMP_JUMP10BACK:
+ {
+ int x;
+ int i = playing;
+ if (i) StopPlaying(0);
+ for (x = 0; x < 10; x ++)
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_BUTTON1, 0);
+ if (i) StartPlaying();
+ }
+ return 1;
+ case WINAMP_JUMP10FWD:
+ {
+ int x;
+ int i = playing;
+ if (i) StopPlaying(0);
+ for (x = 0; x < 10; x ++)
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_BUTTON5, 0);
+ if (i) StartPlaying();
+ }
+ return 1;
+ case WINAMP_GETMORESKINS:
+ myOpenURLWithFallback(hwnd, L"http://www.google.com/search?q=Winamp+Skins", L"http://www.google.com/search?q=Winamp+Skins");
+ return 0;
+ case WINAMP_VISCONF:
+ {
+ wchar_t b[MAX_PATH] = {0};
+ HINSTANCE hLib;
+ PathCombineW(b, VISDIR, config_visplugin_name);
+ hLib = LoadLibraryW(b);
+ if (hLib)
+ {
+ winampVisModule *module = NULL;
+ winampVisGetHeaderType pr = (winampVisGetHeaderType) GetProcAddress(hLib, "winampVisGetHeader");
+ winampVisHeader* pv = pr(hMainWindow);
+ if (pv) module = pv->getModule(config_visplugin_num);
+ if (module)
+ {
+ module->hDllInstance = hLib;
+ module->hwndParent = hMainWindow;
+ if (!(config_no_visseh&1))
+ {
+ __try {
+ module->Config(module);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ LPMessageBox(hwnd, IDS_PLUGINERROR, IDS_ERROR, MB_OK | MB_ICONEXCLAMATION);
+ }
+ }
+ else
+ {
+ module->Config(module);
+ }
+ }
+ else
+ {
+ LPMessageBox(hwnd, IDS_ERRORLOADINGPLUGIN, IDS_ERROR, MB_OK);
+ }
+ FreeLibrary(hLib);
+ }
+ }
+ return 1;
+ case WINAMP_MINIMIZE:
+ if (GetAsyncKeyState(VK_SHIFT) >> 15)
+ minimize_hack_winamp = 1;
+ else
+ minimize_hack_winamp = 0;
+ ShowWindow(hMainWindow, SW_MINIMIZE);
+ return 1;
+ case WINAMP_VIDEO_TOGGLE_FS:
+ videoToggleFullscreen();
+ return 1;
+ case ID_MLFILE_NEWPLAYLIST:
+ {
+ HWND h = (HWND)sendMlIpc(0, 0);
+ HWND fgw = GetForegroundWindow();
+ if (h && IsWindow(h) && IsWindowVisible(h) && IsChild(fgw, h))
+ sendMlIpc(ML_IPC_NEWPLAYLIST, (WPARAM)h);
+ else sendMlIpc(ML_IPC_NEWPLAYLIST, (WPARAM)(g_dialog_box_parent ? g_dialog_box_parent : hMainWindow));
+ showLibrary();
+ }
+ return 1;
+ case ID_MLFILE_SAVEPLAYLIST:
+ showLibrary();
+ {
+ HWND h = (HWND)sendMlIpc(0, 0);
+ HWND fgw = GetForegroundWindow();
+ if (h && IsWindow(h) && IsWindowVisible(h) && IsChild(fgw, h))
+ sendMlIpc(ML_IPC_SAVEPLAYLIST, (WPARAM)h);
+ else sendMlIpc(ML_IPC_SAVEPLAYLIST, (WPARAM)(g_dialog_box_parent ? g_dialog_box_parent : hMainWindow));
+ }
+ return 1;
+ case ID_MLFILE_LOADPLAYLIST:
+ {
+ HWND h = (HWND)sendMlIpc(0, 0);
+ HWND fgw = GetForegroundWindow();
+ if (h && IsWindow(h) && IsWindowVisible(h) && IsChild(fgw, h))
+ sendMlIpc(ML_IPC_IMPORTPLAYLIST, (WPARAM)h);
+ else
+ sendMlIpc(ML_IPC_IMPORTPLAYLIST, (WPARAM)(g_dialog_box_parent ? g_dialog_box_parent : hMainWindow));
+ showLibrary();
+ }
+ return 1;
+ case ID_MLFILE_IMPORTCURRENTPLAYLIST:
+ sendMlIpc(ML_IPC_IMPORTCURRENTPLAYLIST, 0);
+ showLibrary();
+ return 1;
+ case ID_MLVIEW_MEDIA:
+#define TREE_LOCALMEDIA 1000
+ showLibrary();
+ sendMlIpc(ML_IPC_SETCURTREEITEM, TREE_LOCALMEDIA);
+ return 1;
+ case ID_MLVIEW_PLAYLISTS:
+#define TREE_PLAYLISTS 3001
+ showLibrary();
+ sendMlIpc(ML_IPC_SETCURTREEITEM, TREE_PLAYLISTS);
+ return 1;
+ case ID_MLVIEW_DEVICES:
+#define TREE_DEVICES 10000
+ showLibrary();
+ sendMlIpc(ML_IPC_SETCURTREEITEM, TREE_DEVICES);
+ return 1;
+ case ID_MLVIEW_INTERNETRADIO:
+#define TREE_INTERNET_RADIO 11000
+ showLibrary();
+ sendMlIpc(ML_IPC_SETCURTREEITEM, TREE_INTERNET_RADIO);
+ return 1;
+ case ID_MLVIEW_INTERNETTV:
+#define TREE_INTERNET_VIDEO 11001
+ showLibrary();
+ sendMlIpc(ML_IPC_SETCURTREEITEM, TREE_INTERNET_VIDEO);
+ return 1;
+ case ID_MLVIEW_LIBRARYPREFERENCES:
+ showLibrary();
+ sendMlIpc(ML_IPC_OPENPREFS, 0);
+ return 1;
+ case ID_PLAY_VOLUMEUP: // increase by ~ 10%
+ {
+ int a = 5;
+ while (a--) SendMessageW(hwnd, WM_COMMAND, WINAMP_VOLUMEUP, 0);
+ }
+ return 1;
+ case ID_PLAY_VOLUMEDOWN: // decrease by ~10%
+ {
+ int a = 5;
+ while (a--)
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_VOLUMEDOWN, 0);
+ }
+ return 1;
+
+ case ID_RATING5: return setCurrentRating(5);
+ case ID_RATING4: return setCurrentRating(4);
+ case ID_RATING3: return setCurrentRating(3);
+ case ID_RATING2: return setCurrentRating(2);
+ case ID_RATING1: return setCurrentRating(1);
+ case ID_RATING0: return setCurrentRating(0);
+ case ID_PL_RATING5: return setPlRating(5);
+ case ID_PL_RATING4: return setPlRating(4);
+ case ID_PL_RATING3: return setPlRating(3);
+ case ID_PL_RATING2: return setPlRating(2);
+ case ID_PL_RATING1: return setPlRating(1);
+ case ID_PL_RATING0: return setPlRating(0);
+
+ case ID_PE_FFOD:
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (!PlayList_getitem2W(PlayList_getPosition(), fn, NULL))
+ {
+ explorerFindFileManager->AddFile(fn);
+ explorerFindFileManager->ShowFiles();
+ }
+ }
+ return 1;
+ } // switch()
+ return 0;
+} // Main_OnCommand() \ No newline at end of file
diff --git a/Src/Winamp/main_display.cpp b/Src/Winamp/main_display.cpp
new file mode 100644
index 00000000..ddc4296c
--- /dev/null
+++ b/Src/Winamp/main_display.cpp
@@ -0,0 +1,122 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "wa_dlg.h"
+#include "../nu/AutoChar.h"
+#include "resource.h"
+
+extern "C" extern int g_skinloadedmanually;
+
+int Main_OnGetText(wchar_t *text, int sizeCch)
+{
+ size_t rem;
+ StringCchCopyExW(text, sizeCch, caption, 0, &rem, 0);
+ return (int)sizeCch-rem;
+
+}
+// evil 256 color mode windows palette handling
+int Main_OnQueryNewPalette(HWND hwnd)
+{
+ if (draw_hpal) { // hPal is NULL if we're in hicolor
+ HDC hdc = GetWindowDC(hwnd);
+ SelectPalette(hdc,draw_hpal,FALSE);
+ RealizePalette(hdc);
+ InvalidateRect(hwnd,NULL,FALSE);
+ ReleaseDC(hwnd,hdc);
+ }
+ return 1;
+}
+
+// more 256 color windows palette handling
+int Main_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange)
+{
+ if (draw_hpal)
+ {
+ HDC hdc = GetWindowDC(hwnd);
+ SelectPalette(hdc,draw_hpal,FALSE);
+ RealizePalette(hdc);
+ UpdateColors(hdc);
+ ReleaseDC(hwnd,hdc);
+ }
+ return 1;
+}
+
+// displaychange handling. This reinitializes bitmaps, to use optimal storage format
+// depending on mode (DIB or DDB)
+int Main_OnDisplayChange(HWND hwnd)
+{
+ int t=0;
+ if (g_skinloadedmanually)
+ {
+ Skin_Load();
+ }
+
+ if (g_skinmissinggenff)
+ {
+ wchar_t msg[512] = {0};
+ StringCchPrintfW(msg, 512, getStringW(IDS_NO_MODERN_SKIN_SUPPORT, NULL, 0), config_skin);
+ MessageBoxW(NULL, msg, getStringW(IDS_SKIN_LOAD_ERROR, NULL, 0), MB_ICONWARNING | MB_OK | MB_TOPMOST);
+ }
+
+ draw_setnoupdate(1);
+ draw_init();
+ draw_clutterbar(0);
+ draw_shuffle(config_shuffle,0);
+ draw_eject(0);
+ draw_eqplbut(config_eq_open,0,config_pe_open,0);
+ draw_repeat(config_repeat,0);
+ draw_buttonbar(-1);
+ draw_volumebar(config_volume,0);
+ draw_panbar(config_pan,0);
+ draw_songname(L"",&t,0);
+ draw_playicon(playing?paused?4:1:2);
+ draw_tbar(config_hilite?(GetForegroundWindow() == hMainWindow?1:0):1, config_windowshade,eggstat);
+
+ draw_monostereo(-1);
+ if (playing)
+ {
+ draw_bitmixrate(-1,-1);
+ }
+
+ draw_setnoupdate(0);
+ draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
+
+ // tell other windows
+ if (IsWindow(hVideoWindow))
+ SendMessageW(hVideoWindow, WM_DISPLAYCHANGE,0,0);
+ if (IsWindow(hEQWindow))
+ SendMessageW(hEQWindow, WM_DISPLAYCHANGE,0,0);
+ if (IsWindow(hPLWindow))
+ SendMessageW(hPLWindow, WM_DISPLAYCHANGE,0,0);
+ /*
+ if (IsWindow(hMBWindow))
+ SendMessageW(hVideoWindow, WM_DISPLAYCHANGE,0,0);
+ */
+ if (IsWindow(hExternalVisWindow))
+ SendMessageW(hExternalVisWindow, WM_DISPLAYCHANGE,0,0);
+
+ SetTimer(hMainWindow, 101, 250, NULL); // set_aot(-1);
+
+ InvalidateRect(hwnd,NULL,FALSE);
+ //UpdateWindow(hwnd);
+
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *p =embedwndlist;
+ while (p)
+ {
+ PostMessageW(p->me,WM_DISPLAYCHANGE,0,0);
+ p=p->link;
+ }
+ }
+
+ LeaveCriticalSection(&embedcs);
+
+ PostMessageW(hMainWindow, WM_WA_IPC, 0, IPC_SKIN_CHANGED);
+ return 1;
+}
diff --git a/Src/Winamp/main_init.cpp b/Src/Winamp/main_init.cpp
new file mode 100644
index 00000000..70f634a6
--- /dev/null
+++ b/Src/Winamp/main_init.cpp
@@ -0,0 +1,322 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "menuv5.h"
+#include "resource.h"
+
+extern "C"
+{
+ int g_main_created = 0;
+}
+
+static INT_PTR CALLBACK tmpProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+BOOL InitApplication(HINSTANCE hInstance) // register Winamp's window class, returns TRUE on success
+{
+ HICON hIcon;
+ WNDCLASSW wc = {0, };
+
+ wc.style = CS_DBLCLKS;
+ wc.hInstance = hInstance;
+ hIcon = wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(ICON_XP));
+ wc.hCursor = NULL;
+
+ //wc.lpfnWndProc = Main_WndProc;
+ //wc.lpszClassName = L"Winamp";;
+ //if (!RegisterClassW( &wc ))
+ // return 0;
+
+ wc.lpfnWndProc = VIS_WndProc;
+ wc.lpszClassName = L"WinampVis";
+ if (!RegisterClassW(&wc))
+ return 0;
+
+
+ wc.lpfnWndProc = video_WndProc;
+ wc.lpszClassName = L"Winamp Video";
+ if (!RegisterClassW(&wc))
+ return 0;
+
+#ifdef WA2
+#ifndef NETSCAPE
+ wc.style = CS_DBLCLKS;
+ wc.lpfnWndProc = MB_WndProc;
+ wc.lpszClassName = "Winamp MB";
+ if (!RegisterClassW(&wc))
+ return 0;
+#endif
+#endif
+
+ /* now register unicode windows */
+ WNDCLASSW wcW = {0, };
+
+ wcW.style = CS_DBLCLKS;
+ wcW.hInstance = hInstance;
+ hIcon = wcW.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(ICON_XP));
+ wcW.hCursor = NULL;
+
+ wcW.lpfnWndProc = emb_WndProc;
+ wcW.lpszClassName = L"Winamp Gen";
+ if (!RegisterClassW(&wcW))
+ return 0;
+
+ wcW.style |= CS_VREDRAW | CS_HREDRAW;
+ wcW.lpfnWndProc = EQ_WndProc;
+ wcW.lpszClassName = L"Winamp EQ";
+ if (!RegisterClassW(&wcW))
+ return 0;
+
+ wcW.lpfnWndProc = PE_WndProc;
+ wcW.lpszClassName = L"Winamp PE";
+ if (!RegisterClassW(&wcW))
+ return 0;
+
+ // make other people's dialogs show the winamp icon
+ HWND h = CreateDialogW(hMainInstance, MAKEINTRESOURCE(IDD_OPENLOC), NULL, tmpProc);
+ SetClassLongPtrW(h, GCLP_HICON, (LONG_PTR)hIcon);
+ DestroyWindow(h);
+
+ return 1;
+}
+
+void ConvertRatingMenuStar(HMENU menu, UINT menu_id)
+{
+MENUITEMINFOW mi = {sizeof(mi), MIIM_DATA | MIIM_TYPE, MFT_STRING};
+wchar_t rateBuf[32], *rateStr = rateBuf;
+ mi.dwTypeData = rateBuf;
+ mi.cch = 32;
+ if(GetMenuItemInfoW(menu, menu_id, FALSE, &mi))
+ {
+ while(rateStr && *rateStr)
+ {
+ if(*rateStr == L'*') *rateStr = L'\u2605';
+ rateStr=CharNextW(rateStr);
+ }
+ SetMenuItemInfoW(menu, menu_id, FALSE, &mi);
+ }
+}
+
+void main_Create()
+{
+ static int t = 0;
+
+ g_main_created = 1;
+ SetWindowTextW(hMainWindow, caption);
+
+ hVisWindow = CreateWindowExW(0, L"WinampVis", L"", WS_CHILD, 0, 0, 0, 0,
+ hMainWindow, NULL, hMainInstance, NULL);
+ ShowWindow(hVisWindow, SW_SHOWNA);
+
+ SetWindowLong(hMainWindow, GWLP_USERDATA, (config_keeponscreen&2) ? 0x49474541 : 0);
+ hTooltipWindow = CreateWindowW(TOOLTIPS_CLASSW, (LPCWSTR)NULL, TTS_ALWAYSTIP | TTS_NOPREFIX,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ hMainWindow, NULL, hMainInstance, NULL);
+ SendMessageW(hTooltipWindow, TTM_SETDELAYTIME, TTDT_INITIAL, 375);
+ SendMessageW(hTooltipWindow, TTM_SETDELAYTIME, TTDT_AUTOPOP, 2000);
+ SendMessageW(hTooltipWindow, TTM_SETDELAYTIME, TTDT_RESHOW, 1000);
+
+ hEQTooltipWindow = CreateWindowW(TOOLTIPS_CLASSW, (LPCWSTR)NULL, TTS_ALWAYSTIP | TTS_NOPREFIX,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ hEQWindow, NULL, hMainInstance, NULL);
+ SendMessageW(hEQTooltipWindow, TTM_SETDELAYTIME, TTDT_INITIAL, 125);
+ SendMessageW(hEQTooltipWindow, TTM_SETDELAYTIME, TTDT_AUTOPOP, 2000);
+ SendMessageW(hEQTooltipWindow, TTM_SETDELAYTIME, TTDT_RESHOW, 1000);
+
+
+ hVideoTooltipWindow = CreateWindowW(TOOLTIPS_CLASSW, (LPCWSTR)NULL, TTS_ALWAYSTIP | TTS_NOPREFIX,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ hVideoWindow, NULL, hMainInstance, NULL);
+ SendMessageW(hVideoTooltipWindow, TTM_SETDELAYTIME, TTDT_INITIAL, 125);
+ SendMessageW(hVideoTooltipWindow, TTM_SETDELAYTIME, TTDT_AUTOPOP, 2000);
+ SendMessageW(hVideoTooltipWindow, TTM_SETDELAYTIME, TTDT_RESHOW, 1000);
+
+ hPLTooltipWindow = CreateWindowW(TOOLTIPS_CLASSW, (LPCWSTR)NULL, TTS_ALWAYSTIP | TTS_NOPREFIX,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ hPLWindow, NULL, hMainInstance, NULL);
+ SendMessageW(hPLTooltipWindow, TTM_SETDELAYTIME, TTDT_INITIAL, 125);
+ SendMessageW(hPLTooltipWindow, TTM_SETDELAYTIME, TTDT_AUTOPOP, 2000);
+ SendMessageW(hPLTooltipWindow, TTM_SETDELAYTIME, TTDT_RESHOW, 1000);
+
+ /*hPL2TooltipWindow = CreateWindowW(TOOLTIPS_CLASSW, (LPCWSTR)NULL, TTS_ALWAYSTIP | TTS_NOPREFIX,
+ 0, 0, 0, 0, hPLWindow, NULL, hMainInstance, NULL);*/
+ // TODO attempt to make this more like the listview timings
+ /*SendMessageW(hPL2TooltipWindow, TTM_SETDELAYTIME, TTDT_INITIAL, 125);
+ SendMessageW(hPL2TooltipWindow, TTM_SETDELAYTIME, TTDT_AUTOPOP, 2000);
+ SendMessageW(hPL2TooltipWindow, TTM_SETDELAYTIME, TTDT_RESHOW, 1000);*/
+
+ SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
+
+ top_menu = LPLoadMenu(WINAMP_MAIN);
+
+#ifdef NETSCAPE
+ EnableMenuItem(top_menu, WINAMP_OPTIONS_MINIBROWSER, MF_BYCOMMAND | MF_GRAYED);
+#endif
+ main_menu = GetSubMenu(top_menu, 0);
+
+ g_submenus_play = GetSubMenu(main_menu, 2);
+ g_submenus_bookmarks1 = GetSubMenu(main_menu, 4);
+ g_submenus_bookmarks2 = GetSubMenu(GetSubMenu(main_menu, 2), 4 + (g_audiocdletters ? g_audiocdletters + 1 : 0));
+ g_submenus_skins1 = GetSubMenu(main_menu, MAINMENU_OPTIONS_BASE + 3);
+ g_submenus_skins2 = GetSubMenu(GetSubMenu(main_menu, MAINMENU_OPTIONS_BASE), 1);
+ g_submenus_vis = GetSubMenu(main_menu, MAINMENU_OPTIONS_BASE + 2);
+ g_submenus_options = GetSubMenu(main_menu, MAINMENU_OPTIONS_BASE);
+
+ if (config_wlz_menu)
+ {
+ MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU | MIIM_TYPE | MIIM_ID, MFT_STRING, };
+ mii.hSubMenu = g_submenus_lang = CreatePopupMenu();
+ mii.dwTypeData = getStringW(IDS_LANGUAGEPACKS_MENU, NULL, 0);
+ mii.cch = (UINT)wcslen(mii.dwTypeData);
+ g_submenus_lang_id = mii.wID = unique_loword_command++;
+ InsertMenuItemW(main_menu, MAINMENU_OPTIONS_BASE+4, TRUE, &mii);
+ }
+
+ HMENU rating_menu = GetSubMenu(GetSubMenu(GetSubMenu(top_menu,2),5),10);
+ ConvertRatingMenuStar(rating_menu, ID_PL_RATING5);
+ ConvertRatingMenuStar(rating_menu, ID_PL_RATING4);
+ ConvertRatingMenuStar(rating_menu, ID_PL_RATING3);
+ ConvertRatingMenuStar(rating_menu, ID_PL_RATING2);
+ ConvertRatingMenuStar(rating_menu, ID_PL_RATING1);
+
+ rating_menu = GetSubMenu(GetSubMenu(GetSubMenu(top_menu,3),0),5);
+ ConvertRatingMenuStar(rating_menu, ID_RATING5);
+ ConvertRatingMenuStar(rating_menu, ID_RATING4);
+ ConvertRatingMenuStar(rating_menu, ID_RATING3);
+ ConvertRatingMenuStar(rating_menu, ID_RATING2);
+ ConvertRatingMenuStar(rating_menu, ID_RATING1);
+
+ Skin_Random();
+ Skin_Load();
+
+ g_skinloadedmanually = 0;
+ set_aot(0);
+ set_taskbar();
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_EASYMOVE, config_easymove ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(main_menu, WINAMP_FILE_SHUFFLE, config_shuffle ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(main_menu, WINAMP_FILE_REPEAT, config_repeat ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(GetSubMenu(GetSubMenu(top_menu, 3), 13), ID_VIDEOWND_VERTICALLYFLIP, (config_video_fliprgb ? MF_CHECKED: MF_UNCHECKED));
+ if (!config_timeleftmode)
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_ELAPSED, MF_CHECKED);
+ else
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_REMAINING, MF_CHECKED);
+ draw_setnoupdate(1);
+ draw_init();
+ draw_shuffle(config_shuffle, 0);
+ draw_eqplbut(config_eq_open, 0, config_pe_open, 0);
+ draw_repeat(config_repeat, 0);
+ draw_eject(0);
+ draw_buttonbar( -1);
+ draw_volumebar(config_volume, 0);
+ draw_panbar(config_pan, 0);
+ draw_songname(L"", &t, 0);
+ draw_playicon(2);
+ draw_clutterbar(0);
+ draw_monostereo(0);
+ draw_tbar(1, config_windowshade, 0);
+ draw_setnoupdate(0);
+ InsertMenuW(GetSystemMenu(hMainWindow, FALSE), 0, MF_POPUP | MF_BYPOSITION, (UINT_PTR) main_menu, L"Winamp");
+ InsertMenu(GetSystemMenu(hMainWindow, FALSE), 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
+ if (config_autoscrollname) SetTimer(hMainWindow, UPDATE_DISPLAY_TIMER + 1, 200, NULL);
+
+ if (config_shuffle) PlayList_randpos( -BIGINT);
+ dsp_init();
+
+ newversioncheck();
+
+ SetTimer(hMainWindow, STATS_TIMER, 1000, NULL);
+}
+
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) // create the main Winamp window
+{
+ int sc = config_minimized; // config_minimized gets trashed in WM_CREATE
+ deferring_show = 1;
+
+ main_Create();
+ out_setwnd();
+
+ if (!CreateWindowExW(0, L"Winamp EQ", getStringW(IDS_EQCAPTION, NULL, 0), WS_OVERLAPPED,
+ config_eq_wx, config_eq_wy, 0, 0, // WM_CREATE will size it
+ hMainWindow, NULL, hInstance, NULL)) return FALSE;
+
+ if (!CreateWindowExW(WS_EX_ACCEPTFILES, L"Winamp PE", getStringW(IDS_PECAPTION, NULL, 0), WS_OVERLAPPED,
+ config_pe_wx, config_pe_wy, 0, 0, // WM_CREATE will size it
+ hMainWindow, NULL, hInstance, NULL)) return FALSE;
+
+ if (!video_Create())
+ return FALSE;
+
+ hPLVisWindow = CreateWindowExW(0, L"WinampVis", L"", WS_CHILD,
+ 0, 0, 0, 0,
+ hPLWindow, NULL, hMainInstance, NULL);
+ ShowWindow(hPLVisWindow, SW_SHOWNA);
+
+ eq_startuphack = pe_startuphack = 1;
+
+ if (config_eq_open)
+ {
+ config_eq_open = 0;
+ eq_dialog(hMainWindow,sc);
+ }
+ // MessageBox(NULL,"p4","0",0);
+ if (config_pe_open)
+ {
+ config_pe_open = 0;
+ pleditDlg(hMainWindow,sc);
+ }
+ if (config_video_open)
+ {
+ config_video_open = 0;
+ ShowVideoWindow(sc);
+ }
+ // MessageBox(NULL,"p5","0",0);
+ if (!config_mw_open)
+ {
+ MoveOffscreen(hMainWindow);
+ Ipc_WindowToggle(IPC_CB_WND_MAIN, config_mw_open);
+ //config_mw_open=1;
+ //SendMessageW(hMainWindow,WM_COMMAND,WINAMP_MAIN_WINDOW,0);
+ }
+ else
+ CheckMenuItem(main_menu, WINAMP_MAIN_WINDOW, MF_CHECKED);
+
+ eq_startuphack = pe_startuphack = 0;
+
+ /*
+ Browser_init();
+ if (config_si_open)
+ OpenBrowser();
+*/
+ if (sc)
+ g_showcode = SW_SHOWMINIMIZED;
+ else if (nCmdShow == SW_SHOWMAXIMIZED || nCmdShow == SW_MAXIMIZE)
+ g_showcode = SW_SHOWNORMAL;
+ else
+ g_showcode = nCmdShow;
+
+ v5_top_menu = LPLoadMenu(WINAMP5_MENUBAR);
+
+ if (config_wlz_menu)
+ {
+ MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU | MIIM_TYPE | MIIM_ID, MFT_STRING, };
+ mii.hSubMenu = g_submenus_lang;
+ mii.dwTypeData = getStringW(IDS_LANGUAGEPACKS_MENU, NULL, 0);
+ mii.cch = (UINT)wcslen(mii.dwTypeData);
+ mii.wID = g_submenus_lang_id;
+ InsertMenuItemW(GetSubMenu(v5_top_menu, 2), 1, TRUE, &mii);
+ g_mm_ffoptionsbase_adj++;
+ }
+
+ SetTimer(hMainWindow, 200, 5, NULL); // defer main window showing
+
+ BeginFullscreenAppMonitor();
+
+ return TRUE;
+} \ No newline at end of file
diff --git a/Src/Winamp/main_mouse.cpp b/Src/Winamp/main_mouse.cpp
new file mode 100644
index 00000000..400e4893
--- /dev/null
+++ b/Src/Winamp/main_mouse.cpp
@@ -0,0 +1,280 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "resource.h"
+#include "../Plugins/General/gen_ml/ml.h"
+extern "C" HMENU g_submenus_vis;
+#include "../Plugins/General/gen_ml/ml_ipc.h"
+extern librarySendToMenuStruct mainSendTo;
+#include "../Plugins/General/gen_ml/menufucker.h"
+
+void ScaleMouseButtons(int &x, int &y)
+{
+ if (config_dsize)
+ {
+ x /= 2;
+ y /= 2;
+ }
+}
+
+// Pops up a menu on right click
+int Main_OnRButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ HMENU hmenu=main_menu;
+ POINT p;
+
+ if ((flags & MK_LBUTTON)) return 1;
+
+ GetCursorPos(&p);
+ ScaleMouseButtons(x,y);
+
+ if (x < 266 && x > 105 && y < 35 && y > 24)
+ {
+ int rating = 0;
+ static HMENU ratingmenu = NULL;
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),0);
+ CheckMenuItem(hmenu,WINAMP_TOGGLE_AUTOSCROLL,(config_autoscrollname&1)?MF_CHECKED:MF_UNCHECKED);
+ rating = sendMlIpc(ML_IPC_GETRATING, 0);
+ // deal with no ml being present and querying the rating of a file from the tag (if possible)
+ // as well as getting a zero rating which could mean that it's not present in the library
+ if (!rating && !got_ml)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ if (!PlayList_getitem2W(PlayList_getPosition(), fn, NULL))
+ {
+ wchar_t buf[64] = {0};
+ in_get_extended_fileinfoW(fn, L"rating", buf, 64);
+ rating = _wtoi(buf);
+ }
+ }
+
+ if(!IsMenu(ratingmenu))
+ {
+ ratingmenu = GetSubMenu(hmenu, 5);
+ }
+
+ CheckMenuItem(ratingmenu, ID_RATING5, (rating == 5) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingmenu, ID_RATING4, (rating == 4) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingmenu, ID_RATING3, (rating == 3) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingmenu, ID_RATING2, (rating == 2) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingmenu, ID_RATING1, (rating == 1) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(ratingmenu, ID_RATING0, (rating == 0) ? MF_CHECKED : MF_UNCHECKED);
+
+ LRESULT IPC_LIBRARY_SENDTOMENU = wa_register_ipc((WPARAM)&"LibrarySendToMenu");
+ HMENU menu = 0;
+ memset(&mainSendTo, 0, sizeof(mainSendTo));
+ if (IPC_LIBRARY_SENDTOMENU > 65536 && SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)0, IPC_LIBRARY_SENDTOMENU) == 0xffffffff)
+ {
+ MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU | MIIM_TYPE, MFT_STRING, };
+ mii.hSubMenu = menu = CreatePopupMenu();
+ mii.dwTypeData = getStringW(IDS_SENDTO_STR,NULL,0);
+ mii.cch = (UINT)wcslen(mii.dwTypeData);
+
+ InsertMenuItemW(hmenu, 4, TRUE, &mii);
+
+ mainSendTo.mode = 1;
+ mainSendTo.hwnd = hwnd;
+ mainSendTo.data_type = ML_TYPE_FILENAMESW;
+ mainSendTo.build_hMenu = menu;
+ }
+
+ menufucker_t mf = {sizeof(mf),MENU_SONGTICKER,hmenu,0x3000,0x4000,0};
+ pluginMessage message_build = {(int)wa_register_ipc((WPARAM)&"menufucker_build"),(intptr_t)&mf,0};
+ sendMlIpc(ML_IPC_SEND_PLUGIN_MESSAGE,(WPARAM)&message_build);
+
+ int ret = DoTrackPopup(hmenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, p.x, p.y, hwnd);
+
+ pluginMessage message_result = {(int)wa_register_ipc((WPARAM)&"menufucker_result"),(intptr_t)&mf,ret,0};
+ sendMlIpc(ML_IPC_SEND_PLUGIN_MESSAGE,(WPARAM)&message_result);
+
+ if (menu)
+ {
+ if (mainSendTo.mode == 2)
+ {
+ mainSendTo.menu_id = ret;
+ if (SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&mainSendTo, IPC_LIBRARY_SENDTOMENU) == 0xffffffff)
+ {
+ wchar_t buf[1041] = {0};
+ wchar_t *end=buf;
+ size_t endSize;
+ StringCchCopyExW(buf, 1040, FileName, &end, &endSize, 0);
+ end[1]=0; // double null terminate (since we passed 1040 for a 1041 size buffer, this is always safe)
+
+ mainSendTo.mode = 3;
+ mainSendTo.data = buf;
+ mainSendTo.data_type = ML_TYPE_FILENAMESW;
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&mainSendTo, IPC_LIBRARY_SENDTOMENU);
+ }
+ }
+ // remove sendto
+ DeleteMenu(hmenu, 4, MF_BYPOSITION);
+ }
+ if (mainSendTo.mode)
+ {
+ mainSendTo.mode = 4;
+ SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&mainSendTo, IPC_LIBRARY_SENDTOMENU); // cleanup
+ memset(&mainSendTo, 0, sizeof(mainSendTo));
+ }
+ if (ret) SendMessageW(hwnd, WM_COMMAND, ret, 0);
+ return 1;
+ }
+ else if ((!config_windowshade && x >= 36 && y >= 26 && x < 96 && y < 39) ||
+ (config_windowshade && x >= 129 && y >= 3 && x < 129+28 && y < 3+6))
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),1);
+ CheckMenuItem(hmenu,WINAMP_OPTIONS_ELAPSED,config_timeleftmode?MF_UNCHECKED:MF_CHECKED);
+ CheckMenuItem(hmenu,WINAMP_OPTIONS_REMAINING,config_timeleftmode?MF_CHECKED:MF_UNCHECKED);
+ }
+ else if ((x >= 27 && y >= 40 && x < 99 && y < 61) ||
+ (config_windowshade && x >= 78 && y >= 4 && x < 116 && y < 11))
+ {
+ hmenu=g_submenus_vis;
+ }
+ else if ((x >= 16 && y >= 88 && x < 37 && y < 106) || /// button 1
+ (config_windowshade && x >= 167 && y >= 3 && x < 176 && y < 12))
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),2);
+ }
+ else if ((x >= 37 && y >= 88 && x < 62 && y < 106) || /// button 2
+ (config_windowshade && x >= 176 && y >= 3 && x < 186 && y < 12))
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),3);
+ }
+ else if ((x >= 62 && y >= 88 && x < 89 && y < 106) || /// button 3
+ (config_windowshade && x >= 186 && y >= 3 && x < 196 && y < 12))
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),4);
+ }
+ else if ((x >= 89 && y >= 88 && x < 107 && y < 106) || /// button 4
+ (config_windowshade && x >= 196 && y >= 3 && x < 206 && y < 12))
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),5);
+ }
+ else if ((x >= 107 && y >= 88 && x < 130 && y < 106) || /// button 5
+ (config_windowshade && x >= 206 && y >= 3 && x < 216 && y < 12))
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),6);
+ }
+ else if ((x >= 136 && y >= 89 && x < 158 && y < 105) || /// eject
+ (config_windowshade && x >= 215 && y >= 3 && x < 225 && y < 12))
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),7);
+ UpdateAudioCDMenus(hmenu);
+ }
+ else if (playing && (in_mod && in_mod->is_seekable) && x >= 18 && y >= 73 && x < 263 && y < 81)
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),8);
+ }
+ else if (x >= 164 && y >= 89 && x < 211 && y < 104) /// shuffle
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),9);
+ CheckMenuItem(hmenu,WINAMP_FILE_SHUFFLE,config_shuffle?MF_CHECKED:MF_UNCHECKED);
+ }
+ else if (x >= 211 && y >= 89 && x < 211+28 && y < 104) /// repeat
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),10);
+ CheckMenuItem(hmenu,WINAMP_FILE_REPEAT,config_repeat?MF_CHECKED:MF_UNCHECKED);
+ CheckMenuItem(hmenu,WINAMP_FILE_MANUALPLADVANCE,config_pladv?MF_UNCHECKED:MF_CHECKED);
+ }
+ else if (x >= 219 && y >= 58 && x < 219+(265-219)/2 && y < 70) /// eq
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),11);
+ CheckMenuItem(hmenu,WINAMP_OPTIONS_EQ,config_eq_open?MF_CHECKED:MF_UNCHECKED);
+ }
+ else if (x >= 219+(265-219)/2 && y >= 58 && x < 265 && y < 70) /// pe
+ {
+ hmenu = GetSubMenu(GetSubMenu(top_menu,3),12);
+ CheckMenuItem(hmenu,WINAMP_OPTIONS_PLEDIT,config_pe_open?MF_CHECKED:MF_UNCHECKED);
+ }
+ DoTrackPopup(hmenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ return 1;
+}
+
+// Doubleclick handler. Checks for a few regions, and usually does nothing,
+// except pass on a WM_LBUTTONDOWN.
+int Main_OnLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
+{
+ int nx=x, ny=y;
+
+ ScaleMouseButtons(nx,ny);
+
+ if (nx <= 16 && nx >= 6 && ny <= 12 && ny >= 4)
+ {
+ KillTimer(hwnd,666);
+ SendMessageW(hwnd,WM_CLOSE,0xDEADBEEF,0xDEADF00D);
+ }
+ else if (config_windowshade && nx <= 158 && nx >= 129 &&
+ ny <= 10 && ny >= 5)
+ Main_OnLButtonDown(hwnd,0,x,y,keyFlags);
+ else if (config_windowshade && nx <= 213 && nx >= 168 &&
+ ny <= 11 && ny >= 2)
+ Main_OnLButtonDown(hwnd,0,x,y,keyFlags);
+ else if (nx < 266 && nx > 117 && ny < 35 && ny > 24)
+ {
+ SendMessageW(hwnd,WM_COMMAND,WINAMP_EDIT_ID3,0);
+ }
+ else if ((nx >= 24 && ny >= 43 && nx < 24+76 && ny < 43+16) ||
+ (config_windowshade && nx >= 79 && ny >= 5 && nx < 79+38 && ny < 5+5))
+ {
+ if (config_windowshade) config_sa = !config_sa;
+ else
+ {
+ config_sa+=2;
+ config_sa %= 3;
+ }
+ sa_setthread(config_sa);
+ if (vis_running()) vis_stop();
+ else vis_start(hMainWindow,NULL);
+ }
+ else if (ny < 15 && nx < 244)
+ {
+ SendMessageW(hwnd,WM_COMMAND,WINAMP_OPTIONS_WINDOWSHADE,0);
+ UpdateWindow(hwnd);
+ Sleep(200);
+ for (;;)
+ {
+ MSG msg;
+ if (!PeekMessage(&msg,hMainWindow,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
+ break;
+ }
+ }
+ else Main_OnLButtonDown(hwnd,0,x,y,keyFlags);
+ return 1;
+}
+
+int Main_OnCaptureChanged(HWND hwnd)
+{
+ if (hwnd != hMainWindow)
+ ui_handlemouseevent(0,0,-2,0);
+ return 0;
+}
+// Mouseup handler. Just passes to routines in ui.c, scaling if in doublesize mode
+int Main_OnLButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ ScaleMouseButtons(x,y);
+ ui_handlemouseevent(x,y,-1,flags);
+ ReleaseCapture();
+ return 1;
+}
+
+// Mousedown handler. Just passes to routines in ui.c, scaling if in doublesize mode
+int Main_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
+{
+ ScaleMouseButtons(x,y);
+ SetCapture(hwnd);
+ ui_handlemouseevent(x,y,1,keyFlags);
+ return 1;
+}
+
+// Mousemove handler. Just passes to routines in ui.c, scaling if in doublesize mode
+int Main_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
+{
+ ScaleMouseButtons(x,y);
+ ui_handlemouseevent(x,y,0,keyFlags);
+ return 1;
+} \ No newline at end of file
diff --git a/Src/Winamp/main_nonclient.cpp b/Src/Winamp/main_nonclient.cpp
new file mode 100644
index 00000000..c481ce0c
--- /dev/null
+++ b/Src/Winamp/main_nonclient.cpp
@@ -0,0 +1,40 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+UINT Main_OnNCHitTest(HWND hwnd, int x, int y)
+{
+ return HTCLIENT;
+}
+
+BOOL Main_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized)
+{
+ if (fActive == FALSE)
+ {
+ draw_tbar(config_hilite ? 0 : 1, config_windowshade, eggstat);
+ if (config_windowshade) SendMessageW(hwnd, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ }
+ else
+ {
+ static int i;
+ if (i) draw_tbar(1, config_windowshade, eggstat);
+ i = 1;
+ if (config_windowshade) SendMessageW(hwnd, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ }
+
+ return TRUE;
+}
+
+UINT Main_OnNCCalcSize(HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS * lpcsp)
+{
+ /*if (fCalcValidRects)
+ {}
+ else
+ {}*/
+ return WVR_ALIGNTOP | WVR_ALIGNBOTTOM | WVR_ALIGNRIGHT | WVR_ALIGNLEFT;
+}
+
diff --git a/Src/Winamp/main_timer.cpp b/Src/Winamp/main_timer.cpp
new file mode 100644
index 00000000..12824cdf
--- /dev/null
+++ b/Src/Winamp/main_timer.cpp
@@ -0,0 +1,133 @@
+#include "main.h"
+#include "stats.h"
+
+// Display update, and menu popping up (vs killing)
+LRESULT Main_OnTimer(HWND hwnd, UINT id)
+{
+#ifdef BENSKI_TEST_WM_PRINTCLIENT
+ if (id == 9999)
+ {
+ PrintWindow(hPLWindow);
+ }
+#endif
+ if (id == 99)
+ {
+ // 250 ms after a fs application has settled on
+ KillTimer(hMainWindow, 99);
+ g_dropaot_timer_set = 0;
+ dropAOT();
+ return 0;
+ }
+ if (id == 100)
+ {
+ // 250 ms after a fs application has settled off
+ KillTimer(hMainWindow, 100);
+ g_restoreaot_timer_set = 0;
+ restoreAOT();
+ return 0;
+ }
+ if (id == 101)
+ {
+ KillTimer(hMainWindow, 101);
+ // 250ms after wm_displaychange, enforce config_keeponscreen, but not if the display change was because of a
+ // fullscreen app, like a game
+ if (!g_fsapp) set_aot(-1);
+ }
+ if (id == 200)
+ {
+ KillTimer(hMainWindow, 200);
+ if (!deferring_show)
+ return 0;
+ deferring_show = 0;
+ if (g_showcode == SW_SHOWMINIMIZED && config_taskbar)
+ {
+ ShowWindow(hMainWindow, SW_SHOWNORMAL);
+ }
+ ShowWindow(hMainWindow, g_showcode);
+ return 0;
+ }
+ if (id == STATS_TIMER)
+ {
+ stats.IncrementStat(Stats::TIME_RUNNING);
+ if (playing) stats.IncrementStat(Stats::TIME_PLAYING);
+ if (!config_minimized) stats.IncrementStat(Stats::TIME_VISIBLE);
+ if (!config_minimized && playing) stats.IncrementStat(Stats::TIME_VISIBLE_PLAYING);
+ //if (config_mb_open && !config_minimized) stats_timemb++;
+ //if (config_mb_open && !config_minimized && playing) stats_timembplaying++;
+ }
+ // removing the playing only check on this so rating menu updates will appear even when stopped
+ if ((id == UPDATE_DISPLAY_TIMER) || (id == UPDATE_DISPLAY_TIMER + 2) || (id == UPDATE_DISPLAY_TIMER + 4))
+ {
+ if (playing)
+ {
+ int a = (in_getouttime()) / 1000;
+ int l = in_getlength();
+ if (!config_minimized && (config_mw_open || config_pe_open))
+ {
+ static int t = -1;
+ static int la = -123;
+ static int ll = -15055;
+ if (paused)
+ {
+ if (t == -1) t = 10;
+ else t--;
+ }
+ else t = -1;
+ if (a != la || l != ll || (paused && t == 10) || id == UPDATE_DISPLAY_TIMER + 4) ui_drawtime(a, 0);
+ la = a;
+ ll = l;
+ }
+ if (g_brate != last_brate)
+ draw_bitmixrate(last_brate = g_brate, g_srate);
+ }
+ if (g_need_titleupd || (id == UPDATE_DISPLAY_TIMER + 2))
+ {
+ if (id == UPDATE_DISPLAY_TIMER + 2)
+ KillTimer(hMainWindow, id);
+
+ g_need_titleupd = 0;
+ PlayList_getcurrent_tupdate(FileName, FileTitle);
+
+ {
+ if (!do_volbar_active && !do_posbar_active && !do_panbar_active)
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ set_caption(!playing, L"%s - %S", (config_dotasknum?FileTitleNum:FileTitle), app_name);
+ plEditSelect(PlayList_getPosition() | (1 << 30));
+ }
+ if (playing && g_need_infoupd)
+ {
+ int r = g_need_infoupd;
+ g_need_infoupd = 0;
+
+ if (r & 8)
+ {
+ last_brate = g_brate;
+ draw_bitmixrate(g_brate, g_srate);
+ draw_monostereo(g_nch);
+ }
+ if (r & 2)
+ draw_playicon(4);
+ else if (r & 1)
+ draw_playicon(1);
+ else
+ draw_playicon(8);
+ }
+ }
+ if (id == UPDATE_DISPLAY_TIMER + 1 && !config_minimized && !config_windowshade && config_mw_open)
+ if (config_autoscrollname&1)
+ {
+ ui_doscrolling();
+ }
+ if (id == 666)
+ {
+ KillTimer(hwnd, 666);
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_MAINMENU, 0);
+ }
+ if (id == UPDATE_DISPLAY_TIMER + 1)
+ {
+ if (config_autoscrollname&2)
+ do_caption_autoscroll();
+ }
+ return 1;
+}
diff --git a/Src/Winamp/main_wndproc.cpp b/Src/Winamp/main_wndproc.cpp
new file mode 100644
index 00000000..5a868fc7
--- /dev/null
+++ b/Src/Winamp/main_wndproc.cpp
@@ -0,0 +1,253 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "../nu/ns_wc.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoWideFn.h"
+#include "./api.h"
+#include "resource.h"
+#include "wintheme.h"
+
+// WM_CREATE handler
+LRESULT Main_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
+{
+ // srand(GetTickCount());
+ hMainWindow = hwnd;
+ DisableVistaPreview();
+
+ HACCEL hAccel = LoadAcceleratorsW(language_pack_instance, MAKEINTRESOURCEW(IDR_ACCELERATOR_GLOBAL));
+ if (!hAccel && language_pack_instance != hMainInstance) hAccel = LoadAcceleratorsW(hMainInstance, MAKEINTRESOURCEW(IDR_ACCELERATOR_GLOBAL));
+ if (hAccel) WASABI_API_APP->app_addAccelerators(hwnd, &hAccel, 1, TRANSLATE_MODE_GLOBAL);
+
+ hAccel = LoadAcceleratorsW(language_pack_instance, MAKEINTRESOURCEW(IDR_ACCELERATOR_MAIN));
+ if (!hAccel && language_pack_instance != hMainInstance) hAccel = LoadAcceleratorsW(hMainInstance, MAKEINTRESOURCEW(IDR_ACCELERATOR_MAIN));
+ if (hAccel) WASABI_API_APP->app_addAccelerators(hwnd, &hAccel, 1, TRANSLATE_MODE_NORMAL);
+
+ WASABI_API_APP->app_registerGlobalWindow(hwnd);
+
+ return 1;
+} // Main_OnCreate()
+
+// Message sent from system notification area
+LRESULT Main_OnWASystray(HWND hwnd, int id)
+{
+ POINT p;
+ switch (id)
+ {
+ case WM_LBUTTONUP:
+ if (GetAsyncKeyState(VK_CONTROL) & (1 << 15))
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_LOC, 0);
+ else if (GetAsyncKeyState(VK_SHIFT) & (1 << 15))
+ SendMessageW(hwnd, WM_COMMAND, WINAMP_FILE_PLAY, 0);
+ else if (!IsWindowVisible(hwnd))
+ {
+ ShowWindow(hwnd, SW_RESTORE);
+ ShowWindow(hwnd, SW_SHOW);
+ }
+ else SetForegroundWindow(hwnd);
+
+ break;
+ case WM_RBUTTONUP:
+ GetCursorPos(&p);
+ SetForegroundWindow(hwnd);
+ //DoTrackPopup(main_menu, TPM_RIGHTBUTTON, p.x, p.y, hwnd);
+ TrackPopupMenu(main_menu, TPM_RIGHTBUTTON, p.x, p.y, 0, hwnd, NULL);
+ break;
+ }
+ return 1;
+}
+
+
+// WM_SIZE handler, to detect minizations.
+LRESULT Main_OnSize(HWND hwnd, UINT state, int cx, int cy)
+{
+
+ if (state == SIZE_MINIMIZED)
+ {
+ int q = GetAsyncKeyState(VK_SHIFT) >> 15;
+ if (config_taskbar || q || minimize_hack_winamp) ShowWindow(hwnd, SW_HIDE);
+ if (q || minimize_hack_winamp)
+ {
+ systray_minimize(caption);
+ config_minimized = 2;
+ }
+ else config_minimized = 1;
+ if (config_pe_open && hPLWindow){
+ HWND parent = GetParent(GetParent(hPLWindow));
+ if(IsWindow(parent) && IsWindowVisible(hPLWindow)){}
+ else ShowWindow(hPLWindow,SW_HIDE);
+ }
+ //if (config_mb_open&&hMBWindow) ShowWindow(hMBWindow,SW_HIDE);
+ if (config_eq_open && hEQWindow) ShowWindow(hEQWindow,SW_HIDE);
+ minimize_hack_winamp = 0;
+ }
+ else if (state == SIZE_RESTORED)
+ {
+
+ if (config_minimized == 2 && !(config_taskbar == 1 || config_taskbar == 2))
+ {
+ systray_restore();
+ }
+ if (g_taskbar_dirty)
+ {
+ g_taskbar_dirty = 0;
+ set_taskbar();
+ }
+ if (!IsWindowVisible(hwnd) && !deferring_show) ShowWindow(hwnd, SW_SHOWNA);
+ if (config_minimized) set_aot(0);
+ if (!config_mw_open) MoveOffscreen(hwnd);
+ config_minimized = 0;
+ SendMessageW(hwnd, WM_TIMER, UPDATE_DISPLAY_TIMER + 4, 0);
+ if (!deferring_show) SetForegroundWindow(hwnd);
+ if (config_pe_open && hPLWindow) ShowWindow(hPLWindow, SW_SHOWNA);
+ //if (config_mb_open&&hMBWindow) ShowWindow(hMBWindow,SW_SHOWNA);
+ if (config_eq_open && hEQWindow) ShowWindow(hEQWindow,SW_SHOWNA);
+ if (config_video_open && hVideoWindow) ShowWindow(hVideoWindow, SW_SHOWNA);
+ set_aot(0);
+// Browser_toggleVisible(1);
+ }
+ return 1;
+}
+
+
+// Sent by decode thread to let the main program know it's done
+LRESULT Main_OnWAMPEGEOF(HWND hwnd)
+{
+ return PlayQueue_OnEOF();
+}
+
+// Drag&Drop handler
+LRESULT Main_OnDropFiles(HWND hwnd, HDROP hdrop)
+{
+ wchar_t temp[MAX_PATH] = {0};
+ int s = (GetAsyncKeyState(VK_SHIFT) & (1 << 15)) ? 0 : 1;
+ int y = DragQueryFileW(hdrop, 0xffffffff, temp, MAX_PATH);
+ if (s)
+ {
+ PlayList_delete();
+ PlayList_randpos(0);
+ }
+ for (int x = 0; x < y; x ++)
+ {
+ DragQueryFileW(hdrop, x, temp, MAX_PATH);
+
+ PlayList_appendthing(temp, 0, 0);
+ }
+ if (s)
+ BeginPlayback();
+
+ plEditRefresh();
+
+ return 1;
+}
+
+LRESULT Main_OnCopyData(HWND sendingHWND, COPYDATASTRUCT *cds)
+{
+ switch (cds->dwData)
+ {
+ case IPC_SETSKIN:
+ if (cds->lpData && lstrlenA((char *)cds->lpData))
+ {
+ AutoWide dataW((char*)cds->lpData);
+ if (_wcsicmp(config_skin, dataW))
+ {
+ StringCchCopyW(config_skin, MAX_PATH, dataW);
+ }
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_REFRESHSKIN, 0);
+ }
+ return TRUE;
+ case IPC_SETSKINW:
+ if (cds->lpData && lstrlenW((wchar_t*)cds->lpData))
+ {
+ if (_wcsicmp(config_skin, (wchar_t*)cds->lpData))
+ {
+ StringCchCopyW(config_skin, MAX_PATH, (wchar_t*)cds->lpData);
+ }
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_REFRESHSKIN, 0);
+ }
+ return TRUE;
+ case IPC_CHDIR:
+ SetCurrentDirectoryA((char *) cds->lpData);
+ return TRUE;
+ case IPC_PLAYFILE:
+ {
+ char *filename = (char *)cds->lpData;
+ PlayList_appendthing(AutoWideFn(filename), 0, 0);
+ plEditRefresh();
+ }
+ return TRUE;
+ case IPC_PLAYFILEW:
+ {
+ wchar_t *filename = (wchar_t *)cds->lpData;
+ PlayList_appendthing(filename, 0, 0);
+ plEditRefresh();
+ }
+ return TRUE;
+ case IPC_GETMODULENAME:
+ {
+ char b[512] = {0}, b2[512] = {0};
+ GetModuleFileNameA(hMainInstance, b, sizeof(b));
+ GetShortPathNameA(b, b2, 511);
+ GetShortPathNameA((char *)cds->lpData, b, 511);
+ stat_isit = _stricmp(b, b2);
+ }
+ return TRUE;
+ case IPC_ADDBOOKMARK:
+ {
+ wchar_t* file = AutoWide((char *)cds->lpData);
+ Bookmark_additem(file, PlayList_gettitle(file, 1));
+ }
+ return TRUE;
+ case IPC_ADDBOOKMARKW:
+ {
+ Bookmark_additem((wchar_t *)cds->lpData, PlayList_gettitle((const wchar_t *)cds->lpData, 1));
+ }
+ return TRUE;
+ case IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE:
+ {
+ wchar_t *filename = (wchar_t *)cds->lpData;
+ wchar_t *tagname = filename + wcslen(filename) + 1;
+
+ extendedFileInfoStructW info;
+ info.filename = filename;
+ info.metadata = tagname;
+ wchar_t ret[1024]=L"";
+ info.ret = ret;
+ info.retlen = 1024;
+
+ if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
+ ret[0] = L'\0';
+
+ COPYDATASTRUCT answer;
+ answer.lpData = info.ret;
+ answer.cbData = sizeof(ret);
+ answer.dwData = IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE;
+ return SendMessageW(sendingHWND, WM_COPYDATA, (WPARAM)hMainWindow, (LPARAM)&answer);
+ }
+ case IPC_GET_PLAYING_FILENAME:
+ {
+ COPYDATASTRUCT answer;
+ answer.lpData = FileName;
+ answer.cbData = (DWORD)(sizeof(wchar_t) * (wcslen(FileName) + 1));
+ answer.dwData = IPC_GET_PLAYING_FILENAME;
+ return SendMessageW(sendingHWND, WM_COPYDATA, (WPARAM)hMainWindow, (LPARAM)&answer);
+ }
+ case IPC_OPEN_URL:
+ {
+ myOpenURL(hMainWindow, (wchar_t *)cds->lpData);
+ return TRUE;
+ }
+ case IPC_HANDLE_URI:
+ {
+ HandleFilename((wchar_t *)cds->lpData);
+ return TRUE;
+ }
+ }
+ return FALSE;
+} \ No newline at end of file
diff --git a/Src/Winamp/manifest.xml b/Src/Winamp/manifest.xml
new file mode 100644
index 00000000..e22433cb
--- /dev/null
+++ b/Src/Winamp/manifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ <assemblyIdentity
+ version="5.92.0.10042"
+ processorArchitecture="x86"
+ name="Radionomy.Winamp.Winamp for Windows"
+ type="win32"
+ />
+ <description>Winamp 5.9.2</description>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.2600.0"
+ processorArchitecture="x86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+ </dependency>
+<dependency>
+<dependentAssembly>
+<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.30729.6161" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b">
+</assemblyIdentity>
+</dependentAssembly>
+</dependency>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 10 and 11 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ </application>
+ </compatibility>
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true</dpiAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+</assembly> \ No newline at end of file
diff --git a/Src/Winamp/manifest64.xml b/Src/Winamp/manifest64.xml
new file mode 100644
index 00000000..a005cc6b
--- /dev/null
+++ b/Src/Winamp/manifest64.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ <assemblyIdentity
+ version="5.9.1.10003"
+ processorArchitecture="amd64"
+ name="Radionomy.Winamp.Winamp for Windows"
+ type="win32"
+ />
+ <description>Winamp 5.9.1</description>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.2600.0"
+ processorArchitecture="amd64"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+ </dependency>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.30729.6161" processorArchitecture="amd64" publicKeyToken="1fc8b3b9a1e18e3b" />
+ </dependentAssembly>
+ </dependency>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 10 and 11 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ </application>
+ </compatibility>
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true</dpiAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+</assembly></assembly>
diff --git a/Src/Winamp/manifest_debug.xml b/Src/Winamp/manifest_debug.xml
new file mode 100644
index 00000000..d74a445c
--- /dev/null
+++ b/Src/Winamp/manifest_debug.xml
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="win32" name="Microsoft.VC142.CRT" version="14.29.30139.0" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b" />
+ </dependentAssembly>
+ </dependency>
+</assembly>
diff --git a/Src/Winamp/manifest_x64.rc b/Src/Winamp/manifest_x64.rc
new file mode 100644
index 00000000..64f8f903
--- /dev/null
+++ b/Src/Winamp/manifest_x64.rc
@@ -0,0 +1,63 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Winamp/manifest_x86.rc b/Src/Winamp/manifest_x86.rc
new file mode 100644
index 00000000..8a1b9285
--- /dev/null
+++ b/Src/Winamp/manifest_x86.rc
@@ -0,0 +1,70 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+1 RT_MANIFEST "manifest.xml"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Winamp/mb.cpp b/Src/Winamp/mb.cpp
new file mode 100644
index 00000000..2f4cf986
--- /dev/null
+++ b/Src/Winamp/mb.cpp
@@ -0,0 +1 @@
+#include "Main.h"
diff --git a/Src/Winamp/mbui.cpp b/Src/Winamp/mbui.cpp
new file mode 100644
index 00000000..61f734b2
--- /dev/null
+++ b/Src/Winamp/mbui.cpp
@@ -0,0 +1 @@
+#include "main.h" \ No newline at end of file
diff --git a/Src/Winamp/menuv5.cpp b/Src/Winamp/menuv5.cpp
new file mode 100644
index 00000000..350548d4
--- /dev/null
+++ b/Src/Winamp/menuv5.cpp
@@ -0,0 +1,653 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include "menuv5.h"
+#include "../nu/AutoWide.h"
+#include "../Plugins/General/gen_ml/ml.h"
+
+#define TREE_LOCALMEDIA 1000
+#define TREE_PLAYLISTS 3001
+#define TREE_DEVICES 10000
+#define TREE_QUERIES 1000
+
+extern HINSTANCE language_pack_instance;
+
+
+void ensureInScreen(HMENU menu, int *x, int *y, int *flag, int width, int height);
+
+HMENU v5_top_menu = NULL;
+
+
+int MergeMenu(HMENU pMenuDestination, const HMENU pMenuAdd, int bTopLevel /*=false*/)
+{
+ // Abstract:
+ // Merges two menus.
+ //
+ // Parameters:
+ // pMenuDestination - [in, retval] destination menu handle
+ // pMenuAdd - [in] menu to merge
+ // bTopLevel - [in] indicator for special top level behavior
+ //
+ // Return value:
+ // <false> in case of error.
+ //
+ // Comments:
+ // This function calles itself recursivley. If bTopLevel is set to true,
+ // we append popups at top level or we insert before <Window> or <Help>.
+
+ // get the number menu items in the menus
+ int iMenuAddItemCount = GetMenuItemCount(pMenuAdd);
+ int iMenuDestItemCount = GetMenuItemCount(pMenuDestination);
+ int iLoop;
+
+ // if there are no items return
+ if( iMenuAddItemCount == 0 )
+ return 1;
+
+ // if we are not at top level and the destination menu is not empty
+ // -> we append a seperator
+ if( !bTopLevel && iMenuDestItemCount > 0 )
+ AppendMenu(pMenuDestination, MF_SEPARATOR, 0, 0);
+
+ // iterate through the top level of
+ for( iLoop = 0; iLoop < iMenuAddItemCount; iLoop++ )
+ {
+ HMENU pSubMenu = 0;
+ // get the menu string from the add menu
+ wchar_t sMenuAddString[1024] = {0}; // hope it's enough
+
+ GetMenuStringW(pMenuAdd, iLoop, sMenuAddString, 1024, MF_BYPOSITION);
+
+ // try to get the submenu of the current menu item
+ pSubMenu =GetSubMenu(pMenuAdd, iLoop);
+
+ // check if we have a sub menu
+ if (!pSubMenu)
+ {
+ // normal menu item
+ // read the source and append at the destination
+ UINT nState = GetMenuState(pMenuAdd, iLoop, MF_BYPOSITION);
+ UINT nItemID = GetMenuItemID(pMenuAdd, iLoop);
+
+ if(AppendMenuW(pMenuDestination, nState, nItemID, sMenuAddString))
+ {
+ // menu item added, don't forget to correct the item count
+ iMenuDestItemCount++;
+ }
+ else
+ {
+ // MergeMenu: AppendMenu failed!
+ return 0;
+ }
+ }
+ else
+ {
+ HMENU NewPopupMenu=NULL;
+ // create or insert a new popup menu item
+
+ // default insert pos is like ap
+ int iInsertPosDefault = -1;
+
+ // if we are at top level merge into existing popups rather than
+ // creating new ones
+ if( bTopLevel )
+ {
+ //ASSERT( sMenuAddString != "&?" && sMenuAddString != "?" );
+ //CString sAdd( sMenuAddString );
+ //sAdd.Remove('&'); // for comparison of menu items supress '&'
+ int bAdded = 0;
+ int iLoop1=0;
+
+ // try to find existing popup
+ for( iLoop1 = 0; iLoop1 < iMenuDestItemCount; iLoop1++ )
+ {
+ // get the menu string from the destination menu
+ wchar_t sDest[1024] = {0}; // hope it's enough
+ GetMenuStringW(pMenuDestination, iLoop1, sDest, 1024, MF_BYPOSITION );
+ //sDest.Remove( '&' ); // for a better compare (s.a.)
+
+ //if( !lstrcmp(sAdd,sDest))
+ {
+ // we got a hit -> merge the two popups
+ // try to get the submenu of the desired destination menu item
+ HMENU pSubMenuDest = GetSubMenu(pMenuDestination, iLoop1 );
+
+ if( pSubMenuDest )
+ {
+ // merge the popup recursivly and continue with outer for loop
+ if( !MergeMenu( pSubMenuDest, pSubMenu, 0 ))
+ return 0;
+
+ bAdded = 1;
+ break;
+ }
+ }
+
+ // alternativ insert before <Window> or <Help>
+ //if( iInsertPosDefault == -1 && ( sDest == "Window" || sDest == "?" || sDest == "Help" ))
+ // iInsertPosDefault = iLoop1;
+
+ }
+
+ if( bAdded )
+ {
+ // menu added, so go on with loop over pMenuAdd's top level
+ continue;
+ }
+ }
+
+ // if the top level search did not find a position append the menu
+ if( iInsertPosDefault == -1 )
+ iInsertPosDefault = GetMenuItemCount(pMenuDestination);
+
+ // create a new popup and insert before <Window> or <Help>
+ NewPopupMenu = CreatePopupMenu();
+ if( !NewPopupMenu)
+ {
+ // MergeMenu: CreatePopupMenu failed!
+ return 0;
+ }
+
+ // merge the new popup recursivly
+ if( !MergeMenu( NewPopupMenu, pSubMenu, 0 ))
+ return 0;
+
+ // insert the new popup menu into the destination menu
+ HMENU hNewMenu = NewPopupMenu;
+ {
+ MENUITEMINFOW menuItem={sizeof(MENUITEMINFO),
+ MIIM_TYPE|MIIM_SUBMENU,
+ MFT_STRING,
+ MFS_ENABLED,
+ 0, //wID
+ hNewMenu, // hSubMenu
+ NULL, // hbmpChecked
+ NULL, // hbmpUnchecked
+ 0, // dwItemData
+ sMenuAddString, // dwTypeData
+ 0, // cch
+ };
+
+ if (InsertMenuItemW(pMenuDestination, iInsertPosDefault, TRUE, &menuItem))
+ {
+ // don't forget to correct the item count
+ iMenuDestItemCount++;
+ }
+ else
+ {
+ // MergeMenu: InsertMenu failed!
+ return 0;
+ }
+ }
+
+ }
+ }
+
+ return 1;
+}
+
+int getMenuItemPos(HMENU menu, UINT command)
+{
+ int i;
+ for (i = 0;i < 256;i++)
+ {
+ MENUITEMINFO mii = {sizeof(mii), MIIM_ID, };
+ if (!GetMenuItemInfo(menu, i, TRUE, &mii)) break;
+ if (mii.wID == command) return i;
+ }
+ return -1;
+}
+
+extern int g_SkinTop, g_BookmarkTop;
+
+int V5_File_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ int flag = TPM_LEFTALIGN;
+ HMENU file_menu = GetSubMenu(v5_top_menu, 0);
+ HMENU hMenu = GetSubMenu(file_menu, 3);
+ MENUITEMINFOW i = {sizeof(i), };
+ FILE *fp;
+ int a = 34768;
+ int offs = 3;
+ int count = GetMenuItemCount(hMenu) + 1;
+
+ i.fMask = MIIM_TYPE | MIIM_DATA | MIIM_ID;
+ i.fType = MFT_STRING;
+ i.wID = 34768;
+
+ // remove all of the items we might have added - do by command for certainty
+ while (count){
+ if(!RemoveMenu(hMenu, a++, MF_BYCOMMAND)) break;
+ count--;
+ }
+
+ fp = _wfopen(BOOKMARKFILE8, L"rt");
+ if (fp)
+ {
+ while (1)
+ {
+ char ft[FILETITLE_SIZE] = {0}, fn[FILENAME_SIZE] = {0};
+ fgets(fn, FILENAME_SIZE, fp);
+ if (feof(fp)) break;
+ fgets(ft, FILETITLE_SIZE, fp);
+ if (feof(fp)) break;
+ if (ft[0] && fn[0])
+ {
+ if (fn[lstrlenA(fn) - 1] == '\n') fn[lstrlenA(fn) - 1] = 0;
+ if (ft[lstrlenA(ft) - 1] == '\n') ft[lstrlenA(ft) - 1] = 0;
+ if (ft[0] && fn[0])
+ {
+ i.dwTypeData = AutoWideDup(ft, CP_UTF8);
+ i.cch = lstrlenW(i.dwTypeData);
+ RemoveMenu(hMenu, i.wID, MF_BYCOMMAND);
+ InsertMenuItemW(hMenu, i.wID + offs - 34768, TRUE, &i);
+ i.wID++;
+ }
+ }
+ }
+ fclose(fp);
+ }
+ g_BookmarkTop = i.wID;
+
+ // put in a place holder item if there were no read bookmarks
+ if (g_BookmarkTop == 34768)
+ {
+ i.dwTypeData = getStringW(IDS_NO_BOOKMARKS,NULL,0);
+ i.cch = lstrlenW(i.dwTypeData);
+ InsertMenuItemW(hMenu, i.wID + offs - 34768, TRUE, &i);
+ EnableMenuItem(hMenu, i.wID, MF_BYCOMMAND | MF_GRAYED);
+ }
+
+ ensureInScreen(file_menu, &x, &y, &flag, width, height);
+
+ DoTrackPopup(file_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+int V5_Play_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ HMENU play_menu = GetSubMenu(v5_top_menu, 1);
+ int flag = TPM_LEFTALIGN;
+ ensureInScreen(play_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(play_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+
+int V5_Options_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ int flag = TPM_LEFTALIGN;
+ HMENU options_menu = GetSubMenu(v5_top_menu, 2);
+ HMENU eqMenu = NULL;
+
+ { // set options skin menu to the skin menu
+ extern HMENU g_submenus_skins1;
+ MENUITEMINFO mi = {sizeof(mi), MIIM_SUBMENU};
+ mi.hSubMenu = g_submenus_skins1;
+ SetMenuItemInfoW(options_menu, 0, TRUE, &mi);
+ }
+
+ eqMenu = GetSubMenu(options_menu, 2);
+ CheckMenuItem(eqMenu, EQ_ENABLE, config_use_eq ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(options_menu, WINAMP_OPTIONS_DSIZE, config_dsize ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(options_menu, WINAMP_OPTIONS_AOT, config_aot ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(options_menu, WINAMP_OPTIONS_ELAPSED, config_timeleftmode ? MF_UNCHECKED : MF_CHECKED);
+ CheckMenuItem(options_menu, WINAMP_OPTIONS_REMAINING, config_timeleftmode ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(options_menu, WINAMP_OPTIONS_PREFS, IsWindow(prefs_hwnd) ? MF_CHECKED : MF_UNCHECKED);
+ ensureInScreen(options_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(options_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+int V5_Windows_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ HMENU windows_menu = GetSubMenu(v5_top_menu, 3);
+ int flag = TPM_LEFTALIGN;
+ CheckMenuItem(windows_menu, WINAMP_OPTIONS_PLEDIT, config_pe_open ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(windows_menu, WINAMP_VISPLUGIN, vis_running() ? MF_CHECKED : MF_UNCHECKED);
+ if (g_has_video_plugin) CheckMenuItem(windows_menu, WINAMP_OPTIONS_VIDEO, config_video_open ? MF_CHECKED : MF_UNCHECKED);
+ ensureInScreen(windows_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(windows_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+int Help_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ HMENU help_menu = GetSubMenu(v5_top_menu, 4);
+ int flag = TPM_LEFTALIGN;
+
+ MENUITEMINFOW i = {sizeof(i), };
+ i.fMask = MIIM_TYPE;
+ i.fType = MFT_STRING;
+ i.dwTypeData = getStringW(IDS_WINAMP_MENUITEM, NULL, 0);
+ i.cch = (UINT)wcslen(i.dwTypeData);
+ SetMenuItemInfoW(help_menu, WINAMP_HELP_ABOUT, FALSE, &i);
+
+ ensureInScreen(help_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(help_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+int V5_Help_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ return Help_Menu(hwnd, x, y, width, height);
+}
+
+LRESULT sendMlIpc(int msg, WPARAM param);
+
+// TODO:: need to make this only show what's needed at the time ie it'll still show even if there's no ml_playlists
+// and properly show if there's no playlists
+int V5_PE_File_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ int flag = TPM_LEFTALIGN;
+ HMENU pefile_menu = GetSubMenu(v5_top_menu, 5);
+ HMENU playlistsmenu = NULL;
+ HMENU viewmenu = NULL;
+ HWND mlwnd = (HWND)sendMlIpc(0, 0);
+ int viewmenu_added = 0;
+ g_open_ml_item_in_pe = 1;
+ if (mlwnd)
+ {
+ mlGetTreeStruct mgts = { TREE_PLAYLISTS, 45000, -1 };
+ playlistsmenu = (HMENU)SendMessageW(mlwnd, WM_ML_IPC, (WPARAM) & mgts, ML_IPC_GETTREE);
+ if (playlistsmenu)
+ {
+ mlGetTreeStruct mgts = { TREE_QUERIES, 45000, -1 };
+ viewmenu = (HMENU)SendMessageW(mlwnd, WM_ML_IPC, (WPARAM) & mgts, ML_IPC_GETTREE);
+ if (GetMenuItemCount(playlistsmenu) == 0) InsertMenuW(playlistsmenu, 0, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, getStringW(IDS_ML_NO_PLAYLISTS,NULL,0));
+ InsertMenuW(pefile_menu, 2, MF_BYPOSITION | MF_ENABLED | MF_POPUP, (UINT_PTR)playlistsmenu, getStringW(IDS_ML_OPEN_PLAYLIST,NULL,0));
+ if (viewmenu && GetMenuItemCount(viewmenu) > 0)
+ {
+ viewmenu_added = 1;
+ InsertMenuW(pefile_menu, 3, MF_BYPOSITION | MF_ENABLED | MF_POPUP, (UINT_PTR)viewmenu, getStringW(IDS_ML_OPEN_VIEW_RESULTS,NULL,0));
+ }
+ }
+ }
+
+ ModifyMenuW(pefile_menu, ID_PE_CLOSE, MF_BYCOMMAND | MF_STRING, ID_PE_CLOSE, config_pe_open ? getStringW(IDS_PE_CLOSE,NULL,0) : getStringW(IDS_PE_OPEN,NULL,0));
+ ensureInScreen(pefile_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(pefile_menu, flag, x, y, hwnd);
+
+ if (playlistsmenu)
+ {
+ if (viewmenu_added) RemoveMenu(pefile_menu, 3, MF_BYPOSITION);
+ if (viewmenu) DestroyMenu(viewmenu);
+ RemoveMenu(pefile_menu, 2, MF_BYPOSITION);
+ DestroyMenu(playlistsmenu);
+ }
+ return 1;
+}
+
+int V5_PE_Playlist_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ HMENU peplaylist_menu = GetSubMenu(v5_top_menu, 6);
+ int flag = TPM_LEFTALIGN;
+ ensureInScreen(peplaylist_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(peplaylist_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+int V5_PE_Sort_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ HMENU pesort_menu = GetSubMenu(v5_top_menu, 7);
+ int flag = TPM_LEFTALIGN;
+ ensureInScreen(pesort_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(pesort_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+int V5_PE_Help_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ return Help_Menu(hwnd, x, y, width, height);
+}
+
+int V5_ML_File_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ int flag = TPM_LEFTALIGN;
+ HMENU mlfile_menu = GetSubMenu(v5_top_menu, 8);
+ HWND mlwnd = (HWND)sendMlIpc(0, 0);
+ HWND mlplwnd = (HWND)SendMessageW(mlwnd, WM_ML_IPC, 0, ML_IPC_GETPLAYLISTWND);
+ ModifyMenuW(mlfile_menu, 3, MF_BYPOSITION | (mlplwnd == NULL ? MF_GRAYED : 0), ID_MLFILE_SAVEPLAYLIST, getStringW(IDS_ML_EXPORT_PLAYLIST,NULL,0));
+ {
+ int visible = IsWindowVisible(mlwnd);
+ int p = getMenuItemPos(mlfile_menu, ID_FILE_CLOSELIBRARY);
+ if (p == -1) p = getMenuItemPos(mlfile_menu, ID_FILE_SHOWLIBRARY);
+ ModifyMenuW(mlfile_menu, p, MF_BYPOSITION | MF_STRING, visible ? ID_FILE_CLOSELIBRARY : ID_FILE_SHOWLIBRARY, visible ? getStringW(IDS_ML_CLOSE_ML,NULL,0) : getStringW(IDS_ML_OPEN_ML,NULL,0));
+ }
+ ensureInScreen(mlfile_menu, &x, &y, &flag, width, height);
+ DoTrackPopup(mlfile_menu, flag, x, y, hwnd);
+ return 1;
+}
+
+int V5_ML_View_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ int flag = TPM_LEFTALIGN;
+ HMENU mlview_menu = GetSubMenu(v5_top_menu, 9), mediamenu = NULL;
+ HWND mlwnd = (HWND)sendMlIpc(0, 0);
+ if (mlwnd)
+ {
+ mlGetTreeStruct mgts = { 0, 45000, -1 };
+ mediamenu = (HMENU)SendMessageW(mlwnd, WM_ML_IPC, (WPARAM) & mgts, ML_IPC_GETTREE);
+ if (mediamenu)
+ {
+ MergeMenu(mediamenu, mlview_menu, 0);
+ //InsertMenu(mediamenu, 0, MF_BYPOSITION | MF_STRING, ID_MLVIEW_MEDIA, "All &Media");
+ //InsertMenu(mlview_menu, 1, MF_BYPOSITION | MF_ENABLED | MF_POPUP, (UINT)mediamenu, "&Local Media");
+ }/*
+ mgts.item_start = TREE_PLAYLISTS;
+ playlistsmenu = (HMENU)SendMessageW(mlwnd, WM_ML_IPC, (int) & mgts, ML_IPC_GETTREE);
+ if (playlistsmenu)
+ {
+ if (GetMenuItemCount(playlistsmenu) == 0) InsertMenu(playlistsmenu, 0, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, "No playlists");
+ InsertMenu(mlview_menu, 2, MF_BYPOSITION | MF_ENABLED | MF_POPUP, (UINT)playlistsmenu, "&Playlists");
+ }
+ mgts.item_start = TREE_DEVICES;
+ devicesmenu = (HMENU)SendMessageW(mlwnd, WM_ML_IPC, (int) & mgts, ML_IPC_GETTREE);
+ if (devicesmenu)
+ {
+ if (GetMenuItemCount(devicesmenu) == 0) InsertMenu(devicesmenu, 0, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, "No devices");
+ InsertMenu(mlview_menu, 3, MF_BYPOSITION | MF_ENABLED | MF_POPUP, (UINT)devicesmenu, "&Devices");
+ }*/
+ }
+
+ g_open_ml_item_in_pe = 0;
+
+ //ID_MLVIEW_PLAYLISTS
+ //ID_MLVIEW_DEVICES
+
+ ensureInScreen(mediamenu, &x, &y, &flag, width, height);
+ DoTrackPopup(mediamenu, flag, x, y, hwnd);
+/*
+ if (devicesmenu)
+ {
+ RemoveMenu(mlview_menu, 3, MF_BYPOSITION);
+ DestroyMenu(devicesmenu);
+ }
+ if (playlistsmenu)
+ {
+ RemoveMenu(mlview_menu, 2, MF_BYPOSITION);
+ DestroyMenu(playlistsmenu);
+ }*/
+ if (mediamenu)
+ {
+ //RemoveMenu(mlview_menu, 1, MF_BYPOSITION);
+ DestroyMenu(mediamenu);
+ }
+ return 1;
+}
+
+int V5_ML_Help_Menu(HWND hwnd, int x, int y, int width, int height)
+{
+ return Help_Menu(hwnd, x, y, width, height);
+}
+
+int V5_PE_ListOfPlaylists_Menu(int x, int y)
+{
+ HMENU viewmenu = NULL;
+ mlGetTreeStruct mgts = { TREE_PLAYLISTS, 55000, -1 };
+ HWND mlwnd = (HWND)sendMlIpc(0, 0);
+ HMENU playlistsmenu = (HMENU)SendMessageW(mlwnd, WM_ML_IPC, (WPARAM) & mgts, ML_IPC_GETTREE);
+ if (playlistsmenu)
+ {
+ InsertMenuW(playlistsmenu, 0, MF_BYPOSITION | MF_STRING, ID_MANAGEPLAYLISTS, getStringW(IDS_ML_MANAGE_PLAYLISTS,NULL,0));
+ {
+ mlGetTreeStruct mgts = { TREE_QUERIES, 55000, -1 };
+ viewmenu = (HMENU)SendMessageW(mlwnd, WM_ML_IPC, (WPARAM) &mgts, ML_IPC_GETTREE);
+ }
+ if (viewmenu && GetMenuItemCount(viewmenu) > 0)
+ InsertMenuW(playlistsmenu, 1, MF_BYPOSITION | MF_ENABLED | MF_POPUP, (UINT_PTR)viewmenu, getStringW(IDS_ML_SMART_VIEW_RESULTS,NULL,0));
+ InsertMenu(playlistsmenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
+ g_open_ml_item_in_pe = 1;
+ DoTrackPopup(playlistsmenu, TPM_LEFTALIGN, x, y, hMainWindow);
+ }
+ DestroyMenu(playlistsmenu);
+ DestroyMenu(viewmenu);
+ return 1;
+}
+
+void getViewportFromPoint(POINT *pt, RECT *r)
+{
+ if (!r || !pt) return ;
+ {
+
+ HMONITOR hm;
+ hm = MonitorFromPoint(*pt, MONITOR_DEFAULTTONULL);
+ if (hm)
+ {
+ MONITORINFOEXW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+
+ if (GetMonitorInfo(hm, &mi))
+ {
+ *r = mi.rcMonitor;
+ return ;
+ }
+ }
+ }
+}
+
+#undef GetSystemMetrics
+
+void ensureInScreen(HMENU menu, int *x, int *y, int *flag, int width, int height)
+{
+ POINT pt = {*x, *y};
+ int nitems = GetMenuItemCount(menu);
+ int i;
+ RECT mwr;
+ RECT monitor;
+ int rightdone = 0;
+ int bottomdone = 0;
+ int xedge = GetSystemMetrics(SM_CXEDGE);
+ int yedge = GetSystemMetrics(SM_CYEDGE);
+ int itemheight = GetSystemMetrics(SM_CYMENU);
+ int checkmarkwidth = GetSystemMetrics(SM_CXMENUCHECK);
+ int cury = *y + yedge + 1;
+ GetWindowRect(hMainWindow, &mwr);
+ getViewportFromPoint(&pt, &monitor);
+ /*if (nitems*GetSystemMetrics(SM_CYMENU)+yedge*2+*y > monitor.bottom) {
+ bottomdone = 1;
+ *y -= height;
+ *flag &= ~TPM_TOPALIGN;
+ *flag |= TPM_BOTTOMALIGN;
+ }*/
+ for (i = 0;i < nitems;i++)
+ {
+ SIZE s={0};
+ RECT item;
+ MENUITEMINFOW info = {sizeof(info), MIIM_DATA | MIIM_TYPE | MIIM_STATE | MIIM_ID, MFT_STRING, };
+ GetMenuItemRect(hMainWindow, menu, i, &item);
+ item.left -= mwr.left;
+ item.top -= mwr.top;
+ item.right -= mwr.left;
+ item.bottom -= mwr.top;
+ if (item.top == 0 && item.left == 0)
+ {
+ // item has never been shown so MS wont give us the rect, I HATE THEM ! I HATE THEM SO MUCH ARRRG !
+
+ // y
+ item.top = cury;
+ {
+ GetMenuItemInfoW(menu, i, TRUE, &info);
+ if (info.fType & MFT_SEPARATOR)
+ cury += (itemheight - 1) >> 1;
+ else
+ {
+ cury += itemheight - 2;
+ //info.dwTypeData = (LPTSTR) MALLOC(++info.cch + 1);
+ GetMenuItemInfoW(menu, i, TRUE, &info);
+ //info.dwTypeData[info.cch] = 0;
+ }
+ }
+ item.bottom = cury;
+
+ // x
+ if (info.dwTypeData)
+ {
+ LOGFONT m_lf;
+ HFONT font = nullptr;
+ HDC dc = nullptr;
+ NONCLIENTMETRICS nm = {sizeof (NONCLIENTMETRICS), };
+ memset((PVOID) &m_lf, 0, sizeof (LOGFONT));
+ SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, nm.cbSize, &nm, 0);
+ m_lf = nm.lfMenuFont;
+ font = CreateFontIndirectW(&m_lf);
+ dc = GetDC(hMainWindow);
+ GetTextExtentPoint32(dc, info.dwTypeData, lstrlen(info.dwTypeData), &s);
+ ReleaseDC(hMainWindow, dc);
+ DeleteObject(font);
+ //free(info.dwTypeData);
+ }
+ if (!(info.fType & MFT_SEPARATOR))
+ {
+ item.left = *x + xedge + 1;
+ item.right = item.left + s.cx + checkmarkwidth * 2 + xedge + 1;
+ }
+ else
+ {
+ item.left = *x + xedge + 1;
+ item.right = item.left + xedge + 1;
+ }
+ }
+ else
+ {
+ item.left += *x;
+ item.top += *y;
+ item.right += *x;
+ item.bottom += *y;
+ item.right += xedge * 2 + 2; // to avoid last test
+ cury = item.bottom;
+ }
+ if (!bottomdone && cury > monitor.bottom)
+ {
+ bottomdone = 1;
+ *y -= height;
+ *flag &= ~TPM_TOPALIGN;
+ *flag |= TPM_BOTTOMALIGN;
+ }
+ if (!rightdone && item.right > monitor.right)
+ {
+ rightdone = 1;
+ *x += width;
+ *flag &= ~TPM_LEFTALIGN;
+ *flag |= TPM_RIGHTALIGN;
+ }
+ if (rightdone && bottomdone) return ;
+ }
+ cury += yedge + 1;
+ if (!bottomdone && cury > monitor.bottom)
+ {
+ //bottomdone = 1;
+ *y -= height;
+ *flag &= ~TPM_TOPALIGN;
+ *flag |= TPM_BOTTOMALIGN;
+ }
+}
+
+
diff --git a/Src/Winamp/menuv5.h b/Src/Winamp/menuv5.h
new file mode 100644
index 00000000..a2559916
--- /dev/null
+++ b/Src/Winamp/menuv5.h
@@ -0,0 +1,24 @@
+#ifndef _MENUV5_H
+#define _MENUV5_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern HMENU v5_top_menu;
+void Init_V5_Menu();
+int V5_File_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_Play_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_Options_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_Windows_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_Help_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_PE_File_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_PE_Playlist_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_PE_Sort_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_PE_Help_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_ML_File_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_ML_View_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_ML_Help_Menu(HWND hwnd, int x, int y, int width, int height);
+int V5_PE_ListOfPlaylists_Menu(int x, int y);
+#ifdef __cplusplus
+}
+#endif
+#endif \ No newline at end of file
diff --git a/Src/Winamp/metrics.cpp b/Src/Winamp/metrics.cpp
new file mode 100644
index 00000000..a2d3a604
--- /dev/null
+++ b/Src/Winamp/metrics.cpp
@@ -0,0 +1,228 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include <windows.h>
+#include "../nu/AutoUrl.h"
+#include <io.h>
+
+char metric_plugin_list[512] = {0};
+
+typedef struct
+{
+ char country[64];
+ char email[128];
+ char objects[256];
+ unsigned char sendemail;
+ unsigned char sex; //1=m, 2=f, otherwise undefined
+ unsigned char agegroup; // 1=under 13, 2=13-18, 3=18-24, 4=25-34, 5=35-44, 6=45-54, 7=55+
+ unsigned char pad[1];
+} reg_data;
+
+void makeurlcodes(char *in, char *out)
+{
+ char *i=in,*p=out;
+ while (i && *i)
+ {
+ int v=*((unsigned char *)i++);
+ if (IsCharAlpha(v) || (v>='0' && v <='9') || v == ' ' || v == '.' || v == '-' || v == '_') *p++ = v;
+ else
+ {
+ int a,b;
+ *p++ = '%';
+ a=v>>4;
+ b=v&15;
+ a += '0';
+ if (a > '9') a += 'A'-'9'-1;
+ b += '0';
+ if (b > '9') b += 'A'-'9'-1;
+ *p++ = a;
+ *p++ = b;
+ }
+ }
+ if (p) *p=0;
+}
+
+static int in_objlist(char *objlist, char *obj)
+{
+ char *b=objlist-1;
+ while ((b=strstr(b+1,obj)))
+ {
+ if (b==objlist||b[-1]==':')
+ {
+ if (b[lstrlenA(obj)]==':' || !b[lstrlenA(obj)])
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* benski> this could be made faster using StringCchCatEx, but this isn't called enough to warrant
+spending the time right this instant */
+static void diff_objs(char *oldobj, char *newobj, char out[512])
+{
+ char *n=newobj;
+ *out=0;
+ while (n && *n)
+ {
+ char buf[128],*b=buf;
+ while (n && *n && *n != ':') *b++=*n++;
+ if (n && *n) n++;
+ *b++=0;
+ if (!in_objlist(oldobj,buf))
+ {
+ if (!*out) StringCchCatA(out, 512, ":");
+ StringCchCatA(out, 512, buf);
+ }
+ }
+ n=oldobj;
+ while (n && *n)
+ {
+ char buf[128],*b=buf;
+ while (n && *n && *n != ':') *b++=*n++;
+ if (n && *n) n++;
+ *b++=0;
+ if (!in_objlist(newobj,buf))
+ {
+ if (!*out) StringCchCatA(out, 512, ":");
+ StringCchCatA(out, 512, "-");
+ StringCchCatA(out, 512, buf);
+ }
+ }
+}
+
+static void get_objlist(char l[256])
+{
+ char browserbrand[128]="";
+ GetPrivateProfileStringA("winamp","browserbrand","",browserbrand+1,sizeof(browserbrand)-1,INI_FILEA);
+ if (browserbrand[1])
+ browserbrand[0]='.';
+ else browserbrand[0]=0;
+ StringCchPrintfA(l, 256, "wa%s%s%s",app_version,browserbrand,metric_plugin_list);
+}
+
+#define METRICS_EMAIL 0x0001
+#define METRICS_COUNTRY 0x0002
+#define METRICS_ANNOUNCEMENTS 0x0003
+#define METRICS_GENDER 0x0004
+
+INT GetMetricsValueW(const char *data, const char *pszType, void *pDest, int cbDest)
+{
+ reg_data *prd = (reg_data*)data;
+ char *str = NULL;
+ unsigned char *val = NULL;
+ if (!prd || !pszType || !pDest) return 0;
+
+ if (IS_INTRESOURCE(pszType))
+ {
+ switch(((INT)(INT_PTR)pszType))
+ {
+ case METRICS_EMAIL: str = prd->email; break;
+ case METRICS_COUNTRY: str = prd->country; break;
+ case METRICS_ANNOUNCEMENTS: val = &prd->sendemail; break;
+ case METRICS_GENDER: val = &prd->sex; break;
+ }
+ }
+
+ if (str) return MultiByteToWideChar(CP_ACP, 0, str, -1, (wchar_t*)pDest, cbDest/sizeof(wchar_t));
+ if (val)
+ {
+ ZeroMemory(pDest, cbDest);
+ *((unsigned char*)pDest) = *val;
+ return sizeof(*val);
+ }
+ return 0;
+}
+
+BOOL SetMetricsValueW(const char *data, const char *pszType, const void *pVal, int cbVal)
+{
+ reg_data *prd = (reg_data*)data;
+ char *str = NULL;
+ unsigned char *val = NULL;
+ int maxLen;
+ if (!prd || !pszType) return FALSE;
+
+ maxLen = 1;
+
+ if (IS_INTRESOURCE(pszType))
+ {
+ switch(((INT)(INT_PTR)pszType))
+ {
+ case METRICS_EMAIL: str = prd->email; maxLen = sizeof(prd->email)/sizeof(char); break;
+ case METRICS_COUNTRY: str = prd->country; maxLen = sizeof(prd->country)/sizeof(char); break;
+ case METRICS_ANNOUNCEMENTS: val = &prd->sendemail; break;
+ case METRICS_GENDER: val = &prd->sex; break;
+ }
+ }
+
+ if (str)
+ {
+ int len;
+ const wchar_t *val = (const wchar_t*)pVal;
+ if (!*val) { *str = 0x00; return TRUE; }
+ len = WideCharToMultiByte(CP_ACP, 0, val, (-1 == cbVal) ? -1 : cbVal/sizeof(wchar_t), str, maxLen, NULL, NULL);
+ if (len && len < maxLen) str[len] = 0x00;
+ return (len);
+ }
+ if (val)
+ {
+ *val = *((unsigned char*)pVal);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+INT GetMetricsSize(const char *data)
+{
+ reg_data *prd = (reg_data*)data;
+ if (!prd || (!*prd->email && !*prd->country && !prd->sex && !prd->agegroup && !prd->sendemail)) return 0;
+ return sizeof(reg_data);
+}
+
+BOOL SendMetrics(const char *data, HWND hwndParent)
+{
+ BOOL result;
+ reg_data *prd = (reg_data*)data;
+ char buf1[512] = {0}, buf2[512] = {0}, _old_obj[256] = {0};
+ char urlbuf[8192] = {0};
+ size_t urlsize = sizeof(urlbuf)/sizeof(*urlbuf);
+ char *url = urlbuf;
+ int is_upgrade=!GetPrivateProfileIntW(L"WinampReg",L"IsFirstInst",0,INI_FILE);
+
+ if (!prd) return 0;
+
+ // fucko: set is_upgrade
+ StringCchCopyExA(url,urlsize,"http://client.winamp.com/update/do_im.php?", &url, &urlsize, 0);
+ makeurlcodes(prd->country,buf1);
+ stats_getuidstr(buf2);
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0, "ID=%s&ZIP=%s",buf2,buf1);
+ makeurlcodes(prd->email,buf1);
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0, "&EMAIL=%s&ML=%c" /*"&AGE=%d" */ "&SEX=%c&ISUP=%d",buf1,prd->sendemail?'y':'n',
+// prd->agegroup,
+ prd->sex==1 ? 'M' : (prd->sex==2 ? 'F' : 'N' ),
+ is_upgrade);
+
+ CopyMemory(_old_obj, prd->objects, sizeof(_old_obj));
+ get_objlist(prd->objects);
+ diff_objs(_old_obj,prd->objects,buf1);
+ makeurlcodes(buf1,buf2);
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&OBJS=%s",buf2);
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&SKIN=%s",(char *)AutoUrl(config_skin));
+
+ wchar_t mlfilename[MAX_PATH] = {0};
+ PathCombineW(mlfilename, PLUGINDIR, L"gen_ml.dll");
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&MLIB=%d",!_waccess(mlfilename, 0));
+
+ StringCchPrintfExA(url, urlsize, &url, &urlsize, 0,"&V=%s",app_version);
+
+ DeleteFileW(TEMP_FILE);
+ result = !httpRetrieveFileW(hwndParent, urlbuf, TEMP_FILE, getStringW(IDS_INST_SENDINGIN,NULL,0));
+ if (result) WritePrivateProfileStringW(L"WinampReg", L"IsFirstInst", L"0", INI_FILE);
+ return result;
+} \ No newline at end of file
diff --git a/Src/Winamp/ole.cpp b/Src/Winamp/ole.cpp
new file mode 100644
index 00000000..b8039668
--- /dev/null
+++ b/Src/Winamp/ole.cpp
@@ -0,0 +1,431 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoWideFn.h"
+extern "C"
+{
+ extern int g_has_deleted_current;
+};
+#include "shlobj.h"
+#include "../Plugins/General/gen_ff/ff_ipc.h"
+
+ bool refuseDrops = false;
+class DropTarget: public IDropTarget
+{
+public:
+ DropTarget(int enqueue, int isshell)
+ { m_enqueue = enqueue; m_isshell = isshell; }
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID * ppvObj)
+ {
+ if (riid == IID_IDropTarget || riid == IID_IUnknown)
+ {
+ *ppvObj = this;
+ return S_OK;
+ }
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+ STDMETHODIMP_(ULONG) AddRef ()
+ { return 0; }
+ STDMETHODIMP_(ULONG) Release ()
+ { return 0; }
+
+ STDMETHODIMP DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
+ {
+ if (pdwEffect)
+ {
+ if (refuseDrops && !m_isshell)
+ *pdwEffect = DROPEFFECT_NONE;
+ else
+ *pdwEffect = DROPEFFECT_COPY;
+ }
+
+ return S_OK;
+ }
+ STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
+ {
+
+ if (pdwEffect)
+ {
+ if (refuseDrops && !m_isshell)
+ *pdwEffect = DROPEFFECT_NONE;
+ }
+
+ return S_OK;
+ }
+ STDMETHODIMP DragLeave()
+ {
+ return 0;
+ }
+
+ STDMETHODIMP Drop(IDataObject * pDataObj, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
+ {
+ POINT p = {pt.x, pt.y};
+ HWND wnd;
+ int pl_forceappend = 0;
+ int is_main = 0;
+ int is_pe = 0;
+ int pe_insert = 0;
+ if (m_isshell)
+ {
+ is_main = 1;
+ wnd = hMainWindow;
+ if (m_enqueue == 2)
+ {
+ pe_insert = !SendMessageW(hMainWindow, WM_WA_IPC, PlayList_getlength(), IPC_SHELL_ACTION_START);
+ }
+ }
+ else
+ {
+ wnd = WindowFromPoint(p);
+
+ HWND child=0;
+ do
+ {
+ RECT r;
+ GetWindowRect(wnd, &r);
+ POINT offset = p;
+ offset.x -= r.left;
+ offset.y -= r.top;
+ child = ChildWindowFromPoint(wnd, offset);
+ if (child == wnd)
+ child = 0;
+ else if (child)
+ wnd = child;
+ } while (child);
+
+ HWND par = wnd;
+ HWND pledit_poopie = NULL;
+ while (par && !(GetWindowLongW(par, GWL_EXSTYLE) & WS_EX_ACCEPTFILES))
+ {
+ par = GetParent(par);
+ }
+ if (par) wnd = par;
+
+ if (wnd == hMainWindow || IsChild(hMainWindow, wnd)
+ || (HWND)SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)wnd, IPC_FF_GETCONTENTWND) == hMainWindow)
+ {
+ is_main = 1;
+ }
+ else if (wnd == hPLWindow || IsChild(hPLWindow, wnd) || GetParent(hPLWindow) && IsChild(wnd, hPLWindow) ||
+ (pledit_poopie = (HWND)SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)wnd, IPC_FF_GETCONTENTWND)) == hPLWindow)
+ {
+ is_pe = 1;
+ if (pledit_poopie) pl_forceappend = 1; // if we got here because we're hosting the pledit, but not actually
+ // parenting it (meaning we are windowshaded playlist)
+ }
+ else
+ {
+ EnterCriticalSection(&embedcs);
+ {
+ embedWindowState *p = embedwndlist;
+ while (p)
+ {
+ if (IsChild(p->me, wnd) || (GetParent(p->me) && IsChild(wnd, p->me))) break;
+ p = p->link;
+ }
+ if (p)
+ {
+ if (wnd == p->me || IsChild(wnd, p->me) || !(GetWindowLongW(wnd, GWL_EXSTYLE) & WS_EX_ACCEPTFILES)) // if this window accepts files, dont fuck it up
+ {
+ HWND wnd2 = FindWindowExW(p->me, NULL, NULL, NULL);
+ if (!(GetWindowLongW(wnd2, GWL_EXSTYLE)&WS_EX_ACCEPTFILES)) is_main = 1;
+ else
+ {
+ HWND h = GetParent(p->me);
+ char buf[128] = {0};
+ // see if we are (AVS) docked to the main (modern) window
+ if (h && (h = GetParent(h)) && GetWindowTextA(h, buf, sizeof(buf)) && !_stricmp(buf, "Player Window"))
+ is_main = 1;
+ else wnd = wnd2;
+ }
+ }
+ }
+ else is_main = 1;
+ }
+ LeaveCriticalSection(&embedcs);
+ }
+
+ if (is_main) wnd = hMainWindow;
+ if (is_pe) wnd = hPLWindow;
+ }
+
+ HRESULT hr = S_OK;
+ if (pDataObj)
+ {
+ // Important: these strings need to be non-Unicode (don't compile UNICODE)
+ unsigned short cp_format_url = (unsigned short)RegisterClipboardFormat(CFSTR_SHELLURL);
+ //Set up format structure for the descriptor and contents
+ FORMATETC format_url =
+ {cp_format_url, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ FORMATETC format_file =
+ {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ // Check for URL
+ hr = pDataObj->QueryGetData(&format_url);
+ if (hr == S_OK)
+ {
+ // Get the descriptor information
+ STGMEDIUM storage = {0, 0, 0};
+ hr = pDataObj->GetData(&format_url, &storage);
+ char* url = (char *)GlobalLock(storage.hGlobal);
+ if (url)
+ {
+ if (is_pe || is_main || m_isshell)
+ {
+ int t, lp, a;
+ int del = is_main && !(GetAsyncKeyState(VK_SHIFT) & (1 << 15));
+ if (del) PlayList_delete();
+ else if (!is_main && !m_isshell) // playlist
+ {
+ RECT r;
+ POINT dp;
+ GetWindowRect(wnd, &r);
+ dp.x = pt.x - r.left;
+ dp.y = pt.y - r.top;
+ if (config_pe_height == 14 || pl_forceappend) t = PlayList_getlength();
+ else
+ {
+ t = (dp.y - 20) / pe_fontheight;
+ if (t < 0) t = 0;
+ else if (t > (config_pe_height - 38 - 20 - 2) / pe_fontheight) t = PlayList_getlength();
+ else t += pledit_disp_offs;
+ }
+ a = PlayList_getlength();
+ PlayList_saveend(t);
+ lp = PlayList_getPosition();
+ }
+
+ if(!PathIsURLA(url))
+ {
+ // if it's not reported as an url, try to treat it like
+ // a filepath which has been url-encoded and insert it
+ // though if it fails to be converted then revert to it
+ // just being added to the playlist without processing.
+ char url2[FILENAME_SIZE] = {"file:///"};
+ strncat(url2, url, FILENAME_SIZE);
+ DWORD len = lstrlenA(url2);
+ if(SUCCEEDED(PathCreateFromUrlA(url2, url2, &len, 0)))
+ {
+ PlayList_appendthing(AutoWideFn(url2), 0, 0);
+ }
+ else
+ {
+ PlayList_appendthing(AutoWideFn(url), 0, 0);
+ }
+ }
+ else
+ {
+ PlayList_appendthing(AutoWideFn(url), 0, 0);
+ }
+
+ if (del) StartPlaying();
+ else if (!is_main && !m_isshell) // playlist
+ {
+ PlayList_restoreend();
+ if (t <= PlayList_getPosition())
+ {
+ PlayList_setposition(lp + PlayList_getlength() - a);
+ if (!g_has_deleted_current)
+ {
+ PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
+ draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
+ }
+ }
+ plEditRefresh();
+ }
+ }
+ else // fucko: pass url to 'wnd' somehow?
+ {}
+ }
+ GlobalUnlock(url);
+ GlobalFree(url);
+ }
+ else
+ {
+ // check for file
+ hr = pDataObj->QueryGetData(&format_file);
+ if (hr == S_OK)
+ {
+ STGMEDIUM medium;
+ pDataObj->GetData (&format_file, &medium);
+ wchar_t temp[FILENAME_SIZE] = {0};
+ if (m_enqueue)
+ {
+ HDROP hdrop = (HDROP)medium.hGlobal;
+ int y = DragQueryFileW(hdrop, 0xffffffff, temp, FILENAME_SIZE);
+ int current = PlayList_getPosition();
+ for (int x = 0; x < y; x ++)
+ {
+ DragQueryFileW(hdrop, x, temp, FILENAME_SIZE);
+ if (!pe_insert)
+ PlayList_appendthing(temp, 0, 0);
+ else
+ {
+ PlayList_insert(++current, temp);
+ }
+ }
+ DragFinish(hdrop);
+
+ plEditRefresh();
+ }
+ else
+ {
+ int skinLoad = -2;
+ int langLoad = -2;
+ RECT r;
+ GetWindowRect(wnd, &r);
+ LPDROPFILES d = (LPDROPFILES)GlobalLock(medium.hGlobal);
+ d->pt.x = pt.x - r.left;
+ if (pl_forceappend)
+ d->pt.y = r.bottom - r.top;
+ else d->pt.y = pt.y - r.top;
+ d->fNC = FALSE;
+
+ GlobalUnlock(d);
+
+ // check for the file being a skin or language pack
+ // being dropped so we can intercept and not add it
+ // into the pledit but can instead prompt for install
+ DragQueryFileW((HDROP)medium.hGlobal, 0, temp, FILENAME_SIZE);
+ CheckSkin(temp, hMainWindow, &skinLoad);
+ CheckLang(temp, hMainWindow, &langLoad);
+
+ if(!skinLoad && !langLoad)
+ {
+ PostMessageW(wnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0);
+ }
+ }
+ }
+ }
+ }
+
+ if (m_isshell && (m_enqueue == 2))
+ {
+ SendMessageW(hMainWindow, WM_WA_IPC, PlayList_getlength(), IPC_SHELL_ACTION_END);
+ }
+ return S_OK;
+ }
+public:
+ int m_enqueue;
+ int m_isshell;
+};
+
+static DropTarget m_target(0, 0);
+
+class ClassFactory : public IClassFactory
+{
+public:
+ ClassFactory(int enqueue) { m_drop = new DropTarget(enqueue, 1); }
+ ~ClassFactory() { delete(m_drop); }
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID * ppvObj)
+ {
+ if (riid == IID_IClassFactory || riid == IID_IUnknown)
+ {
+ *ppvObj = this;
+ return S_OK;
+ }
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+ STDMETHODIMP_(ULONG) AddRef ()
+ { return 0; }
+ STDMETHODIMP_(ULONG) Release ()
+ { return 0; }
+
+ STDMETHODIMP CreateInstance(IUnknown * pUnkOuter, REFIID riid, void ** ppvObject)
+ {
+ if (pUnkOuter != NULL)
+ {
+ return CLASS_E_NOAGGREGATION;
+ }
+ if (riid == IID_IDropTarget || riid == IID_IUnknown)
+ {
+ *ppvObject = m_drop;
+ return S_OK;
+ }
+ return E_NOINTERFACE;
+ }
+ STDMETHODIMP LockServer(BOOL fLock)
+ {
+ return S_OK;
+ }
+private:
+ DropTarget *m_drop;
+};
+
+static ClassFactory m_playCF(0);
+static ClassFactory m_enqueueCF(1);
+static ClassFactory m_enqueuePlayCF(2);
+
+static DWORD m_exposePlayHandle = NULL, m_exposeEnqueueHandle = NULL, m_exposeEnqueuePlayHandle = NULL;
+
+extern "C"
+{
+
+ void InitDragDrops()
+ {
+ SetWindowLong(hMainWindow, GWL_EXSTYLE, GetWindowLongW(hMainWindow, GWL_EXSTYLE)|(WS_EX_ACCEPTFILES));
+
+ refuseDrops = false;
+ }
+
+ void Ole_initDragDrop()
+ {
+ OleInitialize(NULL);
+ RegisterDragDrop(hMainWindow, &m_target);
+ RegisterDragDrop(hPLWindow, &m_target);
+ if (hVideoWindow) RegisterDragDrop(hVideoWindow, &m_target);
+
+ // {46986115-84D6-459c-8F95-52DD653E532E}
+ static const GUID playGuid =
+ { 0x46986115, 0x84D6, 0x459c, { 0x8f, 0x95, 0x52, 0xdd, 0x65, 0x3e, 0x53, 0x2e } };
+ if (CoRegisterClassObject(playGuid, &m_playCF, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_exposePlayHandle) != S_OK)
+ m_exposePlayHandle = NULL;
+
+ // {77A366BA-2BE4-4a1e-9263-7734AA3E99A2}
+ static const GUID enqueueGuid =
+ { 0x77A366BA, 0x2BE4, 0x4a1e, { 0x92, 0x63, 0x77, 0x34, 0xAA, 0x3e, 0x99, 0xa2 } };
+ if (CoRegisterClassObject(enqueueGuid, &m_enqueueCF, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_exposeEnqueueHandle) != S_OK)
+ m_exposeEnqueueHandle = NULL;
+
+ // {ED50B649-42B0-4153-9E99-54C45F6BD708}
+ static const GUID enqueuePlayGuid =
+ { 0xed50b649, 0x42b0, 0x4153, { 0x9e, 0x99, 0x54, 0xc4, 0x5f, 0x6b, 0xd7, 0x8 } };
+ if (CoRegisterClassObject(enqueuePlayGuid, &m_enqueuePlayCF, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_exposeEnqueuePlayHandle) != S_OK)
+ m_exposeEnqueuePlayHandle = NULL;
+ }
+
+ void UninitDragDrops()
+ {
+ SetWindowLong(hMainWindow, GWL_EXSTYLE, GetWindowLongW(hMainWindow, GWL_EXSTYLE)&~(WS_EX_ACCEPTFILES));
+ refuseDrops = true;
+ }
+
+ void Ole_uninitDragDrop()
+ {
+ if (hVideoWindow) RevokeDragDrop(hVideoWindow);
+ RevokeDragDrop(hPLWindow);
+ RevokeDragDrop(hMainWindow);
+
+ if (m_exposePlayHandle)
+ CoRevokeClassObject(m_exposePlayHandle);
+ if (m_exposeEnqueueHandle)
+ CoRevokeClassObject(m_exposeEnqueueHandle);
+ if (m_exposeEnqueuePlayHandle)
+ CoRevokeClassObject(m_exposeEnqueuePlayHandle);
+ OleUninitialize();
+ }
+
+ void *Ole_getDropTarget()
+ {
+ return (void *)&m_target;
+ }
+}; \ No newline at end of file
diff --git a/Src/Winamp/options_bookmarks.cpp b/Src/Winamp/options_bookmarks.cpp
new file mode 100644
index 00000000..3bcaa759
--- /dev/null
+++ b/Src/Winamp/options_bookmarks.cpp
@@ -0,0 +1,386 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#if 0 // no more minibrowser
+
+static int listDragging=0,listSel=-1;
+
+static WNDPROC OldBookListProc;
+
+static BOOL CALLBACK BookListProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_LBUTTONDOWN:
+ if (!listDragging)
+ {
+ POINT p;
+ RECT r;
+ GetCursorPos(&p);
+ GetWindowRect(hwndDlg,&r);
+ if (p.x >= r.left && p.x < r.right && p.y >= r.top && p.y < r.bottom)
+ {
+ int x=SendMessageW(hwndDlg,LB_ITEMFROMPOINT,0,MAKELPARAM(p.x-r.left,p.y-r.top-2));
+ if (!HIWORD(x))
+ {
+ listDragging=1;
+ listSel=x;
+ }
+ }
+ }
+ break;
+// case WM_KILLFOCUS:
+ case WM_LBUTTONUP:
+ listDragging=0;
+ listSel=-1;
+ break;
+ }
+ return CallWindowProc(OldBookListProc,hwndDlg,uMsg,wParam,lParam);
+}
+
+static char *g_bmedit_fn, *g_bmedit_ft;
+
+static BOOL CALLBACK BookMarkEditProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemText(hwndDlg,IDC_TITLE,g_bmedit_ft);
+ SetDlgItemText(hwndDlg,IDC_FILE,g_bmedit_fn);
+ return 0;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetDlgItemText(hwndDlg,IDC_TITLE,g_bmedit_ft,4095);
+ GetDlgItemText(hwndDlg,IDC_FILE,g_bmedit_fn,MAX_PATH);
+ case IDCANCEL:
+ EndDialog(hwndDlg,0);
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK BookProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+// hi helpinfo[]={
+// };
+// DO_HELP();
+ switch (uMsg)
+ {
+ case WM_CTLCOLORLISTBOX:
+ if(listDragging)
+ {
+ POINT p;
+ RECT r;
+ int thisp;
+ GetCursorPos(&p);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_SELBOX),&r);
+ thisp=SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_ITEMFROMPOINT,0,MAKELPARAM(p.x-r.left,p.y-r.top-2));
+ if(HIWORD(thisp))
+ {
+ // mouse pointer outside client area
+ thisp=LOWORD(thisp);
+ }
+ if (listSel != -1 && listSel != thisp)
+ {
+ int len=SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCOUNT,0,0);
+ // move listSel to thisp.
+ if (thisp >= 0 && listSel >= 0 && thisp < len && listSel < len) {
+ char fn[MAX_PATH] = {0};
+ char file1[MAX_PATH] = {0}, title1[4096] = {0};
+ FILE *fp,*fpo;
+ Bookmark_getfn(fn);
+ fp=fopen(fn,"rt");
+
+ fpo=fopen(TEMP_FILE,"wt");
+ if (fp&&fpo)
+ {
+ char ft[4096] = {0};
+ int x=0;
+ while (1)
+ {
+ if (x == listSel)
+ {
+ fgets(file1,MAX_PATH,fp);
+ fgets(title1,4096,fp);
+ }
+ else
+ {
+ fgets(fn,MAX_PATH,fp);
+ fgets(ft,4096,fp);
+ }
+ if (feof(fp)) break;
+ x++;
+ }
+ fseek(fp,0,SEEK_SET);
+ x=0;
+ while (1)
+ {
+ fgets(fn,MAX_PATH,fp);
+ fgets(ft,4096,fp);
+ if (feof(fp)) break;
+ if (listSel < thisp)
+ {
+ if (x != listSel) fprintf(fpo,"%s%s",fn,ft);
+ if (x == thisp) fprintf(fpo,"%s%s",file1,title1);
+ }
+ else
+ {
+ if (x == thisp) fprintf(fpo,"%s%s",file1,title1);
+ if (x != listSel) fprintf(fpo,"%s%s",fn,ft);
+ }
+ x++;
+ }
+ }
+ if (fp) fclose(fp);
+ if (fpo) fclose(fpo);
+ if (fp && fpo)
+ {
+ Bookmark_getfn(fn);
+ DeleteFile(fn);
+ MoveFile(TEMP_FILE,fn);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETTEXT,(WPARAM)listSel,(LPARAM)title1);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_DELETESTRING,(WPARAM)listSel,0);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_INSERTSTRING,(WPARAM)thisp,(LPARAM)title1);
+ listSel=thisp;
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,thisp,0);
+ }
+ }
+
+ }
+ }
+ return 0;
+ case WM_USER+32:
+ if (wParam == 1024 && lParam == 3213)
+ {
+ char fn[MAX_PATH] = {0};
+
+ FILE *fp;
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_RESETCONTENT,0,0);
+ Bookmark_getfn(fn);
+ fp=fopen(fn,"rt");
+ if (fp)
+ {
+ while (1)
+ {
+ char ft[4096] = {0};
+ fgets(fn,MAX_PATH,fp);
+ if (feof(fp)) break;
+ fgets(ft,4096,fp);
+ if (feof(fp)) break;
+ if (ft[0] && fn[0])
+ {
+ if (fn[lstrlen(fn)-1]=='\n') fn[lstrlen(fn)-1]=0;
+ if (ft[lstrlen(ft)-1]=='\n') ft[lstrlen(ft)-1]=0;
+ if (ft[0] && fn[0])
+ {
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_ADDSTRING,0,(LPARAM)ft);
+ }
+ }
+ }
+ fclose(fp);
+ }
+ }
+ return 0;
+ case WM_INITDIALOG:
+ {
+ char fn[MAX_PATH] = {0};
+
+ FILE *fp;
+ OldBookListProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_SELBOX), GWLP_WNDPROC,(LONG)BookListProc);
+ listDragging=0;
+ listSel=-1;
+ Bookmark_getfn(fn);
+ fp=fopen(fn,"rt");
+ if (fp)
+ {
+ while (1)
+ {
+ char ft[4096] = {0};
+ fgets(fn,MAX_PATH,fp);
+ if (feof(fp)) break;
+ fgets(ft,4096,fp);
+ if (feof(fp)) break;
+ if (ft[0] && fn[0])
+ {
+ if (fn[lstrlen(fn)-1]=='\n') fn[lstrlen(fn)-1]=0;
+ if (ft[lstrlen(ft)-1]=='\n') ft[lstrlen(ft)-1]=0;
+ if (ft[0] && fn[0])
+ {
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_ADDSTRING,0,(LPARAM)ft);
+ }
+ }
+ }
+ fclose(fp);
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_BUTTON5:
+ case IDC_SELBOX:
+ case IDC_BUTTON4: // open
+ if (LOWORD(wParam) != IDC_SELBOX || HIWORD(wParam) == LBN_DBLCLK)
+ {
+ int x,len,openDir=0;
+ char fn[MAX_PATH] = {0};
+ FILE *fp;
+ Bookmark_getfn(fn);
+ fp=fopen(fn,"rt");
+
+ if (fp)
+ {
+ len=SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCOUNT,0,0);
+ for (x = 0; x < len; x ++)
+ {
+ char ft[4096] = {0};
+ fgets(fn,MAX_PATH,fp);
+ fgets(ft,4096,fp);
+ if (feof(fp)) break;
+ if (SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETSEL,x,0))
+ {
+ if (ft[0] && fn[0])
+ {
+ if (fn[lstrlen(fn)-1]=='\n') fn[lstrlen(fn)-1]=0;
+ if (ft[lstrlen(ft)-1]=='\n') ft[lstrlen(ft)-1]=0;
+ if (ft[0] && fn[0])
+ {
+ if (!strstr(fn,"http://"))
+ {
+ int ga=GetFileAttributes(fn);
+ if ((ga!=0xffffffff) && (ga & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ getNewFile((LOWORD(wParam) != IDC_BUTTON5),hwndDlg,fn);
+ openDir=1;
+ }
+ }
+ if(!openDir)
+ {
+ if (LOWORD(wParam) != IDC_BUTTON5) PlayList_delete();
+ PlayList_appendthing(fn);
+ }
+ }
+ }
+ }
+ }
+ if (LOWORD(wParam) != IDC_BUTTON5 && !openDir)
+ {
+ if (config_shuffle) PlayList_randpos(-BIGINT);
+ else PlayList_setposition(0);
+ PlayList_getcurrent(FileName,FileTitle,FileTitleNum);
+ plEditRefresh();
+ StartPlaying();
+ }
+ else
+ plEditRefresh();
+ fclose(fp);
+ }
+ }
+ return 0;
+ case IDC_EDITBOOK:
+ {
+ int sel=SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0);
+ if (sel != LB_ERR)
+ {
+ int x;
+ char fn[MAX_PATH] = {0};
+ FILE *fp,*fpo;
+ Bookmark_getfn(fn);
+ fp=fopen(fn,"rt");
+
+ fpo=fopen(TEMP_FILE,"wt");
+ if (fp&&fpo)
+ {
+ x=0;
+ while (1)
+ {
+ char ft[4096] = {0};
+ fgets(fn,MAX_PATH,fp);
+ fgets(ft,4096,fp);
+ if (feof(fp)) break;
+ if (fn[lstrlen(fn)-1]=='\n') fn[lstrlen(fn)-1]=0;
+ if (ft[lstrlen(ft)-1]=='\n') ft[lstrlen(ft)-1]=0;
+ if (x==sel)
+ {
+ g_bmedit_fn=fn;
+ g_bmedit_ft=ft;
+ LPDialogBox(IDD_EDITBOOKMARK,hwndDlg,BookMarkEditProc);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_DELETESTRING,x,0);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_INSERTSTRING,x,(LPARAM)ft);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,x,0);
+ }
+ fprintf(fpo,"%s\n%s\n",fn,ft);
+ x++;
+ }
+ }
+ if (fp) fclose(fp);
+ if (fpo) fclose(fpo);
+ if (fp && fpo)
+ {
+ Bookmark_getfn(fn);
+ DeleteFile(fn);
+ MoveFile(TEMP_FILE,fn);
+ }
+ }
+ }
+ return 0;
+ case IDC_BUTTON1: // remove
+ {
+ int sel=SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0);
+ if (sel != LB_ERR) {
+ char fn[MAX_PATH] = {0};
+ FILE *fp,*fpo;
+ Bookmark_getfn(fn);
+ fp=fopen(fn,"rt");
+
+ fpo=fopen(TEMP_FILE,"wt");
+ if (fp&&fpo)
+ {
+ int l=0;
+ int x=0;
+ while (1)
+ {
+ char ft[4096] = {0};
+ fgets(fn,MAX_PATH,fp);
+ fgets(ft,4096,fp);
+ if (feof(fp)) break;
+ if (x == sel)
+ {
+ l=x-1;
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_DELETESTRING,x,0);
+ }
+ else
+ {
+ fprintf(fpo,"%s%s",fn,ft);
+ }
+ x++;
+ }
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,l,0);
+ }
+ if (fp) fclose(fp);
+ if (fpo) fclose(fpo);
+ if (fp && fpo)
+ {
+ Bookmark_getfn(fn);
+ DeleteFile(fn);
+ MoveFile(TEMP_FILE,fn);
+ }
+ }
+ }
+ break;
+ }
+ return FALSE;
+ }
+ return 0;
+}
+
+#endif
diff --git a/Src/Winamp/options_classic.cpp b/Src/Winamp/options_classic.cpp
new file mode 100644
index 00000000..d876428a
--- /dev/null
+++ b/Src/Winamp/options_classic.cpp
@@ -0,0 +1,291 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include "resource.h"
+#include "options.h"
+
+static HWND subWnd;
+
+static LRESULT CALLBACK ClassicUIProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={
+ {IDC_SNAP,IDS_P_DISP_SNAP},
+ {IDC_SNAPW,IDS_P_DISP_SNAPW},
+ {IDC_HIGHLIGHT,IDS_P_DISP_HILITE},
+ {IDC_CLUTTERBAR,IDS_P_DISP_CB},
+ {IDC_TTIPS,IDS_P_DISP_TTIPS},
+ {IDC_WA_CURSORS,IDS_P_DISP_CURSORS},
+ {IDC_BIFONT,IDS_P_DISP_BIFONT},
+ {IDC_BIFONT_ALT,IDS_P_DISP_BIFONT_ALT},
+ {IDC_EQDSIZE,IDS_P_O_EQDS},
+ {IDC_SPLB,IDS_P_O_SPLB},
+ {IDC_CHECK2,IDS_P_DISP_FREESIZE},
+ {IDC_KEEPONSCREEN,IDS_P_O_LITESTEP},
+ {IDC_AOVD,IDS_P_O_AOVD},
+ {IDC_POS_IN_SONGTICKER,IDS_P_DISP_PLPOS},
+ };
+ DO_HELP();
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ CheckDlgButton(hwndDlg,IDC_SNAP,config_snap?1:0);
+ SetDlgItemInt(hwndDlg,IDC_SNAPW,config_snaplen,0);
+ CheckDlgButton(hwndDlg,IDC_HIGHLIGHT,config_hilite?1:0);
+ CheckDlgButton(hwndDlg,IDC_CLUTTERBAR,config_ascb_new?1:0);
+ CheckDlgButton(hwndDlg,IDC_TTIPS,config_ttips?1:0);
+ CheckDlgButton(hwndDlg,IDC_WA_CURSORS,config_usecursors?1:0);
+ CheckDlgButton(hwndDlg,IDC_BIFONT,config_bifont?1:0);
+ CheckDlgButton(hwndDlg,IDC_BIFONT_ALT,config_bifont_alt?1:0);
+ CheckDlgButton(hwndDlg,IDC_SPLB,config_ospb?1:0);
+ CheckDlgButton(hwndDlg,IDC_CHECK2,config_embedwnd_freesize?1:0);
+ CheckDlgButton(hwndDlg,IDC_EQDSIZE,config_eqdsize?1:0);
+ CheckDlgButton(hwndDlg,IDC_KEEPONSCREEN,(config_keeponscreen&1)?0:1);
+ CheckDlgButton(hwndDlg,IDC_AOVD,(config_keeponscreen&2)?1:0);
+ CheckDlgButton(hwndDlg,IDC_POS_IN_SONGTICKER,config_dotitlenum?1:0);
+
+ EnableWindow(GetDlgItem(hwndDlg,IDC_BIFONT_ALT),!config_bifont);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHECK2:
+ config_embedwnd_freesize=!!IsDlgButtonChecked(hwndDlg,IDC_CHECK2);
+ return 0;
+
+ case IDC_EQDSIZE:
+ config_eqdsize = (BST_CHECKED == IsDlgButtonChecked(hwndDlg,IDC_EQDSIZE));
+ set_aot(0);
+ break;
+
+ case IDC_SPLB:
+ config_ospb = (BST_CHECKED == IsDlgButtonChecked(hwndDlg,IDC_SPLB));
+ break;
+
+ case IDC_BIFONT:
+ config_bifont = (BST_CHECKED == IsDlgButtonChecked(hwndDlg,IDC_BIFONT)) ? 1 : 0;
+ EnableWindow(GetDlgItem(hwndDlg,IDC_BIFONT_ALT),!config_bifont);
+ g_need_titleupd=1;
+ InvalidateRect(hPLWindow, NULL, TRUE);
+ break;
+
+ case IDC_BIFONT_ALT:
+ config_bifont_alt = (BST_CHECKED == IsDlgButtonChecked(hwndDlg,IDC_BIFONT_ALT)) ? 1 : 0;
+ if (config_dsize)
+ {
+ draw_reinit_plfont(1);
+ }
+ break;
+
+ case IDC_POS_IN_SONGTICKER:
+ config_dotitlenum = IsDlgButtonChecked(hwndDlg,IDC_POS_IN_SONGTICKER)?1:0;
+ draw_songname(FileTitle, &ui_songposition, PlayList_getcurrentlength());
+ break;
+
+ case IDC_SNAP: config_snap = IsDlgButtonChecked(hwndDlg,IDC_SNAP)?1:0; break;
+
+ case IDC_SNAPW:
+ if (HIWORD(wParam) == EN_CHANGE) {
+ int t,a;
+ a=GetDlgItemInt(hwndDlg,IDC_SNAPW,&t,0);
+ if (t) config_snaplen= (unsigned char)a;
+ }
+ break;
+
+ case IDC_HIGHLIGHT: config_hilite = IsDlgButtonChecked(hwndDlg,IDC_HIGHLIGHT)?1:0; set_aot(0); break;
+
+ case IDC_CLUTTERBAR:
+ config_ascb_new = IsDlgButtonChecked(hwndDlg,IDC_CLUTTERBAR)?1:0;
+ if (hMainWindow) draw_clutterbar(0);
+ break;
+
+ case IDC_TTIPS:
+ config_ttips = IsDlgButtonChecked(hwndDlg,IDC_TTIPS)?1:0;
+ set_aot(0);
+ break;
+
+ case IDC_WA_CURSORS:
+ config_usecursors = IsDlgButtonChecked(hwndDlg,IDC_WA_CURSORS)?1:0;
+ break;
+
+ case IDC_KEEPONSCREEN:
+ case IDC_AOVD:
+ {
+ config_keeponscreen = IsDlgButtonChecked(hwndDlg,IDC_KEEPONSCREEN)?0:1;
+ config_keeponscreen |= IsDlgButtonChecked(hwndDlg,IDC_AOVD)?2:0;
+ SetWindowLongPtrW(hMainWindow,GWLP_USERDATA,(config_keeponscreen&2)?0x49474541:0);
+ SetWindowLongPtrW(hPLWindow,GWLP_USERDATA,(config_keeponscreen&2)?0x49474541:0);
+ SetWindowLongPtrW(hEQWindow,GWLP_USERDATA,(config_keeponscreen&2)?0x49474541:0);
+// SetWindowLong(hMBWindow,GWL_USERDATA,(config_keeponscreen&2)?0x49474541:0);
+ SetWindowLongPtrW(hVideoWindow,GWLP_USERDATA,(config_keeponscreen&2)?0x49474541:0);
+ }
+ break;
+ }
+ return FALSE;
+ }
+ return FALSE;
+} //display
+
+static LRESULT CALLBACK ClassicVisProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static int text_ids[4]=
+ {
+ IDS_P_CLASSIC_70FPS,
+ IDS_P_CLASSIC_35FPS,
+ IDS_P_CLASSIC_18FPS,
+ IDS_P_CLASSIC_9FPS
+ };
+#if 0
+ hi helpinfo[]={
+ {IDC_USEID4,IDS_P_O_ONLOAD},
+ };
+ DO_HELP();
+#endif
+ if(uMsg == WM_INITDIALOG)
+ {
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER3),TBM_SETRANGEMAX,0,3);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER3),TBM_SETRANGEMIN,0,0);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER3),TBM_SETPOS,1,4-config_saref);
+
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER1),TBM_SETRANGEMAX,0,4);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER1),TBM_SETRANGEMIN,0,0);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER1),TBM_SETPOS,1,config_safalloff);
+
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER2),TBM_SETRANGEMAX,0,4);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER2),TBM_SETRANGEMIN,0,0);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SLIDER2),TBM_SETPOS,1,config_sa_peak_falloff);
+
+ SetDlgItemTextW(hwndDlg,IDC_RRATE,getStringW(text_ids[config_saref-1],NULL,0));
+ if (config_sa == 1) CheckDlgButton(hwndDlg,IDC_RADIO1,BST_CHECKED);
+ else if (config_sa == 2) CheckDlgButton(hwndDlg,IDC_RADIO2,BST_CHECKED);
+ else CheckDlgButton(hwndDlg,IDC_RADIO3,BST_CHECKED);
+
+ if ((config_safire&3) == 1) CheckDlgButton(hwndDlg,IDC_RADIO5,BST_CHECKED);
+ else if ((config_safire&3) == 2) CheckDlgButton(hwndDlg,IDC_RADIO6,BST_CHECKED);
+ else CheckDlgButton(hwndDlg,IDC_RADIO4,BST_CHECKED);
+
+ if (config_sa_peaks) CheckDlgButton(hwndDlg,IDC_CHECK1,BST_CHECKED);
+ if ((config_safire&32)) CheckDlgButton(hwndDlg,IDC_RADIO7,BST_CHECKED);
+ else CheckDlgButton(hwndDlg,IDC_RADIO8,BST_CHECKED);
+
+ if (((config_safire>>2)&3)==0) CheckDlgButton(hwndDlg,IDC_RADIO9,BST_CHECKED);
+ else if (((config_safire>>2)&3)==1) CheckDlgButton(hwndDlg,IDC_RADIO10,BST_CHECKED);
+ else CheckDlgButton(hwndDlg,IDC_RADIO11,BST_CHECKED);
+ }
+
+ if (uMsg == WM_HSCROLL)
+ {
+ HWND swnd = (HWND) lParam;
+ int t=(int)SendMessageW(swnd,TBM_GETPOS,0,0);
+ if (swnd == GetDlgItem(hwndDlg,IDC_SLIDER3))
+ {
+ config_saref=(unsigned char)(4-t);
+ SetDlgItemTextW(hwndDlg,IDC_RRATE,getStringW(text_ids[config_saref-1],NULL,0));
+ }
+
+ if (swnd == GetDlgItem(hwndDlg,IDC_SLIDER2))
+ {
+ config_sa_peak_falloff = (unsigned char)t;
+ }
+
+ if (swnd == GetDlgItem(hwndDlg,IDC_SLIDER1))
+ {
+ config_safalloff= (unsigned char)t;
+ }
+ }
+
+ if (uMsg == WM_COMMAND)
+ switch (LOWORD(wParam))
+ {
+ case IDC_RADIO1:
+ case IDC_RADIO2:
+ case IDC_RADIO3:
+ if (IsDlgButtonChecked(hwndDlg,IDC_RADIO1)) config_sa=1;
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO2)) config_sa=2;
+ else config_sa=0;
+ sa_setthread(config_sa);
+ break;
+
+ case IDC_RADIO4:
+ case IDC_RADIO5:
+ case IDC_RADIO6:
+ config_safire &= ~3;
+ if (IsDlgButtonChecked(hwndDlg,IDC_RADIO5)) config_safire |= 1;
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO6)) config_safire |= 2;
+ break;
+
+ case IDC_CHECK1:
+ config_sa_peaks = IsDlgButtonChecked(hwndDlg,IDC_CHECK1)?1:0;
+ break;
+
+ case IDC_RADIO7:
+ case IDC_RADIO8:
+ if (IsDlgButtonChecked(hwndDlg,IDC_RADIO7)) config_safire|=32;
+ else config_safire&=~32;
+ break;
+
+ case IDC_RADIO9:
+ case IDC_RADIO10:
+ case IDC_RADIO11:
+ config_safire &= ~(3<<2);
+ if (IsDlgButtonChecked(hwndDlg,IDC_RADIO10)) config_safire |= 1<<2;
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO11)) config_safire |= 2<<2;
+ break;
+ }
+
+ const int controls[] =
+ {
+ IDC_SLIDER1,
+ IDC_SLIDER2,
+ IDC_SLIDER3,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ return TRUE;
+
+ return FALSE;
+} // vis options
+
+multiPage classicPages[] = {
+ {IDD_CLASSIC_UI, ClassicUIProc},
+ {IDD_CLASSIC_VIS, ClassicVisProc},
+};
+
+INT_PTR CALLBACK classicSkinProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ TCITEMW item = {0};
+ HWND tabwnd=GetDlgItem(hwndDlg,IDC_TAB1);
+ item.mask=TCIF_TEXT;
+ item.pszText=getStringW(IDS_P_CLASSICUI,NULL,0);
+ SendMessageW(tabwnd, TCM_INSERTITEMW, 0, (LPARAM)&item);
+ item.pszText=getStringW(IDS_P_CLASSICVIS,NULL,0);
+ SendMessageW(tabwnd, TCM_INSERTITEMW, 1, (LPARAM)&item);
+
+ TabCtrl_SetCurSel(tabwnd,config_last_classic_skin_page);
+ subWnd = _dosetsel(hwndDlg,subWnd,&config_last_classic_skin_page,classicPages,sizeof(classicPages)/sizeof(classicPages[0]));
+ }
+ return 0;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR p=(LPNMHDR)lParam;
+ if (p->idFrom == IDC_TAB1 && p->code == TCN_SELCHANGE)
+ subWnd = _dosetsel(hwndDlg,subWnd,&config_last_classic_skin_page,classicPages,sizeof(classicPages)/sizeof(classicPages[0]));
+ }
+ return 0;
+
+ case WM_DESTROY:
+ subWnd=NULL;
+ return 0;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/options_dsp.cpp b/Src/Winamp/options_dsp.cpp
new file mode 100644
index 00000000..ff401846
--- /dev/null
+++ b/Src/Winamp/options_dsp.cpp
@@ -0,0 +1,494 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "resource.h"
+#include "Options.h"
+#include "dsp.h"
+#include "main.hpp"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+
+static bool pluginsLoaded;
+
+static void DSPUpdateSel( HWND hwndDlg, HWND listWindow, INT iItem )
+{
+ wchar_t fn[ MAX_PATH * 2 ] = { 0 }, *libname = fn;
+ int skip = 0;
+
+ if ( ListView_GetNextItem( listWindow, -1, LVIS_SELECTED ) != -1 )
+ {
+ ListView_GetItemTextW( listWindow, iItem, 1, fn, ARRAYSIZE( fn ) );
+ SendDlgItemMessageA( hwndDlg, IDC_DSPMOD, CB_RESETCONTENT, 0, 0 );
+
+ int root = lstrcmpW( fn, getStringW( IDS_NOT_LOADED, NULL, 0 ) );
+
+ if ( fn[ 0 ] && root )
+ {
+ if ( lstrcmpW( config_dspplugin_name, libname ) )
+ config_dspplugin_num = 0;
+ }
+ else
+ {
+ if ( fn[ 0 ] )
+ skip = 1;
+
+ config_dspplugin_num = 0;
+ }
+
+ StringCchCopyW( config_dspplugin_name, MAX_PATH, libname );
+
+ if ( *libname && !skip )
+ {
+ wchar_t b[ 1024 ] = { 0 };
+ PathCombineW( b, DSPDIR, libname );
+
+ HINSTANCE hLib = LoadLibraryW( b );
+
+ if ( hLib )
+ {
+ winampDSPGetHeaderType pr = (winampDSPGetHeaderType) GetProcAddress( hLib, "winampDSPGetHeader2" );
+ if ( pr )
+ {
+ int i = 0;
+
+ for ( ;;)
+ {
+ winampDSPModule *module = pr( hMainWindow )->getModule( i++ );
+
+ if ( !module )
+ break;
+
+ SendDlgItemMessageA( hwndDlg, IDC_DSPMOD, CB_ADDSTRING, 0, (LPARAM) (LPCSTR)module->description );
+ // The description must be send in ASCII
+ }
+ }
+
+ FreeModule( hLib );
+ }
+
+ SendDlgItemMessageA( hwndDlg, IDC_DSPMOD, CB_SETCURSEL, config_dspplugin_num, 0 );
+ }
+ }
+
+ config_dspplugin_num = (unsigned char) SendDlgItemMessageA( hwndDlg, IDC_DSPMOD, CB_GETCURSEL, 0, 0 );
+
+ if ( config_dspplugin_num == CB_ERR )
+ config_dspplugin_num = 0;
+
+ if ( pluginsLoaded )
+ {
+ dsp_quit();
+ dsp_init();
+ }
+
+ if ( skip )
+ fn[ 0 ] = 0;
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DSPCONF ), libname && !!*libname );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UNINSTDSP ), libname && !!*libname || skip );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DSPMOD ), libname && !!*libname );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PLUGINLABEL ), libname && !!*libname );
+}
+
+// dsp tab procedure
+INT_PTR CALLBACK DspProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ hi helpinfo[] = {
+ {IDC_DSPLIB,IDS_P_DSP_LIB},
+ {IDC_DSPMOD,IDS_P_DSP_MOD},
+ {IDC_DSPCONF,IDS_P_DSP_CONF},
+ };
+
+ DO_HELP();
+
+ if ( uMsg == WM_INITDIALOG )
+ {
+ pluginsLoaded = false;
+
+ link_startsubclass( hwndDlg, IDC_PLUGINVERS );
+
+ HWND listWindow = GetDlgItem( hwndDlg, IDC_DSPLIB );
+ if ( IsWindow( listWindow ) )
+ {
+ RECT r = { 0 };
+ GetWindowRect( listWindow, &r );
+ GetClientRect( listWindow, &r );
+ MapWindowPoints( listWindow, hwndDlg, (LPPOINT) &r, 2 );
+ InflateRect( &r, 2, 2 );
+ DestroyWindow( listWindow );
+
+ listWindow = CreateWindowExW( WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, WC_LISTVIEWW, L"",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL |
+ LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER,
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ hwndDlg, (HMENU) IDC_DSPLIB, NULL, NULL );
+
+ SetWindowPos( listWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING );
+
+ ListView_SetExtendedListViewStyleEx( listWindow, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP );
+ SendMessageW( listWindow, WM_SETFONT, SendMessageW( hwndDlg, WM_GETFONT, 0, 0 ), FALSE );
+
+ LVCOLUMNW lvc = { 0 };
+ ListView_InsertColumnW( listWindow, 0, &lvc );
+ ListView_InsertColumnW( listWindow, 1, &lvc );
+
+ if ( !g_safeMode )
+ {
+ SendMessageW( listWindow, LB_SETITEMDATA,
+ SendMessageW( listWindow, LB_ADDSTRING, 0, (LPARAM) getStringW( IDS_DSP_NONE, NULL, 0 ) ),
+ (LPARAM) 0 );
+ SendMessageW( listWindow, LB_SETCURSEL, 0, 0 );
+
+ LVITEMW lvi = { LVIF_TEXT | LVIF_STATE, 0, 0 };
+ lvi.pszText = getStringW( IDS_DSP_NONE, NULL, 0 );
+ lvi.state = LVIS_SELECTED | LVIS_FOCUSED;
+ ListView_InsertItemW( listWindow, &lvi );
+ }
+
+ WIN32_FIND_DATAW d = { 0 };
+ wchar_t dirstr[ MAX_PATH ] = { 0 };
+ PathCombineW( dirstr, DSPDIR, L"DSP_*.DLL" );
+
+ HANDLE h = FindFirstFileW( dirstr, &d );
+ if ( h != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ if ( !g_safeMode )
+ {
+ wchar_t dsp_dir[ 1024 ] = { 0 }, namestr[ MAX_PATH + 256 ] = { 0 };
+ PathCombineW( dsp_dir, DSPDIR, d.cFileName );
+
+ HINSTANCE hLib = LoadLibraryW( dsp_dir );
+ if ( hLib )
+ {
+ winampDSPGetHeaderType pr = (winampDSPGetHeaderType) GetProcAddress( hLib, "winampDSPGetHeader2" );
+ if ( pr )
+ {
+ winampDSPHeader *header = pr( hMainWindow );
+
+ if ( header && header->version >= DSP_HDRVER && header->version < DSP_HDRVER + 0x10 )
+ StringCchCopyW( namestr, MAX_PATH + 256, AutoWide( header->description ) );
+ else
+ StringCchCopyW( namestr, MAX_PATH + 256, L"!" );
+ }
+ else
+ {
+ StringCchCopyW( namestr, MAX_PATH + 256, L"!" );
+ }
+ FreeModule( hLib );
+ }
+ else
+ {
+ StringCchCopyW( namestr, MAX_PATH + 256, L"!" );
+ }
+
+ if ( wcscmp( namestr, L"!" ) )
+ {
+ LVITEMW lvi = { LVIF_TEXT, 0, 0 };
+ lvi.pszText = namestr;
+ lvi.iItem = ListView_InsertItemW( listWindow, &lvi );
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = d.cFileName;
+ ListView_SetItemW( listWindow, &lvi );
+
+ if ( !_wcsicmp( d.cFileName, config_dspplugin_name ) )
+ {
+ ListView_SetItemState( listWindow, lvi.iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
+ DSPUpdateSel( hwndDlg, listWindow, lvi.iItem );
+ }
+ }
+ else
+ {
+ LVITEMW lvi = { LVIF_TEXT, 0, 0 };
+ lvi.pszText = d.cFileName;
+ lvi.iItem = ListView_InsertItemW( listWindow, &lvi );
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = getStringW( IDS_NOT_LOADED, NULL, 0 );
+ ListView_SetItemW( listWindow, &lvi );
+ }
+ }
+ else
+ {
+ LVITEMW lvi = { LVIF_TEXT, 0, 0 };
+ lvi.pszText = d.cFileName;
+ lvi.iItem = ListView_InsertItemW( listWindow, &lvi );
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = getStringW( IDS_NOT_LOADED, NULL, 0 );
+ ListView_SetItemW( listWindow, &lvi );
+ }
+ } while ( FindNextFileW( h, &d ) );
+
+ FindClose( h );
+ }
+
+ if ( g_safeMode && !ListView_GetItemCount( listWindow ) )
+ {
+ LVITEMW lvi = { LVIF_TEXT | LVIF_STATE, 0, 0 };
+ lvi.pszText = getStringW( IDS_DSP_NONE, NULL, 0 );
+ lvi.state = LVIS_SELECTED | LVIS_FOCUSED;
+ ListView_InsertItemW( listWindow, &lvi );
+ }
+
+ GetClientRect( listWindow, &r );
+ ListView_SetColumnWidth( listWindow, 1, LVSCW_AUTOSIZE );
+ ListView_SetColumnWidth( listWindow, 0, ( r.right - r.left ) - ListView_GetColumnWidth( listWindow, 1 ) );
+
+ DirectMouseWheel_EnableConvertToMouseWheel( listWindow, TRUE );
+
+ pluginsLoaded = true;
+ }
+ }
+ else if ( uMsg == WM_DESTROY )
+ {
+ HWND listWindow = GetDlgItem( hwndDlg, IDC_DSPLIB );
+
+ if ( IsWindow( listWindow ) )
+ DirectMouseWheel_EnableConvertToMouseWheel( listWindow, FALSE );
+ }
+ else if ( uMsg == WM_NOTIFY )
+ {
+ static int own_update;
+
+ LPNMHDR p = (LPNMHDR) lParam;
+ if ( p->idFrom == IDC_DSPLIB )
+ {
+ if ( p->code == LVN_ITEMCHANGED && pluginsLoaded && !own_update )
+ {
+ if ( !g_safeMode )
+ {
+ LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
+ LVITEM lvi = { LVIF_PARAM, pnmv->iItem };
+
+ if ( ListView_GetItem( p->hwndFrom, &lvi ) && ( pnmv->uNewState & LVIS_SELECTED ) )
+ {
+ own_update = 1;
+ DSPUpdateSel( hwndDlg, p->hwndFrom, pnmv->iItem );
+ own_update = 0;
+ }
+ }
+ }
+ else if ( p->code == NM_DBLCLK || p->code == NM_CLICK )
+ {
+ // helps to keep the selection on things...
+ LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE) lParam;
+ if ( lpnmitem->iItem == -1 )
+ {
+ int which = ListView_GetNextItem( p->hwndFrom, -1, LVIS_SELECTED );
+ if ( which == -1 )
+ {
+ for ( int i = 0; i < ListView_GetItemCount( p->hwndFrom ); i++ )
+ {
+ wchar_t fn[ MAX_PATH * 2 ] = { 0 };
+ ListView_GetItemTextW( p->hwndFrom, i, 1, fn, ARRAYSIZE( fn ) );
+
+ if ( !_wcsicmp( fn, config_dspplugin_name ) )
+ {
+ own_update = 1;
+ ListView_SetItemState( p->hwndFrom, i, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
+ own_update = 0;
+ break;
+ }
+ }
+ }
+ else
+ ListView_SetItemState( p->hwndFrom, which, LVIS_SELECTED, LVIS_SELECTED );
+ }
+
+ if ( p->code == NM_DBLCLK )
+ {
+ PostMessageW( hwndDlg, WM_COMMAND, MAKEWPARAM( IDC_DSPCONF, 0 ), (LPARAM) GetDlgItem( hwndDlg, IDC_DSPCONF ) );
+ }
+ }
+ }
+ else if ( p->code == HDN_ITEMCHANGINGW )
+ {
+ if ( pluginsLoaded )
+ {
+#ifdef WIN64
+ SetWindowLongPtrW( hwndDlg, DWLP_MSGRESULT, TRUE );
+#else
+ SetWindowLongW( hwndDlg, DWL_MSGRESULT, TRUE );
+#endif
+ return TRUE;
+ }
+ }
+ }
+ else if ( uMsg == WM_COMMAND )
+ {
+ switch ( LOWORD( wParam ) )
+ {
+ case IDC_DSPMOD:
+ if ( HIWORD( wParam ) == CBN_SELCHANGE )
+ {
+ config_dspplugin_num = (unsigned char) SendDlgItemMessageA( hwndDlg, IDC_DSPMOD, CB_GETCURSEL, 0, 0 );
+
+ if ( config_dspplugin_num == CB_ERR )
+ config_dspplugin_num = 0;
+
+ if ( pluginsLoaded && config_dspplugin_name[ 0 ] )
+ {
+ dsp_quit();
+ dsp_init();
+ }
+
+ return FALSE;
+ }
+
+
+ case IDC_DSPCONF:
+ {
+ if ( g_safeMode ) return FALSE;
+
+ if ( IsWindowEnabled( GetDlgItem( hwndDlg, IDC_DSPCONF ) ) )
+ {
+ wchar_t b[ 1024 ] = { 0 };
+ PathCombineW( b, DSPDIR, config_dspplugin_name );
+ HINSTANCE hLib = LoadLibraryW( b );
+ if ( hLib )
+ {
+ winampDSPGetHeaderType pr = (winampDSPGetHeaderType) GetProcAddress( hLib, "winampDSPGetHeader2" );
+ winampDSPModule *module = pr( hMainWindow )->getModule( SendDlgItemMessageA( hwndDlg, IDC_DSPMOD, CB_GETCURSEL, 0, 0 ) );
+
+ if ( module )
+ {
+ module->hDllInstance = hLib;
+ module->hwndParent = hMainWindow;
+
+ if ( !( config_no_visseh & 2 ) )
+ {
+ try
+ {
+ module->Config( module );
+ }
+ catch ( ... )
+ {
+ LPMessageBox( hwndDlg, IDS_PLUGINERROR, IDS_ERROR, MB_OK | MB_ICONEXCLAMATION );
+ }
+ }
+ else
+ {
+ module->Config( module );
+ }
+ }
+ else
+ {
+ LPMessageBox( hwndDlg, IDS_ERRORLOADINGPLUGIN, IDS_ERROR, MB_OK );
+ }
+
+ FreeLibrary( hLib );
+ }
+ else
+ {
+ LPMessageBox( hwndDlg, IDS_ERRORLOADINGPLUGIN, IDS_ERROR, MB_OK );
+ }
+ }
+
+ return FALSE;
+ }
+
+ case IDC_UNINSTDSP:
+ {
+ if ( g_safeMode ) return FALSE;
+
+ if ( IsWindowEnabled( GetDlgItem( hwndDlg, IDC_UNINSTDSP ) ) )
+ {
+ HWND listWindow = GetDlgItem( hwndDlg, IDC_DSPLIB );
+ int which = ListView_GetNextItem( listWindow, -1, LVIS_SELECTED );
+ wchar_t fn[ FILENAME_SIZE ] = { 0 };
+ ListView_GetItemTextW( listWindow, which, 1, fn, ARRAYSIZE( fn ) );
+
+ // copes with not-loaded plug-in dlls
+ if ( !lstrcmpW( fn, getStringW( IDS_NOT_LOADED, NULL, 0 ) ) )
+ {
+ ListView_GetItemTextW( listWindow, which, 0, fn, ARRAYSIZE( fn ) );
+ }
+
+ if ( fn[ 0 ] && LPMessageBox( hwndDlg, IDS_P_PLUGIN_UNINSTALL, IDS_P_PLUGIN_UNINSTALL_CONFIRM, MB_YESNO | MB_ICONEXCLAMATION ) == IDYES )
+ {
+ wchar_t b[ MAX_PATH ] = { 0 };
+ dsp_quit();
+ PathCombineW( b, DSPDIR, fn );
+
+ HINSTANCE hLib = LoadLibraryW( b );
+ if ( hLib )
+ {
+ int ret = DSP_PLUGIN_UNINSTALL_NOW;
+ int ( *pr )( HINSTANCE hDllInst, HWND hwndDlg, int param );
+ *(void **) &pr = (void *) GetProcAddress( hLib, "winampUninstallPlugin" );
+
+ if ( pr )
+ ret = pr( hLib, hwndDlg, 0 );
+
+ wchar_t buf[ MAX_PATH ] = { 0 };
+ GetModuleFileNameW( hLib, buf, MAX_PATH );
+ FreeLibrary( hLib );
+
+ if ( ret == DSP_PLUGIN_UNINSTALL_NOW )
+ {
+ IFileTypeRegistrar *registrar = 0;
+ if ( GetRegistrar( &registrar, true ) == 0 && registrar )
+ {
+ if ( registrar->DeleteItem( buf ) != S_OK )
+ {
+ _w_sW( "remove_genplug", buf );
+ _w_i( "show_prefs", 34 );
+ }
+ else
+ ListView_DeleteItem( listWindow, which );
+
+ registrar->Release();
+ }
+ }
+ else if ( ret == DSP_PLUGIN_UNINSTALL_REBOOT )
+ {
+ extern void _w_s( char *name, char *data );
+ wchar_t buf[ 1024 ] = { 0 };
+ GetModuleFileNameW( hLib, buf, MAX_PATH );
+ _w_sW( "remove_genplug", buf );
+ _w_i( "show_prefs", 34 );
+ PostMessageW( hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP );
+ }
+ }
+ else
+ {
+ IFileTypeRegistrar *registrar = 0;
+ if ( GetRegistrar( &registrar, true ) == 0 && registrar )
+ {
+ if ( registrar->DeleteItem( b ) != S_OK )
+ {
+ _w_sW( "remove_genplug", fn );
+ _w_i( "show_prefs", 34 );
+ }
+ else
+ ListView_DeleteItem( listWindow, which );
+
+ registrar->Release();
+ }
+ }
+ }
+ }
+
+ return FALSE;
+ }
+
+ case IDC_PLUGINVERS:
+ myOpenURLWithFallback( hwndDlg, L"http://www.google.com/search?q=Winamp+DSP+Effect+Plugins", L"http://www.google.com/search?q=Winamp+DSP+Effect+Plugins" );
+ return TRUE;
+ }
+ }
+
+ link_handledraw( hwndDlg, uMsg, wParam, lParam );
+ return FALSE;
+} //dsp \ No newline at end of file
diff --git a/Src/Winamp/options_filetypes.cpp b/Src/Winamp/options_filetypes.cpp
new file mode 100644
index 00000000..52834237
--- /dev/null
+++ b/Src/Winamp/options_filetypes.cpp
@@ -0,0 +1,460 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "Options.h"
+#include "api.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "resource.h"
+
+#define OPT_CD 0x1
+#define OPT_ENQ 0x2
+#define OPT_DIR 0x4
+#define OPT_EXT 0x8
+#define OPT_ICON 0x10
+
+static int optchanged,
+ old_whichicon,
+ old_whichicon2;
+
+static void hideShowAgentItems(HWND hwndDlg)
+{
+ int enabled = IsDlgButtonChecked(hwndDlg, IDC_CHECK1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK2), enabled);
+}
+
+static BOOL iconsChanged(void)
+{
+ if(optchanged & OPT_ICON)
+ {
+ if(old_whichicon != config_whichicon || old_whichicon2 != config_whichicon2)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// this is used to block selections being shown in the file types listbox
+// when running on Windows 8 as selecting doesn't work due to OS changes,
+// so we block mouse clicks as well as the space key for toggling things.
+LRESULT win8_handleclick(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if(uMsg == WM_KEYDOWN && wParam == VK_SPACE)
+ {
+ return 0;
+ }
+ LRESULT ret = CallWindowProcW((WNDPROC)GetPropW(hwndDlg, L"win8_proc"), hwndDlg, uMsg, wParam, lParam);
+ if(uMsg == WM_LBUTTONDOWN)
+ {
+ SendMessageW(hwndDlg,LB_SETSEL,0,-1);
+ }
+ return ret;
+}
+
+// file type tab procedure
+INT_PTR CALLBACK FtypeProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={
+ {IDC_FILETYPES_ICONSCROLL,IDS_P_FT_ICON},
+ {IDC_FILETYPES_ICONSCROLL2,IDS_P_FT_ICON2},
+ {IDC_ADDFILES,IDS_P_FT_ENQUEUE},
+ {IDC_DIRCONTEXT,IDS_P_FT_DIRCONTEXT},
+ {IDC_FTYPE_LIST,(!IsWin8()?IDS_P_FT_EXTENSIONS:IDS_P_FT_EXTENSIONS_WIN8)},
+ {IDC_SELALL,IDS_P_FT_ALL},
+ {IDC_SELNONE,IDS_P_FT_NO},
+ {IDC_CD,IDS_P_FT_CD},
+ {IDC_RSTART,IDS_P_FT_RSTART},
+ {IDC_CHECK1,IDS_P_A_ENABLE},
+ {IDC_CHECK2,IDS_P_A_TRAY},
+ };
+ DO_HELP();
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ optchanged=0;
+ old_whichicon=config_whichicon;
+ old_whichicon2=config_whichicon2;
+
+ link_startsubclass(hwndDlg, IDC_SET_DEF_PROGRAM);
+ SetPropW(GetDlgItem(hwndDlg, IDC_SET_DEF_PROGRAM), L"slim", (HANDLE)1);
+
+ if (FindWindowW(L"WinampAgentMain",NULL))
+ CheckDlgButton(hwndDlg,IDC_CHECK1,BST_CHECKED);
+ if (GetPrivateProfileIntW(L"WinampAgent",L"is_intray",1,INI_FILE))
+ CheckDlgButton(hwndDlg,IDC_CHECK2,BST_CHECKED);
+
+ SendMessageW(GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL),TBM_SETRANGEMAX,0,12);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL),TBM_SETRANGEMIN,0,0);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL),TBM_SETPOS,1,config_whichicon);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL2),TBM_SETRANGEMAX,0,12);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL2),TBM_SETRANGEMIN,0,0);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL2),TBM_SETPOS,1,config_whichicon2);
+ CheckDlgButton(hwndDlg,IDC_ADDFILES,config_addtolist?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DIRCONTEXT,config_isdircontext()?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_CD,config_iscdplayer()?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_RSTART,config_check_ft_startup?BST_CHECKED:BST_UNCHECKED);
+
+ wchar_t *exl = in_getextlistW();
+ wchar_t *a = exl;
+ wchar_t buf[MAX_PATH] = {0};
+ HWND hwnd = GetDlgItem(hwndDlg,IDC_FTYPE_LIST);
+ if (IsWindow(hwnd))
+ {
+ while (a && *a)
+ {
+ int len = min(lstrlenW(a) + 1, MAX_PATH);
+ lstrcpynW(buf, a, len);
+
+ int i = SendMessageW(hwnd, LB_ADDSTRING, 0, (LPARAM)buf);
+ if (!IsWin8() && config_isregistered(a))
+ {
+ SendMessageW(hwnd,LB_SETSEL,(WPARAM)TRUE,(LPARAM)i);
+ }
+ a+=len;
+ }
+ DirectMouseWheel_EnableConvertToMouseWheel(hwnd, TRUE);
+ if (IsWin8())
+ {
+ SetPropW(hwnd, L"win8_proc",
+ (HANDLE)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)win8_handleclick));
+ }
+ }
+
+ if (playlistManager && playlistManager != (api_playlistmanager *)1)
+ {
+ size_t playlistEnum = 0;
+ int lastFind = -1;
+ const wchar_t *playlistExt=0;
+ while (NULL != (playlistExt=playlistManager->EnumExtension(playlistEnum++)))
+ {
+ int len = min(lstrlenW(playlistExt) + 1, MAX_PATH);
+ lstrcpynW(buf, playlistExt, len);
+ CharUpperBuffW(buf, len);
+
+ if ((lastFind = SendMessageW(hwnd, LB_FINDSTRINGEXACT, lastFind, (LPARAM)buf)) == LB_ERR)
+ {
+ int i = SendMessageW(hwnd, LB_ADDSTRING, 0, (LPARAM)buf);
+ if (!IsWin8() && config_isregistered((wchar_t*)playlistExt))
+ {
+ SendMessageW(hwnd, LB_SETSEL, (WPARAM)TRUE, (LPARAM)i);
+ }
+ }
+ }
+ }
+ GlobalFree((HGLOBAL)exl);
+ SendMessageW(hwnd,LB_SETTOPINDEX,0,0);
+
+ wchar_t s[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance,s,MAX_PATH);
+ PathRemoveFileSpecW(s);
+ PathAppendW(s, L"winampa.exe");
+ HANDLE hf = CreateFileW(s,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
+ if (hf != INVALID_HANDLE_VALUE)
+ CloseHandle(hf);
+ else
+ {
+ int ids[]={IDC_WATEXT2,IDC_WATEXT1,IDC_CHECK1,IDC_CHECK2};
+ for (int x=0; x<sizeof(ids)/sizeof(ids[0]); x++)
+ ShowWindow(GetDlgItem(hwndDlg,ids[x]),SW_HIDE);
+ }
+
+ hideShowAgentItems(hwndDlg);
+ }
+ return 0;
+ case WM_DESTROY:
+ {
+ extern void _w_s(char *name, char *data);
+ HWND hwnd=GetDlgItem(hwndDlg,IDC_FTYPE_LIST);
+ int top = SendMessageW(hwnd,LB_GETCOUNT,0,0);
+
+ DirectMouseWheel_EnableConvertToMouseWheel(hwnd, FALSE);
+
+ // if control is held when closing the page then force a saving irrespective
+ if ((GetAsyncKeyState(VK_CONTROL)&0x8000)) optchanged = OPT_CD|OPT_ENQ|OPT_DIR|OPT_EXT|OPT_ICON;
+
+ // TODO: clear all capabilities/FileAssociations in registry so we can have a fresh list
+ if (optchanged & OPT_EXT || iconsChanged())
+ {
+ if (!config_registermediaplayer(2))
+ {
+ LPMessageBox(hwndDlg, IDS_P_FILE_ASSOC_FAILURE, IDS_P_FILE_ASSOC, MB_OK | MB_ICONEXCLAMATION);
+ return 0;
+ }
+ }
+
+ config_addtolist = IsDlgButtonChecked(hwndDlg,IDC_ADDFILES)?1:0;
+ if (optchanged & OPT_EXT || optchanged & OPT_ENQ || iconsChanged())
+ {
+ if (!config_setup_filetypes(1))
+ {
+ LPMessageBox(hwndDlg, IDS_P_FILE_ASSOC_FAILURE, IDS_P_FILE_ASSOC, MB_OK | MB_ICONEXCLAMATION);
+ return 0;
+ }
+ }
+
+ if (optchanged & OPT_DIR)
+ {
+ if (IsDlgButtonChecked(hwndDlg,IDC_DIRCONTEXT))
+ {
+ if (!config_isdircontext())
+ {
+ if (!config_adddircontext(1))
+ {
+ LPMessageBox(hwndDlg, IDS_P_FILE_ASSOC_FAILURE, IDS_P_FILE_ASSOC, MB_OK | MB_ICONEXCLAMATION);
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ if (config_isdircontext())
+ {
+ if (!config_removedircontext(1))
+ {
+ LPMessageBox(hwndDlg, IDS_P_FILE_ASSOC_FAILURE, IDS_P_FILE_ASSOC, MB_OK | MB_ICONEXCLAMATION);
+ return 0;
+ }
+ }
+ }
+ }
+
+ if (optchanged & OPT_CD)
+ {
+ if (!config_regcdplayer(IsDlgButtonChecked(hwndDlg,IDC_CD), 1))
+ {
+ LPMessageBox(hwndDlg, IDS_P_FILE_ASSOC_FAILURE, IDS_P_FILE_ASSOC, MB_OK | MB_ICONEXCLAMATION);
+ return 0;
+ }
+ }
+
+ if (optchanged & OPT_EXT || iconsChanged())
+ {
+ // on Windows 8 we specify all of the extensions which are supported
+ // so they can be selected by the 'set default programs' interface as
+ // the preferences dialog is not able to do it due to OS changes made
+ wchar_t ext_list[16384] = {0};
+ if (IsWin8())
+ {
+ for (int x = 0; x < top; x ++)
+ {
+ wchar_t buf[256] = {0};
+ SendMessageW(hwnd, LB_GETTEXT, x, (LPARAM)buf);
+ if (x) StringCchCatW(ext_list, ARRAYSIZE(ext_list), L":");
+ StringCchCatW(ext_list, ARRAYSIZE(ext_list), buf);
+ if (!config_register_capability(buf, 1))
+ {
+ LPMessageBox(hwndDlg, IDS_P_FILE_ASSOC_FAILURE, IDS_P_FILE_ASSOC, MB_OK | MB_ICONEXCLAMATION);
+ break;
+ }
+ config_register(buf,1);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < top; x ++)
+ {
+ wchar_t buf[256] = {0};
+ SendMessageW(hwnd, LB_GETTEXT, x, (LPARAM)buf);
+ if (SendMessageW(hwnd,LB_GETSEL,x,0))
+ {
+ if (x) StringCchCatW(ext_list, ARRAYSIZE(ext_list), L":");
+ StringCchCatW(ext_list, ARRAYSIZE(ext_list), buf);
+ }
+ if (!config_register_capability(buf, 1))
+ {
+ LPMessageBox(hwndDlg, IDS_P_FILE_ASSOC_FAILURE, IDS_P_FILE_ASSOC, MB_OK | MB_ICONEXCLAMATION);
+ break;
+ }
+ config_register(buf, SendMessageW(hwnd,LB_GETSEL,x,0));
+ }
+ }
+ _w_sW("config_extlist", ext_list);
+ }
+
+ hwnd = FindWindowW(L"WinampAgentMain",NULL);
+ if (IsWindow(hwnd)) SendMessageW(hwnd,WM_USER+1,0,0);
+
+ if (iconsChanged()) SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST|SHCNF_FLUSHNOWAIT,NULL,NULL);
+ }
+ return 0;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_SET_DEF_PROGRAM:
+ {
+ if(IsWin8())
+ {
+ IApplicationAssociationRegistrationUI* pAARUI;
+ HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI,
+ NULL,
+ CLSCTX_INPROC,
+ __uuidof(IApplicationAssociationRegistrationUI),
+ (void**)&pAARUI);
+ BOOL opened = FALSE;
+ if (SUCCEEDED(hr))
+ {
+ hr = pAARUI->LaunchAdvancedAssociationUI(AutoWide(app_name));
+ pAARUI->Release();
+ if (SUCCEEDED(hr)){
+ opened = TRUE;
+ }
+ }
+ if(opened == FALSE)
+ {
+ LPMessageBox(hwndDlg, IDS_DEF_PROG_LOAD_ERROR, IDS_ERROR, MB_OK | MB_ICONWARNING);
+ }
+ }
+ }
+ break;
+ case IDC_CHECK2:
+ {
+ HWND hwnd=FindWindowW(L"WinampAgentMain",NULL);
+ if (IsDlgButtonChecked(hwndDlg,IDC_CHECK2))
+ WritePrivateProfileStringW(L"WinampAgent",L"is_intray",L"1",INI_FILE);
+ else
+ WritePrivateProfileStringW(L"WinampAgent",L"is_intray",L"0",INI_FILE);
+ if (hwnd) SendMessageW(hwnd,WM_USER+1,0,0);
+ }
+ break;
+ case IDC_CHECK1:
+ if (IsDlgButtonChecked(hwndDlg,IDC_CHECK1))
+ {
+ config_agent_add();
+ }
+ else
+ {
+ config_agent_remove();
+ }
+ hideShowAgentItems(hwndDlg);
+ break;
+ case IDC_SELALL:
+ {
+ int top = SendDlgItemMessage(hwndDlg,IDC_FTYPE_LIST,LB_GETCOUNT,0,0),x;
+ for (x = 0; x < top; x ++)
+ {
+ SendDlgItemMessage(hwndDlg,IDC_FTYPE_LIST,LB_SETSEL,1,x);
+ }
+ optchanged |= OPT_EXT;
+ }
+ break;
+ case IDC_SELALL2:
+ case IDC_SELALL3:
+ {
+ HWND h=GetDlgItem(hwndDlg,IDC_FTYPE_LIST);
+ int top = SendMessageW(h,LB_GETCOUNT,0,0), x;
+ for (x = 0; x < top; x ++)
+ {
+ char buf[1024] = {0}, buf2[64] = {0};
+ lstrcpynA(buf,"test.", sizeof(buf)/sizeof(*buf));
+ SendMessageW(h,LB_GETTEXT,x,(LPARAM)(buf+5));
+
+ in_get_extended_fileinfo(buf,"type",buf2,32); // I FUCKING LOVE YOU rOn
+ SendMessageW(h,LB_SETSEL,(!!atoi(buf2)) ^ (!!(LOWORD(wParam) == IDC_SELALL2)),x);
+ }
+ optchanged |= OPT_EXT;
+ }
+ break;
+ case IDC_SELNONE:
+ {
+ int top = SendDlgItemMessage(hwndDlg,IDC_FTYPE_LIST,LB_GETCOUNT,0,0),x;
+ for (x = 0; x < top; x ++)
+ {
+ SendDlgItemMessage(hwndDlg,IDC_FTYPE_LIST,LB_SETSEL,0,x);
+ }
+ optchanged |= OPT_EXT;
+ }
+ break;
+ case IDC_RSTART:
+ config_check_ft_startup=(IsDlgButtonChecked(hwndDlg,IDC_RSTART)?1:0);
+ break;
+
+ // 5.58+ (22/01/2010 - dro)
+ // do this to track if an option has been changed so that elevation, etc
+ // will only be done when it is needed as prior behaviour is to just set
+ // the options again when things haven't been altered which is annoying
+ // when you have a UAC prompt appearing when it really isn't needed
+ case IDC_CD:
+ optchanged ^= OPT_CD;
+ break;
+ case IDC_ADDFILES:
+ optchanged ^= OPT_ENQ;
+ break;
+ case IDC_DIRCONTEXT:
+ optchanged ^= OPT_DIR;
+ break;
+ case IDC_FTYPE_LIST:
+ if(HIWORD(wParam) == LBN_SELCHANGE) optchanged |= OPT_EXT;
+ break;
+ }
+ return 0;
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HICON hIcon;
+ RECT r;
+ BeginPaint(hwndDlg,&ps);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_FILETYPES_ICON),&r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r + 1);
+ hIcon = (HICON)LoadImage(hMainInstance,MAKEINTRESOURCE(geticonid(config_whichicon)),IMAGE_ICON,32,32,LR_SHARED);
+ if (hIcon)
+ {
+ DrawIconEx(ps.hdc,r.left,r.top,hIcon,32,32,0,NULL,DI_NORMAL);
+ }
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_FILETYPES_ICON2),&r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r + 1);
+ hIcon = (HICON)LoadImage(hMainInstance,MAKEINTRESOURCE(geticonid(config_whichicon2)),IMAGE_ICON,32,32,LR_SHARED);
+ if (hIcon)
+ {
+ DrawIconEx(ps.hdc,r.left,r.top,hIcon,32,32,0,NULL,DI_NORMAL);
+ }
+ EndPaint(hwndDlg,&ps);
+ }
+ return 0;
+ case WM_VSCROLL:
+ {
+ HWND swnd = (HWND) lParam;
+ if (swnd == GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL))
+ {
+ RECT r;
+ config_whichicon = (unsigned char) SendMessageW(swnd,TBM_GETPOS,0,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_FILETYPES_ICON),&r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r + 1);
+ InvalidateRect(hwndDlg,&r,TRUE);
+ optchanged |= OPT_ICON;
+ }
+ if (swnd == GetDlgItem(hwndDlg,IDC_FILETYPES_ICONSCROLL2))
+ {
+ RECT r;
+ config_whichicon2 = (unsigned char) SendMessageW(swnd,TBM_GETPOS,0,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_FILETYPES_ICON2),&r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r + 1);
+ InvalidateRect(hwndDlg,&r,TRUE);
+ optchanged |= OPT_ICON;
+ }
+ }
+ return 0;
+ }
+
+ const int controls[] =
+ {
+ IDC_FILETYPES_ICONSCROLL,
+ IDC_FILETYPES_ICONSCROLL2,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ return TRUE;
+
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ return FALSE;
+} // filetypes \ No newline at end of file
diff --git a/Src/Winamp/options_gen.cpp b/Src/Winamp/options_gen.cpp
new file mode 100644
index 00000000..b756c531
--- /dev/null
+++ b/Src/Winamp/options_gen.cpp
@@ -0,0 +1,308 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "resource.h"
+#include "Options.h"
+#include "gen.h"
+#include <vector>
+#include "main.hpp"
+#include "../nu/AutoWide.h"
+
+extern std::vector<winampGeneralPurposePlugin*> gen_plugins;
+// gen tab procedure
+static bool pluginsLoaded;
+INT_PTR CALLBACK GenProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ hi helpinfo[] = {
+ {IDC_GENLIB, IDS_P_GEN_LIB},
+ {IDC_GENCONF, IDS_P_GEN_CONF},
+ };
+
+ DO_HELP();
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ pluginsLoaded = false;
+
+ WIN32_FIND_DATAW d = {0};
+ link_startsubclass(hwndDlg, IDC_PLUGINVERS);
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_GENLIB);
+ if (IsWindow(listWindow))
+ {
+ size_t x;
+ RECT r = {0}, rc = {0};
+ GetWindowRect(listWindow, &r);
+ GetClientRect(listWindow, &r);
+ MapWindowPoints(listWindow, hwndDlg, (LPPOINT)&r, 2);
+ InflateRect(&r, 2, 2);
+ DestroyWindow(listWindow);
+ listWindow = CreateWindowExW(WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, WC_LISTVIEWW, L"",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL |
+ LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER,
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ hwndDlg, (HMENU)IDC_GENLIB, NULL, NULL);
+ SetWindowPos(listWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+ ListView_SetExtendedListViewStyleEx(listWindow, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+ SendMessageW(listWindow, WM_SETFONT, SendMessageW(hwndDlg, WM_GETFONT, 0, 0), FALSE);
+
+ LVCOLUMNW lvc = {0};
+ ListView_InsertColumnW(listWindow, 0, &lvc);
+ ListView_InsertColumnW(listWindow, 1, &lvc);
+
+ for (x = 0; x != gen_plugins.size(); x ++)
+ {
+ // only try to add if the plugin is still there
+ // (as 5.5+ allows for dynamic unloads if supported)
+ if(gen_plugins[x])
+ {
+ wchar_t fn[MAX_PATH] = {0}, buf[512] = {0};
+ GetModuleFileNameW(gen_plugins[x]->hDllInstance, fn, MAX_PATH);
+ PathStripPathW(fn);
+
+ LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, (int)x, 0};
+ lstrcpyn(buf, (gen_plugins[x]->version == GPPHDR_VER_U ? (wchar_t*)gen_plugins[x]->description : AutoWide(gen_plugins[x]->description)), 512);
+ lvi.pszText = buf;
+ lvi.lParam = x;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = fn;
+ ListView_SetItemW(listWindow, &lvi);
+ }
+ }
+
+ wchar_t dirstr[MAX_PATH] = {0};
+ PathCombineW(dirstr, PLUGINDIR, L"GEN_*.DLL");
+ HANDLE h = FindFirstFileW(dirstr, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ PathCombineW(dirstr, PLUGINDIR, d.cFileName);
+ HMODULE b = LoadLibraryExW(dirstr, NULL, LOAD_LIBRARY_AS_DATAFILE);
+ for (x = 0; b && (x != gen_plugins.size()); x ++)
+ {
+ if (gen_plugins[x]->hDllInstance == b)
+ {
+ break;
+ }
+ }
+
+ if (x == gen_plugins.size() || !b)
+ {
+ LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, (int)x, 0};
+ lvi.pszText = d.cFileName;
+ lvi.lParam = -2;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = getStringW(IDS_NOT_LOADED, NULL, 0);
+ ListView_SetItemW(listWindow, &lvi);
+ }
+ FreeLibrary(b);
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+
+ GetClientRect(listWindow, &r);
+ ListView_SetColumnWidth(listWindow, 1, LVSCW_AUTOSIZE);
+ ListView_SetColumnWidth(listWindow, 0, (r.right - r.left) - ListView_GetColumnWidth(listWindow, 1));
+
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, TRUE);
+
+ pluginsLoaded = true;
+ }
+ }
+ else if (uMsg == WM_NOTIFY)
+ {
+ LPNMHDR p = (LPNMHDR)lParam;
+ if (p->idFrom == IDC_GENLIB)
+ {
+ if (p->code == LVN_ITEMCHANGED)
+ {
+ LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+ LVITEM lvi = {LVIF_PARAM, pnmv->iItem};
+ if (ListView_GetItem(p->hwndFrom, &lvi) && (pnmv->uNewState & LVIS_SELECTED))
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GENCONF), (lvi.lParam != -2));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNINST), 1);
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GENCONF), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNINST), 0);
+ }
+ }
+ else if (p->code == NM_DBLCLK)
+ {
+ PostMessageW(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_GENCONF, 0), (LPARAM)GetDlgItem(hwndDlg, IDC_GENCONF));
+ }
+ }
+ else if (p->code == HDN_ITEMCHANGINGW)
+ {
+ if (pluginsLoaded)
+ {
+#ifdef WIN64
+ SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
+#else
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+#endif
+ return TRUE;
+ }
+ }
+ }
+ else if (uMsg == WM_DESTROY)
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_GENLIB);
+ if (IsWindow(listWindow))
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE);
+ }
+ else if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_GENCONF:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_GENCONF)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_GENLIB);
+ LVITEM lvi = {LVIF_PARAM, ListView_GetSelectionMark(listWindow)};
+ if (ListView_GetItem(listWindow, &lvi))
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < (int)gen_plugins.size())
+ {
+ if (!(config_no_visseh&4))
+ {
+ try {
+ gen_plugins[lvi.lParam]->config();
+ }
+ catch(...)
+ {
+ LPMessageBox(hwndDlg, IDS_PLUGINERROR, IDS_ERROR, MB_OK | MB_ICONEXCLAMATION);
+ }
+ }
+ else
+ {
+ gen_plugins[lvi.lParam]->config();
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+
+ case IDC_UNINST:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_UNINST)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_GENLIB);
+ int which_sel = ListView_GetSelectionMark(listWindow);
+ LVITEM lvi = {LVIF_PARAM, which_sel};
+ if (ListView_GetItem(listWindow, &lvi) &&
+ LPMessageBox(hwndDlg, IDS_P_PLUGIN_UNINSTALL,IDS_P_PLUGIN_UNINSTALL_CONFIRM, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < (int)gen_plugins.size())
+ {
+ int ret = GEN_PLUGIN_UNINSTALL_REBOOT;
+ int (*pr)(HINSTANCE hDllInst, HWND hwndDlg, int param);
+
+ if (lvi.lParam != -2)
+ {
+ *(void**)&pr = (void*)GetProcAddress(gen_plugins[lvi.lParam]->hDllInstance, "winampUninstallPlugin");
+ if (pr) ret = pr(gen_plugins[lvi.lParam]->hDllInstance, hwndDlg, 0);
+ }
+
+ if (ret == GEN_PLUGIN_UNINSTALL_REBOOT)
+ {
+ extern void _w_s(char *name, char *data);
+ wchar_t buf[MAX_PATH] = {0};
+ GetModuleFileNameW(gen_plugins[lvi.lParam]->hDllInstance, buf, MAX_PATH);
+ _w_sW("remove_genplug", buf);
+ _w_i("show_prefs", 35);
+ PostMessageW(hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP);
+ }
+ // do dynamic unload if the plugin is able to support it (5.5+)
+ else if (ret == GEN_PLUGIN_UNINSTALL_NOW)
+ {
+ wchar_t buf[MAX_PATH] = {0};
+ GetModuleFileNameW(gen_plugins[lvi.lParam]->hDllInstance, buf, MAX_PATH);
+ gen_plugins[lvi.lParam]->quit();
+ FreeModule(gen_plugins[lvi.lParam]->hDllInstance);
+ gen_plugins[lvi.lParam]=0;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ if (registrar->DeleteItem(buf) != S_OK)
+ {
+ _w_sW("remove_genplug", buf);
+ _w_i("show_prefs", 35);
+ PostMessageW(hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP);
+ }
+ registrar->Release();
+ }
+
+ ListView_DeleteItem(listWindow, which_sel);
+ }
+ }
+ // will cope with not loaded plug-ins so we can still remove them, etc
+ else if (lvi.lParam == -2)
+ {
+ wchar_t buf[1024] = {0}, base[1024] = {0};
+ StringCchCopyW(base, 1024, PLUGINDIR);
+ PathAddBackslashW(base);
+
+ LVITEMW lvi = {LVIF_TEXT, which_sel};
+ lvi.pszText = buf;
+ lvi.cchTextMax = ARRAYSIZE(buf);
+ ListView_GetItemW(listWindow, &lvi);
+
+ wchar_t *p = wcschr(buf, L'.');
+ if (p && *p == L'.')
+ {
+ p += 4;
+ *p = 0;
+ PathRemoveFileSpecW(base);
+ PathAppendW(base, buf);
+ }
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ if (registrar->DeleteItem(base) != S_OK)
+ {
+ _w_sW("remove_genplug", base);
+ _w_i("show_prefs", 35);
+ PostMessageW(hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP);
+ }
+ else
+ ListView_DeleteItem(listWindow, which_sel);
+ registrar->Release();
+ }
+ }
+
+ // resets the focus to the listbox so it'll keep ui response working
+ SetFocus(GetDlgItem(hwndDlg, IDC_GENLIB));
+ }
+ }
+ }
+ return FALSE;
+
+ case IDC_PLUGINVERS:
+ myOpenURLWithFallback(hwndDlg, L"http://www.google.com/search?q=Winamp+General+Plugins", L"http://www.google.com/search?q=Winamp+General+Plugins");
+ break;
+ }
+ }
+ else
+ link_handledraw(hwndDlg, uMsg, wParam, lParam);
+
+ return FALSE;
+} //gen \ No newline at end of file
diff --git a/Src/Winamp/options_general.cpp b/Src/Winamp/options_general.cpp
new file mode 100644
index 00000000..f1ad79e2
--- /dev/null
+++ b/Src/Winamp/options_general.cpp
@@ -0,0 +1,283 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "resource.h"
+#include "options.h"
+#include "winampattributes.h"
+#include "../nu/ns_wc.h"
+
+static wchar_t icon_tmp[MAX_PATH] = {0};
+
+// setup tab procedure
+INT_PTR CALLBACK SetupProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={
+ {IDC_PROXYSTR,IDS_P_SETUP_PROXY},
+ {IDC_NEWVERCHECK,IDS_P_SETUP_VER},
+ {IDC_NEWVERCHECK2,IDS_P_SETUP_VER2},
+ {IDC_COMBO2,IDS_P_SETUP_INTERNET},
+ {IDC_MINST,IDS_P_SETUP_MINST},
+ {IDC_PREFS_PRIORITY_CLASS,IDS_P_SETUP_PRIO},
+ {IDC_SCROLLTITLE,IDS_P_DISP_STITLE},
+ {IDC_SHOWPLEDITPOS,IDS_P_DISP_SPLEDPOS},
+ {IDC_SYSTRAY_SCROLLER,IDS_P_DISP_SYSTRAY},
+ {IDC_CHECK5,IDS_P_DISP_SYSTRAYICON},
+ {IDC_CHECK1,IDS_P_DISP_TASKBAR},
+ {IDC_PREFS_SPLASH,IDS_P_O_SPLASH},
+ {IDC_RECYCLE, IDS_P_O_RECYCLE},
+ {IDC_NO_MOUSEWHEEL, IDS_P_NO_MOUSEWHEEL},
+ };
+ DO_HELP();
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SendMessageW(GetDlgItem(hwndDlg,IDC_PROXYSTR),EM_LIMITTEXT,sizeof(config_proxy),0);
+ /// SetWindowTextA(GetDlgItem(hwndDlg,IDC_PROXYSTR),config_proxy); // PROXY disabled
+ CheckDlgButton(hwndDlg,IDC_MINST,config_minst?1:0);
+
+ SendDlgItemMessageW(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_INST_INET1,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_INST_INET2,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_INST_INET3,NULL,0));
+
+ if (config_inet_mode==3) isInetAvailable(); // autodetect
+
+ if (config_inet_mode==2) SendDlgItemMessage(hwndDlg,IDC_COMBO2, CB_SETCURSEL,2,0);
+ else if (config_inet_mode==1) SendDlgItemMessage(hwndDlg,IDC_COMBO2, CB_SETCURSEL,1,0);
+ else SendDlgItemMessage(hwndDlg,IDC_COMBO2, CB_SETCURSEL,0,0);
+
+ // disable the version and stats aspects as
+ // they are when internet access is disabled
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NEWVERCHECK), (config_inet_mode != 2));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NEWVERCHECK2), (config_inet_mode != 2));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NEWVERCHECK_RC), (config_inet_mode != 2));
+
+ if (config_newverchk)
+ CheckDlgButton(hwndDlg,IDC_NEWVERCHECK,BST_CHECKED);
+ if (config_newverchk2)
+ CheckDlgButton(hwndDlg,IDC_NEWVERCHECK2,BST_CHECKED);
+ if (config_newverchk_rc)
+ CheckDlgButton(hwndDlg, IDC_NEWVERCHECK_RC, BST_CHECKED);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NEWVERCHECK_RC), config_newverchk > 0);
+
+ if (GetPrivateProfileIntW(L"Winamp",L"proxyonly80",0,INI_FILE)) CheckDlgButton(hwndDlg,IDC_PROXY_ONLY_PORT_80,BST_CHECKED);
+
+ CheckDlgButton(hwndDlg,IDC_DROPAOTFS,config_dropaotfs?1:0);
+ CheckDlgButton(hwndDlg,IDC_NO_MOUSEWHEEL,config_nomwheel?1:0);
+
+ SendDlgItemMessage(hwndDlg,IDC_PREFS_PRIORITY_CLASS,TBM_SETRANGEMAX,0,4);
+ SendDlgItemMessage(hwndDlg,IDC_PREFS_PRIORITY_CLASS,TBM_SETRANGEMIN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_PREFS_PRIORITY_CLASS,TBM_SETPOS,1,4-config_priority);
+
+ CheckDlgButton(hwndDlg,IDC_SCROLLTITLE,(config_autoscrollname&2)?1:0);
+ CheckDlgButton(hwndDlg,IDC_SHOWPLEDITPOS,config_dotasknum);
+ CheckDlgButton(hwndDlg,IDC_PREFS_SPLASH,config_splash?1:0);
+
+ if(!icon_tmp[0]) StringCchPrintfW(icon_tmp,MAX_PATH,L"%s\\winamp.ico",CONFIGDIR);
+ int custom_icon = PathFileExistsW(icon_tmp);
+ if(!custom_icon && geticonid(config_sticon) == -666) {
+ config_sticon = 0;
+ }
+ SendDlgItemMessage(hwndDlg,IDC_SYSTRAY_SCROLLER,TBM_SETRANGEMAX,0,12+custom_icon);
+ SendDlgItemMessage(hwndDlg,IDC_SYSTRAY_SCROLLER,TBM_SETRANGEMIN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_SYSTRAY_SCROLLER,TBM_SETPOS,1,config_sticon);
+
+ CheckDlgButton(hwndDlg,IDC_RECYCLE,config_playlist_recyclebin?1:0);
+
+ CheckDlgButton(hwndDlg, IDC_CHECK1, !(config_taskbar & 1));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SCROLLTITLE), !(config_taskbar & 1));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWPLEDITPOS), !(config_taskbar & 1));
+ CheckDlgButton(hwndDlg, IDC_CHECK5, config_taskbar == 1 || config_taskbar == 2);
+ }
+ return 0;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_NEWVERCHECK:
+ case IDC_NEWVERCHECK2:
+ config_newverchk=IsDlgButtonChecked(hwndDlg,IDC_NEWVERCHECK)?(config_newverchk?config_newverchk:1):0;
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NEWVERCHECK_RC), config_newverchk > 0);
+ if (config_newverchk)
+ {
+ config_newverchk_rc = IsDlgButtonChecked(hwndDlg, IDC_NEWVERCHECK_RC) ? (config_newverchk_rc ? config_newverchk_rc : 1) : 0;
+ }
+
+ config_newverchk2=!!IsDlgButtonChecked(hwndDlg,IDC_NEWVERCHECK2);
+ return 0;
+
+ case IDC_COMBO2:
+ if (HIWORD(wParam) == CBN_SELCHANGE)
+ {
+ int l=SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_GETCURSEL,0,0);
+ if (l == 2) config_inet_mode=2;
+ else if (l == 1) config_inet_mode=1;
+ else config_inet_mode=0;
+
+ // disable the version and stats aspects as
+ // they are when internet access is disabled
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NEWVERCHECK), (l != 2));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NEWVERCHECK2), (l != 2));
+ }
+ return 0;
+
+ case IDC_MINST:
+ config_minst = !!IsDlgButtonChecked(hwndDlg,IDC_MINST);
+ return 0;
+
+ case IDC_PROXY_ONLY_PORT_80:
+ config_proxy80 = (IsDlgButtonChecked(hwndDlg,IDC_PROXY_ONLY_PORT_80)==BST_CHECKED);
+ WritePrivateProfileStringW(L"Winamp",L"proxyonly80",config_proxy80?L"1":L"0",INI_FILE);
+ return 0;
+
+ case IDC_RECYCLE:
+ config_playlist_recyclebin = IsDlgButtonChecked(hwndDlg, IDC_RECYCLE)?1:0;
+ break;
+
+ case IDC_PREFS_SPLASH:
+ config_splash = IsDlgButtonChecked(hwndDlg,IDC_PREFS_SPLASH)?1:0;
+ break;
+
+ case IDC_CHECK1:
+ case IDC_CHECK5:
+ if (IsDlgButtonChecked(hwndDlg,IDC_CHECK1)) // taskbar
+ {
+ if (IsDlgButtonChecked(hwndDlg,IDC_CHECK5)) config_taskbar=2;
+ else config_taskbar=0;
+ }
+ else // no taskbar
+ {
+ if (IsDlgButtonChecked(hwndDlg,IDC_CHECK5)) config_taskbar=1;
+ else config_taskbar=3;
+ }
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SCROLLTITLE), !(config_taskbar & 1));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWPLEDITPOS), !(config_taskbar & 1));
+
+ if (IsWindow(hMainWindow) && IsWindowVisible(hMainWindow))
+ {
+ set_taskbar();
+ }
+ else g_taskbar_dirty=1;
+ break;
+ case IDC_SCROLLTITLE:
+ {
+ int t=config_autoscrollname;
+ config_autoscrollname &= ~2;
+ if (IsDlgButtonChecked(hwndDlg,IDC_SCROLLTITLE)) config_autoscrollname |= 2;
+ {
+ if (config_autoscrollname && !t) SetTimer(hMainWindow,UPDATE_DISPLAY_TIMER+1,200,NULL);
+ else if (!config_autoscrollname && t)
+ {
+ KillTimer(hMainWindow,UPDATE_DISPLAY_TIMER+1);
+ }
+ if (!(config_autoscrollname&2))
+ set_caption(0, NULL);
+ }
+ }
+ break;
+
+ case IDC_SHOWPLEDITPOS:
+ config_dotasknum = IsDlgButtonChecked(hwndDlg, IDC_SHOWPLEDITPOS)?1:0;
+ // has cropped up in a few crash reports where app_name is null which causes the update to bork
+ // when receiving a 'stop' command and we try to send an update via JSAPI1_CurrentTitleChanged()
+ if (!app_name || app_name && !*app_name || (unsigned int)(ULONG_PTR)app_name < 65536) BuildAppName();
+ set_caption(0, L"%s - %S", (config_dotasknum?FileTitleNum:FileTitle), app_name);
+ break;
+
+ case IDC_DROPAOTFS:
+ config_dropaotfs = IsDlgButtonChecked(hwndDlg, IDC_DROPAOTFS)?1:0;
+ break;
+
+ case IDC_NO_MOUSEWHEEL:
+ config_nomwheel = IsDlgButtonChecked(hwndDlg, IDC_NO_MOUSEWHEEL)?1:0;
+ break;
+ } // end of WM_COMMAND
+ return 0;
+
+ case WM_VSCROLL:
+ {
+ HWND swnd = (HWND) lParam;
+ if (swnd == GetDlgItem(hwndDlg,IDC_PREFS_PRIORITY_CLASS))
+ {
+ config_priority = 4-(unsigned char)SendMessageW(GetDlgItem(hwndDlg,IDC_PREFS_PRIORITY_CLASS),TBM_GETPOS,0,0);
+ set_priority();
+ }
+ }
+ return 0;
+
+ case WM_DESTROY:
+ GetWindowTextA(GetDlgItem(hwndDlg,IDC_PROXYSTR),config_proxy,sizeof(config_proxy));
+ return 0;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HICON hIcon;
+ RECT r;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_SYSTRAY_ICON),&r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r + 1);
+ BeginPaint(hwndDlg,&ps);
+ int icon_idx = geticonid(config_sticon);
+ if(icon_idx != -666) {
+ hIcon = (HICON)LoadImageW(hMainInstance,MAKEINTRESOURCEW(icon_idx),IMAGE_ICON,16,16,LR_SHARED);
+ }
+ else {
+ if(!PathFileExistsW(icon_tmp)) {
+ hIcon = (HICON)LoadImageW(hMainInstance,MAKEINTRESOURCEW(ICON_XP),IMAGE_ICON,16,16,LR_SHARED);
+ }
+ else {
+ hIcon = (HICON)LoadImageW(0,icon_tmp,IMAGE_ICON,16,16,LR_LOADFROMFILE);
+ }
+ }
+
+ if (hIcon)
+ {
+ DrawIconEx(ps.hdc,r.left+8,r.top+8,hIcon,16,16,0,NULL,DI_NORMAL);
+ }
+ EndPaint(hwndDlg,&ps);
+ }
+ break;
+
+ case WM_HSCROLL:
+ {
+ HWND swnd = (HWND) lParam;
+ if (swnd == GetDlgItem(hwndDlg,IDC_SYSTRAY_SCROLLER))
+ {
+ RECT r;
+ HWND hwnd;
+ config_sticon = (unsigned char) SendMessageW(swnd,TBM_GETPOS,0,0);
+ _w_i("sticon",config_sticon);
+ hwnd=FindWindowW(L"WinampAgentMain",NULL);
+ if (hwnd) SendMessageW(hwnd,WM_USER+1,0,0);
+
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_SYSTRAY_ICON),&r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r);
+ ScreenToClient(hwndDlg,(LPPOINT) &r + 1);
+ InvalidateRect(hwndDlg,&r,TRUE);
+ if (hMainWindow && (config_taskbar == 1 || config_taskbar == 2))
+ {
+ set_taskbar();
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ const int controls[] =
+ {
+ IDC_PREFS_PRIORITY_CLASS,
+ IDC_SYSTRAY_SCROLLER,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ return TRUE;
+
+ return 0;
+} //setup \ No newline at end of file
diff --git a/Src/Winamp/options_in.cpp b/Src/Winamp/options_in.cpp
new file mode 100644
index 00000000..b339d608
--- /dev/null
+++ b/Src/Winamp/options_in.cpp
@@ -0,0 +1,308 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "resource.h"
+#include "Options.h"
+#include "main.hpp"
+#include <vector>
+#include "../nu/AutoWide.h"
+
+extern std::vector<In_Module*> in_modules;
+
+static bool pluginsLoaded;
+INT_PTR CALLBACK InputProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={
+ {IDC_INPUTS,IDS_P_IN_INPUTS},
+ {IDC_CONF,IDS_P_IN_CONF},
+ {IDC_ABOUT,IDS_P_IN_ABOUT},
+ {IDC_UNINSTINPUT,IDS_P_IN_UNINST},
+ };
+
+ DO_HELP();
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ pluginsLoaded = false;
+
+ WIN32_FIND_DATAW d = {0};
+ link_startsubclass(hwndDlg, IDC_PLUGINVERS);
+
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_INPUTS);
+ if (IsWindow(listWindow))
+ {
+ size_t x;
+ RECT r = {0};
+ GetWindowRect(listWindow, &r);
+ GetClientRect(listWindow, &r);
+ MapWindowPoints(listWindow, hwndDlg, (LPPOINT)&r, 2);
+ InflateRect(&r, 2, 2);
+ DestroyWindow(listWindow);
+ listWindow = CreateWindowExW(WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, WC_LISTVIEWW, L"",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL |
+ LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER,
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ hwndDlg, (HMENU)IDC_INPUTS, NULL, NULL);
+ SetWindowPos(listWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+ ListView_SetExtendedListViewStyleEx(listWindow, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+ SendMessageW(listWindow, WM_SETFONT, SendMessageW(hwndDlg, WM_GETFONT, 0, 0), FALSE);
+
+ LVCOLUMNW lvc = {0};
+ ListView_InsertColumnW(listWindow, 0, &lvc);
+ ListView_InsertColumnW(listWindow, 1, &lvc);
+
+ for (x = 0; x < in_modules.size(); x ++)
+ {
+ // only try to add if the plugin is still there
+ // (as 5.5+ allows for dynamic unloads if supported)
+ if(in_modules[x])
+ {
+ wchar_t fn[MAX_PATH] = {0}, buf[512] = {0};
+ GetModuleFileNameW(in_modules[x]->hDllInstance, fn, MAX_PATH);
+ PathStripPathW(fn);
+
+ int ver = ((in_modules[x]->version & ~IN_UNICODE) & ~IN_INIT_RET);
+ LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, (int)x, 0};
+ lstrcpynW(buf, (ver == IN_VER ? (wchar_t*)in_modules[x]->description : AutoWide(in_modules[x]->description)), 512);
+ lvi.pszText = buf;
+ lvi.lParam = x;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = fn;
+ ListView_SetItemW(listWindow, &lvi);
+ }
+ }
+
+ wchar_t dirstr[MAX_PATH] = {0};
+ PathCombineW(dirstr, PLUGINDIR, L"IN_*.DLL");
+ HANDLE h = FindFirstFileW(dirstr, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ PathCombineW(dirstr, PLUGINDIR, d.cFileName);
+ HMODULE b = LoadLibraryExW(dirstr, NULL, LOAD_LIBRARY_AS_DATAFILE);
+ for (x = 0; b && (x != in_modules.size()); x ++)
+ {
+ if (in_modules[x]->hDllInstance == b)
+ {
+ break;
+ }
+ }
+
+ if (x == in_modules.size() || !b)
+ {
+ LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, (int)x, 0};
+ lvi.pszText = d.cFileName;
+ lvi.lParam = -2;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = getStringW(IDS_NOT_LOADED, NULL, 0);
+ ListView_SetItemW(listWindow, &lvi);
+ }
+ FreeLibrary(b);
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+
+ GetClientRect(listWindow, &r);
+ ListView_SetColumnWidth(listWindow, 1, LVSCW_AUTOSIZE);
+ ListView_SetColumnWidth(listWindow, 0, (r.right - r.left) - ListView_GetColumnWidth(listWindow, 1));
+
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, TRUE);
+
+ pluginsLoaded = true;
+ }
+ }
+ else if (uMsg == WM_DESTROY)
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_INPUTS);
+ if (IsWindow(listWindow))
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE);
+ }
+ else if (uMsg == WM_NOTIFY)
+ {
+ LPNMHDR p = (LPNMHDR)lParam;
+ if (p->idFrom == IDC_INPUTS)
+ {
+ if (p->code == LVN_ITEMCHANGED)
+ {
+ LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+ LVITEM lvi = {LVIF_PARAM, pnmv->iItem};
+ if (ListView_GetItem(p->hwndFrom, &lvi) && (pnmv->uNewState & LVIS_SELECTED))
+ {
+ int loaded = (lvi.lParam != -2);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CONF), loaded);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ABOUT), loaded);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTINPUT), 1);
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CONF), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ABOUT), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTINPUT), 0);
+ }
+ }
+ else if (p->code == NM_DBLCLK)
+ {
+ PostMessageW(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_CONF, 0), (LPARAM)GetDlgItem(hwndDlg, IDC_CONF));
+ }
+ }
+ else if (p->code == HDN_ITEMCHANGINGW)
+ {
+ if (pluginsLoaded)
+ {
+#ifdef WIN64
+ SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
+#else
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+#endif
+ return TRUE;
+ }
+ }
+ }
+ else if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_ABOUT:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_ABOUT)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_INPUTS);
+ LVITEM lvi = {LVIF_PARAM, ListView_GetSelectionMark(listWindow)};
+ if (ListView_GetItem(listWindow, &lvi))
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < (int)in_modules.size()) in_modules[lvi.lParam]->About(hwndDlg);
+ }
+ }
+ }
+ break;
+
+ case IDC_CONF:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CONF)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_INPUTS);
+ LVITEM lvi = {LVIF_PARAM, ListView_GetSelectionMark(listWindow)};
+ if (ListView_GetItem(listWindow, &lvi))
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < (int)in_modules.size()) in_modules[lvi.lParam]->Config(hwndDlg);
+ }
+ }
+ }
+ break;
+
+ case IDC_UNINSTINPUT:
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_INPUTS);
+ int which_sel = ListView_GetSelectionMark(listWindow);
+ LVITEM lvi = {LVIF_PARAM, which_sel};
+ if (ListView_GetItem(listWindow, &lvi))
+ {
+ if (LPMessageBox(hwndDlg, IDS_P_PLUGIN_UNINSTALL, IDS_P_PLUGIN_UNINSTALL_CONFIRM, MB_YESNO|MB_ICONEXCLAMATION) == IDYES)
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < (int)in_modules.size())
+ {
+ int ret = IN_PLUGIN_UNINSTALL_REBOOT;
+ int (*pr)(HINSTANCE hDllInst, HWND hwndDlg, int param);
+ *(void**)&pr = (void*)GetProcAddress(in_modules[lvi.lParam]->hDllInstance,"winampUninstallPlugin");
+ if (pr)ret=pr(in_modules[lvi.lParam]->hDllInstance,hwndDlg,0);
+ if (ret == IN_PLUGIN_UNINSTALL_REBOOT)
+ {
+ extern void _w_s(char *name, char *data);
+ char buf[1024] = {0};
+ GetModuleFileNameA(in_modules[lvi.lParam]->hDllInstance,buf,sizeof(buf));
+ _w_s("remove_genplug",buf);
+ _w_i("show_prefs",31);
+ PostMessageW(hMainWindow,WM_USER,0,IPC_RESTARTWINAMP);
+ }
+ // do dynamic unload if the plugin is able to support it (5.5+)
+ else if (ret == IN_PLUGIN_UNINSTALL_NOW)
+ {
+ wchar_t buf[MAX_PATH] = {0};
+ GetModuleFileNameW(in_modules[lvi.lParam]->hDllInstance,buf,MAX_PATH);
+ in_modules[lvi.lParam]->Quit();
+ FreeModule(in_modules[lvi.lParam]->hDllInstance);
+ in_modules[lvi.lParam]=0;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->DeleteItem(buf);
+ if (registrar->DeleteItem(buf) != S_OK)
+ {
+ _w_sW("remove_genplug", buf);
+ _w_i("show_prefs", 31);
+ PostMessageW(hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP);
+ }
+ else
+ ListView_DeleteItem(listWindow, which_sel);
+ registrar->Release();
+ }
+
+ ListView_DeleteItem(listWindow, lvi.lParam);
+ }
+ }
+ // will cope with not loaded plug-ins so we can still remove them, etc
+ else if (lvi.lParam == -2)
+ {
+ wchar_t buf[1024] = {0}, base[1024] = {0};
+ StringCchCopyW(base, 1024, PLUGINDIR);
+ PathAddBackslashW(base);
+
+ LVITEMW lvi = {LVIF_TEXT, which_sel};
+ lvi.pszText = buf;
+ lvi.cchTextMax = ARRAYSIZE(buf);
+ ListView_GetItemW(listWindow, &lvi);
+
+ wchar_t *p = wcschr(buf, L'.');
+ if (p && *p == L'.')
+ {
+ p += 4;
+ *p = 0;
+ PathRemoveFileSpecW(base);
+ PathAppendW(base, buf);
+ }
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ if (registrar->DeleteItem(base) != S_OK)
+ {
+ _w_sW("remove_genplug", base);
+ _w_i("show_prefs", 31);
+ PostMessageW(hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP);
+ }
+ else
+ ListView_DeleteItem(listWindow, which_sel);
+ registrar->Release();
+ }
+ }
+
+ // resets the focus to the listbox so it'll keep ui response working
+ SetFocus(GetDlgItem(hwndDlg,IDC_INPUTS));
+ }
+ }
+ }
+ break;
+
+ case IDC_PLUGINVERS:
+ myOpenURLWithFallback(hwndDlg, L"http://www.google.com/search?q=Winamp+Input+Plugins",L"http://www.google.com/search?q=Winamp+Input+Plugins");
+ break;
+ }
+ }
+
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ return FALSE;
+} //input \ No newline at end of file
diff --git a/Src/Winamp/options_lang.cpp b/Src/Winamp/options_lang.cpp
new file mode 100644
index 00000000..8772e163
--- /dev/null
+++ b/Src/Winamp/options_lang.cpp
@@ -0,0 +1,703 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "language.h"
+#include "resource.h"
+#include "Options.h"
+#include "main.hpp"
+
+static WNDPROC list_oldWndProc;
+static wchar_t rename_lang[MAX_PATH];
+static int cur_lang = LB_ERR;
+
+static BOOL FillEnumRec(ENUMLANG *pel, LPCWSTR pszFileName, BOOL bDirectory, LPWSTR pszName, INT cchName, LPCWSTR pszActiveFile)
+{
+ //if (bDirectory) return FALSE;
+
+ LPCWSTR pExt = 0;
+ if (!bDirectory)
+ {
+ pExt = PathFindExtensionW(pszFileName);
+ if (L'.' != *pExt) return FALSE;
+ pExt++;
+ }
+
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pExt, -1, L"wlz", -1)) pel->nType = LANG_FILETYPE_WLZ;
+ else if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pExt, -1, L"zip", -1)) pel->nType = LANG_FILETYPE_ZIP;
+ else
+ {
+ wchar_t check[MAX_PATH] = {0};
+ PathCombineW(check, LANGDIR, pszFileName);
+ PathCombineW(check, check, L"winamp.lng");
+ if (!PathFileExistsW(check)) return FALSE;
+ pel->nType = LANG_FILETYPE_DIR;
+ }
+
+ if (!bDirectory)
+ {
+ LPCWSTR pszFile = PathFindFileNameW(pszFileName);
+ StringCchCopyNW(pszName, cchName, pszFile, (size_t)(pExt - pszFile - 1));
+ }
+ else
+ StringCchCopyW(pszName, cchName, pszFileName);
+
+ pel->pszFileName = pszFileName;
+ pel->pszName = pszName;
+ pel->bActive = (pszActiveFile && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszActiveFile, -1, pel->pszFileName, -1));
+
+ return TRUE;
+}
+
+int EnumerateLanguages(ENUMLANGPROC fnEnumLang, void *user)
+{
+ if (!fnEnumLang) return FALSE;
+
+ WIN32_FIND_DATAW d = {0};
+ wchar_t dirmask[1024] = {0}, szName[MAX_PATH] = {0}, *pszActive = 0;
+ ENUMLANG el = {0};
+ BOOL bActiveFound = FALSE, bTerminated = FALSE;
+
+ if (*config_langpack)
+ {
+ pszActive = PathFindFileNameW(config_langpack);
+ if (pszActive != config_langpack && BuildFullPath(LANGDIR, config_langpack, szName, sizeof(szName)/sizeof(wchar_t)))
+ {
+ INT cr = ComparePath(szName, pszActive, LANGDIR);
+ if(cr && CSTR_EQUAL != cr && PathFileExistsW(szName))
+ {
+ if (FillEnumRec(&el, config_langpack, FALSE, szName, sizeof(szName)/sizeof(wchar_t), NULL))
+ {
+ el.bActive = TRUE;
+ bActiveFound = TRUE;
+ if (!fnEnumLang(&el, user)) return FALSE;
+ }
+ }
+ }
+ }
+ else pszActive = NULL;
+
+ PathCombineW(dirmask, LANGDIR, L"*");
+ HANDLE h = FindFirstFileW(dirmask, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) continue;
+
+ if (FillEnumRec(&el, d.cFileName, (FILE_ATTRIBUTE_DIRECTORY & d.dwFileAttributes), szName, sizeof(szName)/sizeof(wchar_t), (bActiveFound) ? NULL : pszActive))
+ {
+ if (el.bActive) bActiveFound = TRUE;
+ if (!fnEnumLang(&el, user))
+ {
+ bTerminated = TRUE;
+ break;
+ }
+ }
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+
+ if (!bTerminated)
+ {
+ el.pszFileName = NULL;
+ el.pszName = L"English (US)";
+ el.nType = LANG_FILETYPE_EMBED;
+ el.bActive = !bActiveFound;
+ bTerminated = !fnEnumLang(&el, user);
+ }
+ return !bTerminated;
+}
+
+static int CALLBACK BrowseLangCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ switch (uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ SetWindowTextW(hwnd, getStringW(IDS_P_SELECT_LANGDIR,NULL,0));
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)LANGDIR);
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static void _setreadme(HWND hwndDlg, wchar_t* readme_only_wlz_extraction)
+{
+ if (config_langpack[0] || readme_only_wlz_extraction && readme_only_wlz_extraction[0])
+ {
+ wchar_t s[MAX_PATH] = {0}, *dirpath = (readme_only_wlz_extraction?readme_only_wlz_extraction:lang_directory);
+ FILE *fp = NULL;
+ PathCombineW(s, dirpath, L"readme.txt");
+ fp=_wfopen(s,L"rt");
+ if (!fp)
+ {
+ PathCombineW(s, dirpath, L"read me.txt");
+ fp=_wfopen(s,L"rt");
+ }
+ if (!fp)
+ {
+ WIN32_FIND_DATAW d = {0};
+ PathCombineW(s, dirpath, L"*.txt");
+
+ HANDLE h = FindFirstFileW(s,&d);
+ s[0]=0;
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (NULL != PathCombineW(s, dirpath, d.cFileName))
+ break;
+ } while (FindNextFileW(h,&d));
+
+ FindClose(h);
+ fp=_wfopen(s,L"rt");
+ }
+ }
+
+ if (fp)
+ {
+ SetDialogBoxFromFile(fp, hwndDlg, IDC_EDIT1);
+ fclose(fp);
+ }
+ else
+ SetDlgItemTextW(hwndDlg,IDC_EDIT1,getStringW(IDS_P_SKIN_NO_INFO_FOUND,NULL,0));
+ }
+ else SetDlgItemTextA(hwndDlg,IDC_EDIT1,"\tWinamp Default Language");
+}
+
+static BOOL CALLBACK renameSkinProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextW(hwndDlg,IDC_OLD,rename_lang);
+ SetDlgItemTextW(hwndDlg,IDC_NEW,rename_lang);
+ SetWindowTextW(hwndDlg,getStringW(IDS_RENAME_WLZ, NULL, 0));
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetDlgItemTextW(hwndDlg,IDC_NEW,rename_lang,sizeof(rename_lang)/sizeof(*rename_lang));
+ EndDialog(hwndDlg,!!rename_lang[0]);
+ return 0;
+
+ case IDCANCEL:
+ EndDialog(hwndDlg,0);
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static DWORD WINAPI list_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ if(uMsg == WM_RBUTTONUP)
+ {
+ PostMessageW(GetParent(hwndDlg),WM_USER+0x123,0,0);
+ }
+ return CallWindowProcW(list_oldWndProc,hwndDlg,uMsg,wParam,lParam);
+}
+
+static void LangSwitchDelayText(HWND hwndDlg){
+ if(config_langpack2[0]){
+ wchar_t tmp[MAX_PATH] = {0};
+ StringCchPrintfW(tmp,MAX_PATH,getStringW(IDS_WA_RESTART_FOR_WLZ_NEEDED,NULL,0),
+ (config_langpack2[0]=='<')?L"Winamp Default Language":config_langpack2);
+ SetDlgItemTextW(hwndDlg,IDC_LANG_RESTART_TEXT,tmp);
+ }
+ ShowWindow(GetDlgItem(hwndDlg,IDC_LANG_RESTART_TEXT),config_langpack2[0]?SW_SHOW:SW_HIDE);
+}
+
+void LangSwitchToLangPrompt(HWND hwndDlg, wchar_t* newLang)
+{
+ wchar_t title[64] = {0};
+ // will do an instant switch to the selected language pack
+ if (!(GetAsyncKeyState(VK_SHIFT)&0x8000) && MessageBoxW(hwndDlg,getStringW(IDS_LANGCHANGE,NULL,0),
+ getStringW(IDS_LANGCHANGE_TITLE,title,64),MB_ICONEXCLAMATION|MB_OKCANCEL) == IDOK ||
+ (GetAsyncKeyState(VK_SHIFT)&0x8000))
+ {
+ config_langpack2[0] = 0;
+ lstrcpynW(config_langpack,newLang,MAX_PATH);
+ config_save_langpack_var();
+ _w_i("show_prefs", 25);
+ PostMessageW(hMainWindow,WM_USER,0,IPC_RESTARTWINAMP);
+ }
+ // will switch to the selected language pack on the next restart (as per the options description)
+ // need to indicate which one is pending to be chosen (if there is one) on the dialog
+ // otherwise it might cause confusion with showing one selected when it otherwise shouldn't be
+ else
+ {
+ // fool the exit code to think that we've got a change to save out
+ if(!newLang[0]) newLang[0] = '<';
+ lstrcpynW(config_langpack2,newLang,MAX_PATH);
+ }
+}
+
+static void LangSwitchToLang(HWND hwndDlg, int id)
+{
+ wchar_t buf2[1024] = {0}, buf[1024] = {0}, *o = buf, *p = config_langpack;
+ int ld = (id!=-1?id:SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0));
+ if (ld == LB_ERR) return;
+ int itemdata = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,ld,0);
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,ld,(LPARAM)buf2);
+
+ if (config_langpack[0])
+ {
+ if (_wcsicmp(p, L"winamp.exe"))
+ {
+ while (p && *p != L'.' && *p && o-buf < 512)
+ {
+ wchar_t *t=CharNextW(p);
+ memcpy(o,p,t-p);
+ o+=t-p;
+ p=t;
+ }
+ *o=0;
+ }
+ }
+
+ if (!_wcsicmp(buf,buf2)) return; // no change
+
+ if (buf2[0])
+ {
+ if (itemdata == 2)
+ {
+ StringCbCatW(buf2, sizeof(buf2), L".wlz");
+ }
+ else if (itemdata == 4)
+ {
+ StringCbCatW(buf2, sizeof(buf2), L".zip");
+ }
+ }
+
+ LangSwitchToLangPrompt(hwndDlg, buf2);
+ LangSwitchDelayText(hwndDlg);
+}
+
+static void LangRenameLang(HWND hwndDlg, int id)
+{
+ int x = (id!=-1?id:SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0));
+ int extidx = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,x,0);
+ int is_cur_lp = 0;
+ wchar_t test_lng[MAX_PATH] = {0};
+
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,x,(LPARAM)rename_lang);
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,x,(LPARAM)test_lng);
+
+ switch (extidx)
+ {
+ case 2:
+ {
+ StringCchCatW(test_lng, MAX_PATH, L".wlz");
+ break;
+ }
+ case 4:
+ {
+ StringCchCatW(test_lng, MAX_PATH, L".zip");
+ break;
+ }
+ default: break;
+ }
+
+ // make sure if renaming the current lang pack that it's followed back through
+ if (!_wcsicmp(test_lng,config_langpack))
+ {
+ is_cur_lp = 1;
+ }
+
+ if (rename_lang[0] && _wcsicmp(rename_lang, L"English (US)"))
+ {
+ wchar_t oldlang[MAX_PATH] = {0};
+ lstrcpynW(oldlang, rename_lang, MAX_PATH);
+
+ if (LPDialogBoxW(IDD_RENAMESKIN,hwndDlg,renameSkinProc) && wcscmp(oldlang,rename_lang))
+ {
+ wchar_t oldname[MAX_PATH] = {0}, newname[MAX_PATH] = {0};
+ PathCombineW(oldname, LANGDIR, oldlang);
+ PathCombineW(newname, LANGDIR, rename_lang);
+
+ switch (extidx)
+ {
+ case 2: StringCchCatW(oldname,MAX_PATH, L".wlz"); StringCchCatW(newname,MAX_PATH,L".wlz"); break;
+ case 4: StringCchCatW(oldname,MAX_PATH, L".zip"); StringCchCatW(newname,MAX_PATH,L".zip"); break;
+ default: break;
+ }
+
+ if (MoveFileW(oldname,newname))
+ {
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_DELETESTRING,x,0);
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_INSERTSTRING,x,(LPARAM)rename_lang);
+
+ int par=0;
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETITEMDATA,x,par);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,x,0);
+
+ // only resave if the rename worked
+ if(is_cur_lp)
+ {
+ wchar_t *p = scanstr_backW(newname,L"\\",0)+1;
+ lstrcpynW(config_langpack, p, MAX_PATH);
+ config_save_langpack_var();
+ }
+ }
+ else
+ {
+ wchar_t title[64] = {0};
+ MessageBoxW(hwndDlg,getStringW(IDS_P_LANG_ERR_RENAME,NULL,0),
+ getStringW(IDS_P_LANG_ERR_RENAME_TITLE,title,64),MB_OK);
+ }
+ }
+ }
+}
+
+static void LangDeleteLang(HWND hwndDlg, int id)
+{
+ wchar_t lang[MAX_PATH] = {0};
+ int cur = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0);
+ int x = (id != -1 ? id : cur);
+ if (x == LB_ERR) return;
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,x,(LPARAM)lang);
+
+ switch (SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,x,0))
+ {
+ case 2:
+ {
+ StringCchCatW(lang, MAX_PATH, L".wlz");
+ break;
+ }
+ case 4:
+ {
+ StringCchCatW(lang, MAX_PATH, L".zip");
+ break;
+ }
+ default: break;
+ }
+
+ if (lang[0] && _wcsicmp(lang, L"English (US)"))
+ {
+ wchar_t buf[2048] = {0};
+ StringCchPrintfW(buf, 2048, getStringW(IDS_P_LANG_PACK_DELETEWLZ_PROMPT,NULL,0),lang);
+
+ if (MessageBoxW(hwndDlg,buf,getStringW(IDS_P_LANG_PACK_DELETEWLZ,NULL,0),MB_YESNO|MB_ICONQUESTION) == IDYES)
+ {
+ PathCombineW(buf, LANGDIR, lang);
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->DeleteItem(buf);
+ registrar->Release();
+ }
+
+ if(id == cur_lang)
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,0,0);
+
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_DELETESTRING,x,0);
+
+ if(id == cur_lang)
+ {
+ cur_lang = 0;
+ config_langpack[0]=0;
+ config_save_langpack_var();
+ wchar_t title[64] = {0};
+ if (MessageBoxW(hwndDlg,getStringW(IDS_LANGCHANGE,NULL,0),
+ getStringW(IDS_LANGCHANGE_TITLE,title,64),MB_ICONEXCLAMATION|MB_OKCANCEL) == IDOK)
+ _w_i("show_prefs", 25);
+ PostMessageW(hMainWindow,WM_USER,0,IPC_RESTARTWINAMP);
+ }
+ }
+ }
+}
+
+static BOOL CALLBACK AddLangToListBox(ENUMLANG *pel, void *user)
+{
+ int index = SendMessageW((HWND)user, LB_ADDSTRING, 0, (LPARAM)pel->pszName);
+ if (LB_ERR != index)
+ {
+ SendMessageW((HWND)user, LB_SETITEMDATA, index, (LPARAM)pel->nType);
+ if (pel->bActive) SendMessageW((HWND)user, LB_SETCURSEL, index, 0);
+ }
+ return TRUE;
+}
+
+INT_PTR CALLBACK LangProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={{IDC_SELBOX,IDS_P_SETUP_LANG},
+ {IDC_CHDIR,IDS_P_LNG_CHDR}};
+ DO_HELP();
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ link_startsubclass(hwndDlg, IDC_WINAMPLINK);
+ case WM_USER+50:
+ {
+ HWND hw = GetDlgItem(hwndDlg,IDC_SELBOX);
+ SetDlgItemTextW(hwndDlg,IDC_LANG_ID_STR,langManager->GetLanguageIdentifier(LANG_IDENT_STR));
+
+ if(uMsg == WM_INITDIALOG)
+ {
+ int tabs[] = {150};
+ SendMessageW(hw,LB_SETTABSTOPS,1,(LPARAM)tabs);
+ SetDlgItemTextW(hwndDlg, IDC_CHDIR, LANGDIR);
+ list_oldWndProc=(WNDPROC)SetWindowLongPtrW(hw,GWLP_WNDPROC,(LONG_PTR)list_newWndProc);
+ DirectMouseWheel_EnableConvertToMouseWheel(hw, TRUE);
+ CheckDlgButton(hwndDlg, IDC_SHOW_LNG_PACK, config_wlz_menu);
+ CheckDlgButton(hwndDlg, IDC_LANG_INSTALL_PROMPT, config_wlz_prompt);
+ }
+
+ wchar_t selected[MAX_PATH] = {0};
+
+ SendMessageW(hw,WM_SETREDRAW,FALSE,0);
+
+ EnumerateLanguages(AddLangToListBox, hw);
+ int index = (INT)SendMessageW(hw,LB_GETCURSEL,0,0);
+ if (LB_ERR == index || LB_ERR == SendMessageW(hw, LB_GETTEXT, index, (LPARAM)selected))
+ selected[0] = 0x00;
+
+ index = (INT)SendMessageW(hw, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)L"English (US)");
+ if (LB_ERR != index)
+ {
+ SendMessageW(hw, LB_DELETESTRING, index, 0);
+ SendMessageW(hw, LB_INSERTSTRING, 0, (LPARAM)L"English (US)");
+ }
+
+ index = (*selected) ? (INT)SendMessageW(hw, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)selected) : LB_ERR;
+ if (LB_ERR == index) index = 0;
+ SendMessageW(hw,LB_SETCURSEL, index, 0);
+ cur_lang = index;
+
+ // set buttons to the correct state on init
+ SendMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_SELBOX,LBN_SELCHANGE),
+ (LPARAM)GetDlgItem(hwndDlg,IDC_SELBOX));
+
+ SendMessageW(hw,WM_SETREDRAW,TRUE,0);
+ _setreadme(hwndDlg,0);
+
+ LangSwitchDelayText(hwndDlg);
+ }
+ return FALSE;
+ case WM_DESTROY:
+ {
+ HWND listWindow;
+ listWindow = GetDlgItem(hwndDlg, IDC_SELBOX);
+ if (NULL != listWindow)
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE);
+ }
+ return FALSE;
+
+ case WM_USER+0x123:
+ {
+ HMENU h = GetSubMenu(GetSubMenu(top_menu,5), 1);
+ if (h)
+ {
+ POINT p,ps;
+ GetCursorPos(&p);
+ ps=p;
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_SELBOX),&ps);
+ LRESULT x = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_ITEMFROMPOINT,0,MAKELPARAM(ps.x,ps.y));
+
+ if (HIWORD(x)==0 && (x=LOWORD(x)) >= 0)
+ {
+ wchar_t lang[MAX_PATH] = {0};
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,x,(LPARAM)lang);
+
+ EnableMenuItem(h,0,MF_BYPOSITION|((LOWORD(x)!=cur_lang)?MF_ENABLED:MF_GRAYED));
+ EnableMenuItem(h,2,MF_BYPOSITION|(x ? MF_ENABLED : MF_GRAYED));
+ EnableMenuItem(h,3,MF_BYPOSITION|(x ? MF_ENABLED : MF_GRAYED));
+
+ //int sel=DoTrackPopup(h,TPM_RETURNCMD|TPM_NONOTIFY|TPM_RIGHTBUTTON,p.x,p.y,hwndDlg);
+ int sel=TrackPopupMenu(h,TPM_RETURNCMD|TPM_NONOTIFY|TPM_RIGHTBUTTON,p.x,p.y,0,hwndDlg,NULL);
+ if (sel)
+ {
+ if (sel == ID_LANG_SWITCHTOLANGUAGEPACK)
+ {
+ LangSwitchToLang(hwndDlg,LOWORD(x));
+ }
+ else if (sel == ID_LANG_RENAMELANGUAGEPACK)
+ {
+ LangRenameLang(hwndDlg,LOWORD(x));
+ }
+ else if (sel == ID_LANG_DELETELANGUAGEPACK)
+ {
+ LangDeleteLang(hwndDlg,LOWORD(x));
+ }
+ }
+ }
+ }
+ return 0;
+ }
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_SELECT_LNG_PACK:
+ {
+ SendMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_SELBOX,LBN_DBLCLK),
+ (LPARAM)GetDlgItem(hwndDlg,IDC_SELBOX));
+ break;
+ }
+ case IDC_RENAME_LNG_PACK:
+ {
+ LangRenameLang(hwndDlg,-1);
+ return 0;
+ }
+ case IDC_DELETE_LNG_PACK:
+ {
+ LangDeleteLang(hwndDlg,-1);
+ return 0;
+ }
+ case IDC_LANG_INSTALL_PROMPT:
+ {
+ config_wlz_prompt = !config_wlz_prompt;
+ return 0;
+ }
+ case IDC_SHOW_LNG_PACK:
+ {
+ config_wlz_menu = !config_wlz_menu;
+
+ if (config_wlz_menu)
+ {
+ MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU | MIIM_TYPE | MIIM_ID, MFT_STRING, };
+ mii.hSubMenu = g_submenus_lang = CreatePopupMenu();
+ mii.dwTypeData = getStringW(IDS_LANGUAGEPACKS_MENU, NULL, 0);
+ mii.cch = (UINT)wcslen(mii.dwTypeData);
+ g_submenus_lang_id = mii.wID = unique_loword_command++;
+ InsertMenuItemW(main_menu, MAINMENU_OPTIONS_BASE+4, TRUE, &mii);
+
+ mii.hSubMenu = g_submenus_lang;
+ mii.dwTypeData = getStringW(IDS_LANGUAGEPACKS_MENU, NULL, 0);
+ mii.cch = (UINT)wcslen(mii.dwTypeData);
+ mii.wID = g_submenus_lang_id;
+ InsertMenuItemW(GetSubMenu(v5_top_menu, 2), 1, TRUE, &mii);
+ g_mm_ffoptionsbase_adj++;
+ }
+ else
+ {
+ DeleteMenu(main_menu, g_submenus_lang_id, MF_BYCOMMAND);
+ DeleteMenu(GetSubMenu(v5_top_menu, 2), g_submenus_lang_id, MF_BYCOMMAND);
+
+ g_mm_ffoptionsbase_adj--;
+ g_submenus_lang_id = 0;
+ g_submenus_lang = 0;
+ }
+ break;
+ }
+ case IDC_WINAMPLINK:
+ {
+ myOpenURLWithFallback(hwndDlg, L"http://www.google.com/search?q=%22winamp+language+packs%22+5.9", L"http://forums.winamp.com/showthread.php?t=458120#lang");
+ return 0;
+ }
+ case IDC_CHDIR:
+ {
+ BROWSEINFOW bi = {0};
+ bi.hwndOwner = hwndDlg;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseLangCallbackProc;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist)
+ {
+ wchar_t path[MAX_PATH] = {0};
+ SHGetPathFromIDListW(idlist, path);
+ Shell_Free(idlist);
+
+ if(!PathIsRootW(path))
+ {
+ wchar_t orig[MAX_PATH] = {0};
+ StringCchCopyW(orig, MAX_PATH, LANGDIR);
+ StringCchCopyW(LANGDIR, MAX_PATH, path);
+ _w_sW("LangDir", LANGDIR);
+
+ wchar_t message[2048] = {0};
+ StringCchPrintfW(message,2048,getStringW(IDS_LANG_DIR_MOVE_MESSAGE,NULL,0),orig,LANGDIR);
+ if(MessageBoxW(hwndDlg, message, getStringW(IDS_LANG_DIR_MOVE,NULL,0),MB_YESNO|MB_ICONQUESTION)==IDYES)
+ {
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->MoveDirectoryContents(orig,LANGDIR);
+ registrar->Release();
+ }
+ }
+
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SELBOX),LB_RESETCONTENT,0,0);
+ SetDlgItemTextW(hwndDlg, IDC_CHDIR, LANGDIR);
+ SendMessageW(hwndDlg,WM_USER+50,0,0);
+ }
+ else
+ {
+ wchar_t message[512] = {0};
+ MessageBoxW(hwndDlg, getStringW(IDS_DIR_MOVE_ERROR, message, 512),
+ getStringW(IDS_LANG_DIR_MOVE,NULL,0), MB_OK|MB_ICONEXCLAMATION);
+ }
+ }
+ return FALSE;
+ }
+ case IDC_SELBOX:
+ {
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ {
+ LangSwitchToLang(hwndDlg,-1);
+ }
+
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ int cur = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0);
+ int en = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,cur,0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_RENAME_LNG_PACK),cur);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_DELETE_LNG_PACK),cur);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_SELECT_LNG_PACK),cur!=cur_lang);
+
+ wchar_t test_lng[MAX_PATH] = {0};
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,cur,(LPARAM)test_lng);
+
+ if (en == 2) StringCchCatW(test_lng, MAX_PATH, L".wlz");
+ else if (en == 4) StringCchCatW(test_lng, MAX_PATH, L".zip");
+ PathCombineW(test_lng, LANGDIR, test_lng);
+
+ SetDlgItemTextW(hwndDlg,IDC_LANG_INFO_STR,
+ getStringW((cur!=cur_lang)?IDS_SEL_WLZ_INFO:IDS_CUR_WLZ_INFO,NULL,0));
+ SetDlgItemTextW(hwndDlg,IDC_LANG_ID_STR,(cur!=cur_lang)?L"":langManager->GetLanguageIdentifier(LANG_IDENT_STR));
+
+ // try to pull information about the selected wlz from the current selection
+ if(cur){
+ if(en && cur!=cur_lang){
+ extract_wlz_to_dir(test_lng, 0);
+ _setreadme(hwndDlg,(cur!=cur_lang)?test_lng:0);
+ _cleanupDirW(test_lng);
+ }
+ else
+ _setreadme(hwndDlg,(!en ? test_lng : 0));
+ }
+ else{
+ SetDlgItemTextA(hwndDlg,IDC_EDIT1,"\tWinamp Default Language");
+ }
+ }
+ return FALSE;
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ const int controls[] =
+ {
+ IDC_EDIT1,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ {
+ return TRUE;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/options_output.cpp b/Src/Winamp/options_output.cpp
new file mode 100644
index 00000000..3bf31e50
--- /dev/null
+++ b/Src/Winamp/options_output.cpp
@@ -0,0 +1,328 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "resource.h"
+#include "Options.h"
+#include "../nu/AutoWide.h"
+
+// output tab procedure
+static int last_sel = -1;
+static bool pluginsLoaded;
+INT_PTR CALLBACK OutputProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]=
+ {
+ {IDC_OUTPUTS,IDS_P_OUT_OUTPUTS},
+ {IDC_CONF2,IDS_P_OUT_CONF},
+ {IDC_ABOUT2,IDS_P_OUT_ABOUT},
+ {IDC_UNINSTOUT,IDS_P_OUT_UNINST},
+ };
+
+ DO_HELP();
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ pluginsLoaded = false;
+
+ WIN32_FIND_DATAW d = {0};
+ link_startsubclass(hwndDlg, IDC_PLUGINVERS);
+
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_OUTPUTS);
+ if (IsWindow(listWindow))
+ {
+ size_t x;
+ RECT r = {0};
+ GetWindowRect(listWindow, &r);
+ GetClientRect(listWindow, &r);
+ MapWindowPoints(listWindow, hwndDlg, (LPPOINT)&r, 2);
+ InflateRect(&r, 2, 2);
+ DestroyWindow(listWindow);
+ listWindow = CreateWindowExW(WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, WC_LISTVIEWW, L"",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL |
+ LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER,
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ hwndDlg, (HMENU)IDC_OUTPUTS, NULL, NULL);
+ SetWindowPos(listWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+ ListView_SetExtendedListViewStyleEx(listWindow, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+ SendMessageW(listWindow, WM_SETFONT, SendMessageW(hwndDlg, WM_GETFONT, 0, 0), FALSE);
+
+ LVCOLUMNW lvc = {0};
+ ListView_InsertColumnW(listWindow, 0, &lvc);
+ ListView_InsertColumnW(listWindow, 1, &lvc);
+
+ for (x = 0; out_modules[x]; x ++)
+ {
+ wchar_t fn[MAX_PATH] = {0}, buf[512] = {0};
+ GetModuleFileNameW(out_modules[x]->hDllInstance, fn, MAX_PATH);
+ PathStripPathW(fn);
+
+ LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, (int)x, 0};
+ lstrcpynW(buf, ((out_modules[x]->version == OUT_VER_U) ? (wchar_t*)out_modules[x]->description : AutoWide(out_modules[x]->description)), 512);
+ lvi.pszText = buf;
+ lvi.lParam = x;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = fn;
+ ListView_SetItemW(listWindow, &lvi);
+
+ if (!_stricmp(config_outname, (char*)out_modules[x]->id))
+ {
+ last_sel = lvi.iItem;
+ ListView_SetItemState(listWindow, lvi.iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ }
+ }
+
+ wchar_t dirstr[MAX_PATH] = {0};
+ PathCombineW(dirstr, PLUGINDIR, L"OUT*.DLL");
+ HANDLE h = FindFirstFileW(dirstr, &d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ PathCombineW(dirstr, PLUGINDIR, d.cFileName);
+ HMODULE b = LoadLibraryExW(dirstr, NULL, LOAD_LIBRARY_AS_DATAFILE);
+ bool found = false;
+ for (x = 0; b && out_modules[x]; x ++)
+ {
+ if (out_modules[x]->hDllInstance == b)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, (int)x, 0};
+ lvi.pszText = d.cFileName;
+ lvi.lParam = -2;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = getStringW(IDS_NOT_LOADED, NULL, 0);
+ ListView_SetItemW(listWindow, &lvi);
+ }
+ FreeLibrary(b);
+ }
+ while (FindNextFileW(h, &d));
+ FindClose(h);
+ }
+
+ GetClientRect(listWindow, &r);
+ ListView_SetColumnWidth(listWindow, 1, LVSCW_AUTOSIZE);
+ ListView_SetColumnWidth(listWindow, 0, (r.right - r.left) - ListView_GetColumnWidth(listWindow, 1));
+
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, TRUE);
+
+ pluginsLoaded = true;
+ }
+ }
+ else if (uMsg == WM_DESTROY)
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_OUTPUTS);
+ if (IsWindow(listWindow))
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE);
+ }
+ else if (uMsg == WM_NOTIFY)
+ {
+ LPNMHDR p = (LPNMHDR)lParam;
+ if (p->idFrom == IDC_OUTPUTS)
+ {
+ if (p->code == LVN_ITEMCHANGED)
+ {
+ LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+ LVITEM lvi = {LVIF_PARAM, pnmv->iItem};
+ if (ListView_GetItem(p->hwndFrom, &lvi) && (pnmv->uNewState & LVIS_SELECTED))
+ {
+ int loaded = (lvi.lParam != -2);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CONF2), loaded);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ABOUT2), loaded);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTOUT), 1);
+
+ if (loaded && out_modules[lvi.lParam])
+ {
+ StringCbCopyA(config_outname, sizeof(config_outname), (char *)out_modules[lvi.lParam]->id);
+ if (last_sel != -1 && out_modules[last_sel]) out_changed(out_modules[last_sel]->hDllInstance, OUT_UNSET);
+ out_changed(out_modules[lvi.lParam]->hDllInstance, OUT_SET);
+ PostMessageW(hMainWindow, WM_WA_IPC, (WPARAM)config_outname, IPC_CB_OUTPUTCHANGED);
+ }
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CONF2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ABOUT2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTOUT), 0);
+ }
+ }
+ else if (p->code == NM_DBLCLK || p->code == NM_CLICK)
+ {
+ if (p->code == NM_DBLCLK)
+ {
+ PostMessageW(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_CONF2, 0), (LPARAM)GetDlgItem(hwndDlg, IDC_CONF2));
+ }
+
+ // helps to keep the selection on things...
+ LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
+ if (lpnmitem->iItem == -1)
+ {
+ ListView_SetItemState(p->hwndFrom, ListView_GetSelectionMark(p->hwndFrom), LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ }
+ }
+ }
+ else if (p->code == HDN_ITEMCHANGINGW)
+ {
+ if (pluginsLoaded)
+ {
+#ifdef WIN64
+ SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
+#else
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+#endif
+ return TRUE;
+ }
+ }
+ }
+ else if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_ABOUT2:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_ABOUT2)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_OUTPUTS);
+ LVITEM lvi = {LVIF_PARAM, ListView_GetSelectionMark(listWindow)};
+ if (ListView_GetItem(listWindow, &lvi))
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < 32 && out_modules[lvi.lParam]) out_modules[lvi.lParam]->About(hwndDlg);
+ }
+ }
+ }
+ return FALSE;
+
+ case IDC_CONF2:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CONF2)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_OUTPUTS);
+ LVITEM lvi = {LVIF_PARAM, ListView_GetSelectionMark(listWindow)};
+ if (ListView_GetItem(listWindow, &lvi))
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < 32 && out_modules[lvi.lParam]) out_modules[lvi.lParam]->Config(hwndDlg);
+ }
+ }
+ }
+ return FALSE;
+
+ case IDC_UNINSTOUT:
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_OUTPUTS);
+ int which_sel = ListView_GetSelectionMark(listWindow);
+ LVITEM lvi = {LVIF_PARAM, which_sel};
+ if (ListView_GetItem(listWindow, &lvi))
+ {
+ if (LPMessageBox(hwndDlg, IDS_P_PLUGIN_UNINSTALL,IDS_P_PLUGIN_UNINSTALL_CONFIRM,MB_YESNO|MB_ICONEXCLAMATION) == IDYES)
+ {
+ if (lvi.lParam >= 0 && lvi.lParam < 32 && out_modules[lvi.lParam])
+ {
+ int ret=0;
+ int (*pr)(HINSTANCE hDllInst, HWND hwndDlg, int param);
+
+ *(void**)&pr = (void*)GetProcAddress(out_modules[lvi.lParam]->hDllInstance,"winampUninstallPlugin");
+ // changed 28/11/2010 so that even if non-zero is returned then the plug-in will uninstall
+ if (pr)/*ret=*/pr(out_modules[lvi.lParam]->hDllInstance,hwndDlg,0);
+ if (!ret)
+ {
+ char buf[1024] = {0};
+ int w=-1;
+ char *p=buf;
+ int y;
+ GetModuleFileNameA(out_modules[lvi.lParam]->hDllInstance,buf,sizeof(buf));
+ _w_s("remove_genplug",buf);
+ _w_i("show_prefs",32);
+
+ buf[0]=0;
+
+ for (y = 0; out_modules[y]; y ++)
+ {
+ if (lvi.lParam != y)
+ {
+ GetModuleFileNameA(out_modules[y]->hDllInstance,buf,sizeof(buf));
+ p = PathFindFileNameA(buf);
+
+ if (!_stricmp(p,"out_wave.dll") && w < 1) w=1;
+ if (!_stricmp(p,"out_ds.dll") && w < 0) w=0;
+
+ if (w>0) break;
+ }
+ }
+
+ if (w==1) StringCbCopyA(config_outname, sizeof(config_outname), "out_wave.dll");
+ else if (w==0) StringCbCopyA(config_outname,sizeof(config_outname), "out_ds.dll");
+ else StringCbCopyA(config_outname,sizeof(config_outname),p);
+ PostMessageW(hMainWindow,WM_USER,0,IPC_RESTARTWINAMP);
+ }
+ }
+ // will cope with not loaded plug-ins so we can still remove them, etc
+ else if (lvi.lParam == -2)
+ {
+ wchar_t buf[1024] = {0}, base[1024] = {0};
+ StringCchCopyW(base, 1024, PLUGINDIR);
+ PathAddBackslashW(base);
+
+ LVITEMW lvi = {LVIF_TEXT, which_sel};
+ lvi.pszText = buf;
+ lvi.cchTextMax = ARRAYSIZE(buf);
+ ListView_GetItemW(listWindow, &lvi);
+
+ wchar_t *p = wcschr(buf, L'.');
+ if (p && *p == L'.')
+ {
+ p += 4;
+ *p = 0;
+ PathRemoveFileSpecW(base);
+ PathAppendW(base, buf);
+ }
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ if (registrar->DeleteItem(base) != S_OK)
+ {
+ _w_sW("remove_genplug", base);
+ _w_i("show_prefs", 32);
+ PostMessageW(hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP);
+ }
+ else
+ ListView_DeleteItem(listWindow, which_sel);
+ registrar->Release();
+ }
+ }
+
+ // resets the focus to the listbox so it'll keep ui response working
+ SetFocus(GetDlgItem(hwndDlg,IDC_INPUTS));
+ }
+ }
+ }
+ break;
+
+ case IDC_PLUGINVERS:
+ myOpenURLWithFallback(hwndDlg,L"http://www.google.com/search?q=Winamp+Output+Plugins", L"http://www.google.com/search?q=Winamp+Output+Plugins");
+ break;
+ }
+ }
+ else
+ {
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ }
+
+ return FALSE;
+} //output \ No newline at end of file
diff --git a/Src/Winamp/options_playback.cpp b/Src/Winamp/options_playback.cpp
new file mode 100644
index 00000000..35e6c7c1
--- /dev/null
+++ b/Src/Winamp/options_playback.cpp
@@ -0,0 +1,325 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "Main.h"
+#include "resource.h"
+#include "options.h"
+#include "WinampAttributes.h"
+#include "../Plugins/General/gen_ml/ml.h"
+
+static void EnableDisableReplayGain(HWND hwndDlg)
+{
+ BOOL enabled = IsDlgButtonChecked(hwndDlg, IDC_USE_REPLAY);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC_SOURCE), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC_MODE), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REPLAY_SOURCE), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REPLAY_MODE), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REPLAY_PREFERRED), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NON_REPLAYGAIN), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NON_REPLAYGAIN_DB), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC_ADJ), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REPLAYGAIN_PREAMP), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REPLAYGAIN_PREAMP_DB), enabled);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REPLAY_ADJ), enabled);
+}
+
+static DWORD ml_rg_config_ipc;
+static DLGPROC ml_rg_config_dlg;
+
+static void EnableReplayGainAnalyzer(HWND hwndDlg)
+{
+ pluginMessage message_build = {(int)ml_rg_config_ipc,0,0};
+
+ BOOL enabled = sendMlIpc(ML_IPC_SEND_PLUGIN_MESSAGE,(WPARAM)&message_build);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RGAS), enabled);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RG_ASK), enabled);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RG_ALBUM), enabled);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RG_ALL), enabled);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RGC), enabled);
+
+ message_build.param1 = 1;
+ ml_rg_config_dlg = (DLGPROC)sendMlIpc(ML_IPC_SEND_PLUGIN_MESSAGE,(WPARAM)&message_build);
+}
+
+#define NON_RG_MIN_DB 14
+#define NON_RG_MAX_DB 6
+#define NON_RG_SCALE 10
+
+#define HAS_RG_MIN_DB 14
+#define HAS_RG_MAX_DB 6
+#define HAS_RG_SCALE 10
+
+static HWND subWnd;
+
+static LRESULT CALLBACK PlaybackUIProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ if (uMsg == WM_INITDIALOG)
+ {
+ SendMessageW(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETRANGEMAX, 0, THREAD_PRIORITY_HIGHEST-THREAD_PRIORITY_LOWEST);
+ SendMessageW(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETRANGEMIN, 0, 0);
+ SendMessageW(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETPOS, 1, config_playback_thread_priority-THREAD_PRIORITY_LOWEST);
+
+ CheckDlgButton(hwndDlg,IDC_MONO,config_audio_mono);
+ CheckDlgButton(hwndDlg,IDC_SURROUND,config_audio_surround);
+ CheckDlgButton(hwndDlg,IDC_DITHER,config_audio_dither);
+ CheckDlgButton(hwndDlg,IDC_24BIT,config_audio_bits==24);
+ }
+ if (uMsg == WM_HSCROLL)
+ {
+ HWND swnd = (HWND) lParam;
+ if (swnd == GetDlgItem(hwndDlg,IDC_PRIORITY))
+ {
+ config_playback_thread_priority = (INT_PTR)SendMessageW(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_GETPOS, 0, 0)+THREAD_PRIORITY_LOWEST;
+ }
+ }
+
+ if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_MONO: config_audio_mono = IsDlgButtonChecked(hwndDlg,IDC_MONO)?true:false; break;
+ case IDC_SURROUND: config_audio_surround = IsDlgButtonChecked(hwndDlg,IDC_SURROUND)?true:false; break;
+ case IDC_DITHER: config_audio_dither = IsDlgButtonChecked(hwndDlg,IDC_DITHER)?true:false; break;
+ case IDC_24BIT:
+ {
+ BOOL allow24 = IsDlgButtonChecked(hwndDlg,IDC_24BIT);
+ wchar_t title[64] = {0};
+ getStringW(IDS_P_24BIT_WARNING_TITLE,title,64);
+ if (allow24 && MessageBoxW(hwndDlg, getStringW(IDS_P_24BIT_WARNING,NULL,0), title, MB_YESNO | MB_DEFBUTTON2) == IDNO)
+ {
+ allow24 = FALSE;
+ CheckDlgButton(hwndDlg,IDC_24BIT, BST_UNCHECKED);
+ }
+ config_audio_bits = allow24?24:16;
+ }
+ break;
+ }
+ }
+
+ const int controls[] =
+ {
+ IDC_PRIORITY,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ return TRUE;
+
+ return FALSE;
+}
+
+int first_eq_type = -1, prev_eq_type = EQ_TYPE_4FRONT;
+static LRESULT CALLBACK EqualizerUIProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ if (uMsg == WM_INITDIALOG)
+ {
+ if(first_eq_type != -1 && first_eq_type != config_eq_type)
+ {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_EQ_RESTART_TEXT),SW_SHOW);
+ }
+ else if(first_eq_type == -1)
+ {
+ first_eq_type = config_eq_type;
+ }
+
+ prev_eq_type = config_eq_type;
+ SendDlgItemMessageW(hwndDlg,IDC_EQ,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_4FRONT_EQ,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_EQ,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_CONSTANT_Q,NULL,0));
+ SendDlgItemMessage(hwndDlg,IDC_EQ,CB_SETCURSEL,(config_eq_type==EQ_TYPE_CONSTANT_Q),0);
+
+ wchar_t *name = 0;
+ int width = 0;
+ SendDlgItemMessageW(hwndDlg,IDC_FREQ_BANDS,CB_ADDSTRING,0,(LPARAM)(name = getStringW(IDS_P_WA_FREQ_BANDS,NULL,0)));
+ width = ResizeComboBoxDropDownW(hwndDlg, IDC_FREQ_BANDS, name, width);
+ SendDlgItemMessageW(hwndDlg,IDC_FREQ_BANDS,CB_ADDSTRING,0,(LPARAM)(name = getStringW(IDS_P_ISO_FREQ_BANDS,NULL,0)));
+ ResizeComboBoxDropDownW(hwndDlg, IDC_FREQ_BANDS, name, width);
+ SendDlgItemMessage(hwndDlg,IDC_FREQ_BANDS,CB_SETCURSEL,(config_eq_frequencies==EQ_FREQUENCIES_ISO),0);
+
+ CheckDlgButton(hwndDlg,IDC_LIMITER,config_eq_limiter);
+ }
+
+ else if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_EQ:
+ config_eq_type=SendDlgItemMessage(hwndDlg,IDC_EQ,CB_GETCURSEL,0,0);
+ break;
+
+ case IDC_FREQ_BANDS:
+ config_eq_frequencies=SendDlgItemMessage(hwndDlg,IDC_FREQ_BANDS,CB_GETCURSEL,0,0);
+ set_aot(0);
+ draw_eq_init();
+ eq_set(config_use_eq, (char*)eq_tab, config_preamp);
+ PostMessageW(hMainWindow,WM_WA_IPC,IPC_CB_MISC_EQ,IPC_CB_MISC);
+ InvalidateRect(hEQWindow, NULL, TRUE);
+ break;
+
+ case IDC_LIMITER:
+ config_eq_limiter = IsDlgButtonChecked(hwndDlg,IDC_LIMITER)?true:false;
+ break;
+ }
+ }
+
+ else if (uMsg == WM_DESTROY)
+ {
+ if(config_eq_type != prev_eq_type)
+ {
+ if((first_eq_type != config_eq_type) &&
+ LPMessageBox(hwndDlg,IDS_P_EQ_TYPE_CHANGE_MSG,IDS_P_EQ_TYPE_CHANGE,MB_YESNO|MB_ICONQUESTION) == IDYES)
+ {
+ _w_i("show_prefs", 42);
+ PostMessageW(hMainWindow,WM_USER,0,IPC_RESTARTWINAMP);
+ }
+ }
+ }
+ return FALSE;
+}
+
+static LRESULT CALLBACK ReplayGainUIProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ if (uMsg == WM_INITDIALOG)
+ {
+ SendDlgItemMessageW(hwndDlg,IDC_REPLAY_SOURCE,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_PLAYBACK_RG_SOURCE_TRACK,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_REPLAY_SOURCE,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_PLAYBACK_RG_SOURCE_ALBUM,NULL,0));
+ SendDlgItemMessage(hwndDlg,IDC_REPLAY_SOURCE, CB_SETCURSEL, config_replaygain_source,0);
+
+ SendDlgItemMessageW(hwndDlg,IDC_REPLAY_MODE,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_PLAYBACK_RG_MODE_AG,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_REPLAY_MODE,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_PLAYBACK_RG_MODE_AG_PC,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_REPLAY_MODE,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_PLAYBACK_RG_MODE_N,NULL,0));
+ SendDlgItemMessageW(hwndDlg,IDC_REPLAY_MODE,CB_ADDSTRING,0,(LPARAM)getStringW(IDS_P_PLAYBACK_RG_MODE_PC,NULL,0));
+
+ SendDlgItemMessage(hwndDlg,IDC_REPLAY_MODE, CB_SETCURSEL, config_replaygain_mode,0);
+
+ CheckDlgButton(hwndDlg,IDC_REPLAY_PREFERRED,config_replaygain_preferred_only);
+
+ CheckDlgButton(hwndDlg,IDC_USE_REPLAY, config_replaygain);
+
+ SendMessageW(GetDlgItem(hwndDlg,IDC_NON_REPLAYGAIN),TBM_SETRANGEMAX,0,(NON_RG_MIN_DB+NON_RG_MAX_DB)*NON_RG_SCALE);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_NON_REPLAYGAIN),TBM_SETRANGEMIN,0,0);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_NON_REPLAYGAIN),TBM_SETPOS,1,(LPARAM)((NON_RG_MIN_DB*NON_RG_SCALE)+config_replaygain_non_rg_gain.GetFloat()*(float)NON_RG_SCALE));
+
+ SendMessageW(GetDlgItem(hwndDlg,IDC_REPLAYGAIN_PREAMP),TBM_SETRANGEMAX,0,(HAS_RG_MIN_DB+HAS_RG_MAX_DB)*HAS_RG_SCALE);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_REPLAYGAIN_PREAMP),TBM_SETRANGEMIN,0,0);
+ SendMessageW(GetDlgItem(hwndDlg,IDC_REPLAYGAIN_PREAMP),TBM_SETPOS,1,(LPARAM)((HAS_RG_MIN_DB*HAS_RG_SCALE)+config_replaygain_preamp.GetFloat()*(float)HAS_RG_SCALE));
+
+ wchar_t dummy[64] = {0};
+ StringCchPrintfW(dummy, 64, L"%+6.1f %s", config_replaygain_non_rg_gain.GetFloat(), getStringW(IDS_EQ_DB,NULL,0));
+ SetDlgItemTextW(hwndDlg, IDC_NON_REPLAYGAIN_DB, dummy);
+
+ StringCchPrintfW(dummy, 64, L"%+6.1f %s", config_replaygain_preamp.GetFloat(), getStringW(IDS_EQ_DB,NULL,0));
+ SetDlgItemTextW(hwndDlg, IDC_REPLAYGAIN_PREAMP_DB, dummy);
+
+ EnableDisableReplayGain(hwndDlg);
+
+ EnableReplayGainAnalyzer(hwndDlg);
+ }
+
+ if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_USE_REPLAY:
+ config_replaygain = IsDlgButtonChecked(hwndDlg,IDC_USE_REPLAY)?true:false;
+ EnableDisableReplayGain(hwndDlg); break;
+ case IDC_REPLAY_SOURCE:
+ config_replaygain_source=SendDlgItemMessage(hwndDlg,IDC_REPLAY_SOURCE,CB_GETCURSEL,0,0);
+ break;
+ case IDC_REPLAY_MODE:
+ config_replaygain_mode=SendDlgItemMessage(hwndDlg,IDC_REPLAY_MODE,CB_GETCURSEL,0,0);
+ break;
+ case IDC_REPLAY_PREFERRED:
+ config_replaygain_preferred_only = IsDlgButtonChecked(hwndDlg,IDC_REPLAY_PREFERRED)?true:false;
+ break;
+ }
+ }
+
+ if (uMsg == WM_HSCROLL)
+ {
+ HWND swnd = (HWND) lParam;
+ if (swnd == GetDlgItem(hwndDlg,IDC_NON_REPLAYGAIN))
+ {
+ config_replaygain_non_rg_gain = (float)((int)SendMessageW(GetDlgItem(hwndDlg,IDC_NON_REPLAYGAIN),TBM_GETPOS,0,0)-NON_RG_MIN_DB*NON_RG_SCALE) / (float)NON_RG_SCALE;
+ wchar_t dummy[64] = {0};
+ StringCchPrintfW(dummy, 64, L"%+6.1f %s", config_replaygain_non_rg_gain.GetFloat(), getStringW(IDS_EQ_DB,NULL,0));
+ SetDlgItemTextW(hwndDlg, IDC_NON_REPLAYGAIN_DB, dummy);
+ }
+ else if (swnd == GetDlgItem(hwndDlg,IDC_REPLAYGAIN_PREAMP))
+ {
+ config_replaygain_preamp = (float)((int)SendMessageW(GetDlgItem(hwndDlg,IDC_REPLAYGAIN_PREAMP),TBM_GETPOS,0,0)-HAS_RG_MIN_DB*HAS_RG_SCALE) / (float)HAS_RG_SCALE;
+ wchar_t dummy[64] = {0};
+ StringCchPrintfW(dummy, 64, L"%+6.1f %s", config_replaygain_preamp.GetFloat(), getStringW(IDS_EQ_DB,NULL,0));
+ SetDlgItemTextW(hwndDlg, IDC_REPLAYGAIN_PREAMP_DB, dummy);
+ }
+ }
+
+ // call the ml_rg config dialog (if we've got a dlgproc for the embedded options)
+ if(ml_rg_config_dlg) ml_rg_config_dlg(hwndDlg,uMsg,wParam,lParam);
+
+ const int controls[] =
+ {
+ IDC_NON_REPLAYGAIN,
+ IDC_REPLAYGAIN_PREAMP,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ return TRUE;
+
+ return FALSE;
+}
+
+multiPage playbackPages[] = {
+ {IDD_PLAYBACK, PlaybackUIProc},
+ {IDD_EQUALIZER_UI, EqualizerUIProc},
+ {IDD_REPLAY_GAIN_UI, ReplayGainUIProc},
+ //{IDD_SILENCE_DETECT, 0},
+};
+
+#define TabCtrl_InsertItemW(hwnd, iItem, pitem) \
+ (int)SNDMSG((hwnd), TCM_INSERTITEMW, (WPARAM)(int)(iItem), (LPARAM)(const TC_ITEMW *)(pitem))
+
+INT_PTR CALLBACK PlaybackProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ TCITEMW item = {0};
+ HWND tabwnd=GetDlgItem(hwndDlg,IDC_TAB1);
+ item.mask=TCIF_TEXT;
+ item.pszText=getStringW(IDS_PREFS_PLAYBACK,NULL,0);
+ TabCtrl_InsertItemW(tabwnd,0,&item);
+ item.pszText=getStringW(IDS_P_EQUALIZER,NULL,0);
+ TabCtrl_InsertItemW(tabwnd,1,&item);
+ item.pszText=getStringW(IDS_P_REPLAY_GAIN,NULL,0);
+ TabCtrl_InsertItemW(tabwnd,2,&item);
+ #if 0
+ item.pszText=getStringW(IDS_P_SILENCE_DETECT,NULL,0);
+ TabCtrl_InsertItemW(tabwnd,3,&item);
+ #endif
+
+ ml_rg_config_ipc = wa_register_ipc((WPARAM)&"ml_rg_config");
+ pluginMessage message_build = {(int)ml_rg_config_ipc,2,0};
+ BOOL select_rg_page = sendMlIpc(ML_IPC_SEND_PLUGIN_MESSAGE,(WPARAM)&message_build);
+ if(select_rg_page) config_last_playback_page = 2;
+
+ TabCtrl_SetCurSel(tabwnd,config_last_playback_page);
+ subWnd = _dosetsel(hwndDlg,subWnd,&config_last_playback_page,playbackPages,sizeof(playbackPages)/sizeof(playbackPages[0]));
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR p=(LPNMHDR) lParam;
+ if (p->idFrom == IDC_TAB1 && p->code == TCN_SELCHANGE)
+ subWnd = _dosetsel(hwndDlg,subWnd,&config_last_playback_page,playbackPages,sizeof(playbackPages)/sizeof(playbackPages[0]));
+ }
+ break;
+
+ case WM_DESTROY:
+ subWnd=NULL;
+ break;
+ }
+ return 0;
+} // playback \ No newline at end of file
diff --git a/Src/Winamp/options_playlist.cpp b/Src/Winamp/options_playlist.cpp
new file mode 100644
index 00000000..1e03a5db
--- /dev/null
+++ b/Src/Winamp/options_playlist.cpp
@@ -0,0 +1,268 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include <windowsx.h>
+
+#include "Main.h"
+#include "resource.h"
+#include "Options.h"
+#include "SkinCOM.h"
+#include "ExternalCOM.h"
+#include "../nu/combobox.h"
+#include "../nu/ns_wc.h"
+#include <malloc.h>
+
+static int CALLBACK EnumFontsProc( LOGFONT *lplf, TEXTMETRIC *lptm, DWORD dwType, LPARAM lpData )
+{
+ ComboBox_AddString( (HWND)lpData, lplf->lfFaceName );
+ return TRUE;
+}
+
+
+void UpdatePlaylistFontSizeText( void )
+{
+ HWND plpref = GetDlgItem( prefs_hwnd, IDC_RECT );
+ plpref = GetWindow( plpref, GW_HWNDNEXT );
+ if ( IsWindow( plpref ) )
+ SetDlgItemInt( plpref, IDC_PLFONTSIZE, config_pe_fontsize, 0 );
+}
+
+void UpdateManualAdvanceState( void )
+{
+ HWND plpref = GetDlgItem( prefs_hwnd, IDC_RECT );
+ plpref = GetWindow( plpref, GW_HWNDNEXT );
+ if ( IsWindow( plpref ) )
+ CheckDlgButton( plpref, IDC_MANUALPLAYLISTADVANCE, config_pladv ? 0 : 1 );
+}
+
+// shuffle tab procedure
+INT_PTR CALLBACK PlaybackOptionsProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ static int pl_prefs_init;
+ hi helpinfo[] = {
+ {IDC_PREFS_SHUFFLE_MORPH_RATE,IDS_P_O_SMS},
+ {IDC_DEFEXT,IDS_P_O_DEFEXT},
+ {IDC_RFL,IDS_P_O_RFL},
+
+ {IDC_MANUALPLAYLISTADVANCE,IDS_P_O_MPA},
+ {IDC_PLNUMS,IDS_P_DISP_TNUMS},
+ {IDC_PLFONTSIZE,IDS_P_DISP_PLFONT},
+ };
+
+ DO_HELP();
+
+ if ( uMsg == WM_INITDIALOG )
+ {
+ pl_prefs_init = 0;
+ SetDlgItemTextA( hwndDlg, IDC_DEFEXT, config_defext );
+ SendDlgItemMessage( hwndDlg, IDC_DEFEXT, EM_LIMITTEXT, sizeof( config_defext ), 0 );
+
+ CheckDlgButton( hwndDlg, IDC_RFL, ( config_rofiob & 1 ) ? 1 : 0 );
+ CheckDlgButton( hwndDlg, IDC_MANUALPLAYLISTADVANCE, config_pladv ? 0 : 1 );
+ SendMessageW( GetDlgItem( hwndDlg, IDC_PREFS_SHUFFLE_MORPH_RATE ), TBM_SETRANGEMAX, 0, 50 );
+ SendMessageW( GetDlgItem( hwndDlg, IDC_PREFS_SHUFFLE_MORPH_RATE ), TBM_SETRANGEMIN, 0, 0 );
+ SendMessageW( GetDlgItem( hwndDlg, IDC_PREFS_SHUFFLE_MORPH_RATE ), TBM_SETPOS, 1, config_shuffle_morph_rate );
+ CheckDlgButton( hwndDlg, IDC_PLNUMS, config_shownumsinpl ? 1 : 0 );
+ CheckDlgButton( hwndDlg, IDC_PLZEROPAD, config_zeropadplnum ? 1 : 0 );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PLZEROPAD ), config_shownumsinpl );
+
+ SendDlgItemMessage( hwndDlg, IDC_SPIN1, UDM_SETRANGE, 0, MAKELONG( 999, 1 ) );
+ SetDlgItemInt( hwndDlg, IDC_PLFONTSIZE, config_pe_fontsize, 0 );
+
+ SendDlgItemMessageW( hwndDlg, IDC_PLDIRECTION, CB_ADDSTRING, 0, (LPARAM)getStringW( IDS_P_PLDIRECTION_AUTO, NULL, 0 ) );
+ SendDlgItemMessageW( hwndDlg, IDC_PLDIRECTION, CB_ADDSTRING, 0, (LPARAM)getStringW( IDS_P_PLDIRECTION_L2R, NULL, 0 ) );
+ SendDlgItemMessageW( hwndDlg, IDC_PLDIRECTION, CB_ADDSTRING, 0, (LPARAM)getStringW( IDS_P_PLDIRECTION_R2L, NULL, 0 ) );
+
+ SendDlgItemMessage( hwndDlg, IDC_PLDIRECTION, CB_SETCURSEL, config_pe_direction, 0 );
+
+ HWND fontcombo = GetDlgItem( hwndDlg, IDC_CUSTOMFONT );
+ HDC dc = GetDC( NULL );
+ EnumFonts( dc, NULL, (FONTENUMPROC)EnumFontsProc, (LPARAM)fontcombo );
+ ReleaseDC( NULL, dc );
+
+ // select the font, but fall back to Arial if it doesn't exist
+ ComboBox combobox( fontcombo );
+ if ( combobox.SelectString( playlist_custom_fontW ) == CB_ERR )
+ {
+ StringCbCopyW( playlist_custom_fontW, sizeof( playlist_custom_fontW ), FALLBACK_FONT );
+ combobox.SelectString( playlist_custom_fontW );
+ }
+ CheckDlgButton( hwndDlg, IDC_NOCUSTOMFONT, config_custom_plfont ? 0 : 1 );
+ if ( !config_custom_plfont )
+ {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_CUSTOMFONT ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_STATIC_CUSTOMFONT ), FALSE );
+ }
+
+ //WI(plscrollsize);
+ //WI(plmw2xscroll);
+ SetDlgItemInt( hwndDlg, IDC_PLSCROLL, config_plscrollsize, 0 );
+ SendDlgItemMessage( hwndDlg, IDC_SPIN3, UDM_SETRANGE, 0, MAKELONG( 100, 1 ) );
+ CheckDlgButton( hwndDlg, IDC_MOUSE_SCROLL_DOUBLE_LINES, config_plmw2xscroll ? 1 : 0 );
+ pl_prefs_init = 1;
+ }
+ else if ( uMsg == WM_COMMAND )
+ switch ( LOWORD( wParam ) )
+ {
+ case IDC_PLDIRECTION:
+ if ( HIWORD( wParam ) == CBN_SELCHANGE )
+ {
+ int l = SendDlgItemMessage( hwndDlg, IDC_PLDIRECTION, CB_GETCURSEL, 0, 0 );
+ if ( l != CB_ERR )
+ config_pe_direction = l;
+
+ InvalidateRect( hPLWindow, NULL, FALSE );
+ }
+ return 0;
+
+ case IDC_NOCUSTOMFONT:
+ config_custom_plfont = !IsDlgButtonChecked( hwndDlg, IDC_NOCUSTOMFONT );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_CUSTOMFONT ), IsDlgButtonChecked( hwndDlg, IDC_NOCUSTOMFONT ) ? 0 : 1 );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_STATIC_CUSTOMFONT ), IsDlgButtonChecked( hwndDlg, IDC_NOCUSTOMFONT ) ? 0 : 1 );
+ draw_reinit_plfont( 1 );
+ InvalidateRect( hPLWindow, NULL, FALSE );
+ JSAPI1_SkinChanged();
+ break;
+
+ case IDC_CUSTOMFONT:
+ if ( HIWORD( wParam ) == CBN_SELCHANGE )
+ {
+ HWND fontcombo;
+ int idx, len;
+ wchar_t *t;
+ fontcombo = GetDlgItem( hwndDlg, IDC_CUSTOMFONT );
+ ComboBox combobox( fontcombo );
+ idx = combobox.GetSelection();
+ len = combobox.GetTextLen( idx );
+ t = (wchar_t *)_malloca( ( len + 1 ) * sizeof( wchar_t ) );
+ combobox.GetText( idx, t );
+ t[ len ] = 0;
+ StringCbCopyW( playlist_custom_fontW, sizeof( playlist_custom_fontW ), t );
+ WideCharToMultiByteSZ( CP_ACP, 0, playlist_custom_fontW, -1, playlist_custom_font, 128, 0, 0 );
+ _freea( t );
+ draw_reinit_plfont( 1 );
+ InvalidateRect( hPLWindow, NULL, FALSE );
+ JSAPI1_SkinChanged();
+ }
+ break;
+
+ case IDC_PLNUMS:
+ {
+ int t = config_shownumsinpl;
+ config_shownumsinpl = IsDlgButtonChecked( hwndDlg, IDC_PLNUMS ) ? 1 : 0;
+ if ( config_shownumsinpl != t )
+ {
+ _w_i( "shownumsinpl", config_shownumsinpl );
+ draw_reinit_plfont( 1 );
+ if ( config_pe_open )
+ InvalidateRect( hPLWindow, NULL, FALSE );
+ }
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PLZEROPAD ), config_shownumsinpl );
+ }
+ break;
+
+ case IDC_PLZEROPAD:
+ {
+ config_zeropadplnum = IsDlgButtonChecked( hwndDlg, IDC_PLZEROPAD ) ? 1 : 0;
+ InvalidateRect( hPLWindow, NULL, FALSE );
+ }
+ break;
+
+ case IDC_PLFONTSIZE:
+ if ( HIWORD( wParam ) == EN_CHANGE && pl_prefs_init )
+ {
+ int s = 0, t = GetDlgItemInt( hwndDlg, IDC_PLFONTSIZE, &s, 0 );
+ if ( t < 2 )
+ t = 11;
+
+ if ( t != config_pe_fontsize && s )
+ {
+ config_pe_fontsize = t;
+ if ( hMainWindow )
+ {
+ draw_reinit_plfont( 1 );
+ InvalidateRect( hPLWindow, NULL, FALSE );
+ }
+
+ JSAPI1_SkinChanged();
+ }
+ }
+ break;
+
+ case IDC_DEFEXT:
+ if ( HIWORD( wParam ) == EN_CHANGE )
+ {
+ GetWindowTextA( GetDlgItem( hwndDlg, IDC_DEFEXT ), config_defext, sizeof( config_defext ) );
+ }
+ break;
+
+ case IDC_RFL:
+ config_rofiob &= ~1;
+ config_rofiob |= IsDlgButtonChecked( hwndDlg, IDC_RFL ) ? 1 : 0;
+ break;
+
+ case IDC_MANUALPLAYLISTADVANCE:
+ {
+ int manadv = IsDlgButtonChecked( hwndDlg, IDC_MANUALPLAYLISTADVANCE ) ? 0 : 1;
+ if ( manadv != config_pladv )
+ SendMessageW( hMainWindow, WM_COMMAND, WINAMP_FILE_MANUALPLADVANCE, 0 );
+
+ break;
+ }
+
+ case IDC_MOUSE_SCROLL_DOUBLE_LINES:
+ config_plmw2xscroll = IsDlgButtonChecked( hwndDlg, IDC_MOUSE_SCROLL_DOUBLE_LINES ) ? 1 : 0;
+ break;
+
+ case IDC_PLSCROLL:
+ if ( HIWORD( wParam ) == EN_CHANGE && pl_prefs_init )
+ {
+ int s = 0, t = GetDlgItemInt( hwndDlg, IDC_PLSCROLL, &s, 0 );
+ if ( t < 1 )
+ t = 1;
+
+ if ( t > 16 )
+ t = 16;
+
+ if ( t != config_plscrollsize && s )
+ config_plscrollsize = t;
+ }
+ break;
+
+ case IDC_SHUFFLE_HELP:
+ {
+ wchar_t title[ 64 ] = { 0 };
+ MessageBoxW( hwndDlg, getStringW( IDS_SHUFFLE_MORPH_INFO, NULL, 0 ),
+ getStringW( IDS_SHUFFLE_MORPH_RATE, title, 64 ), 0 );
+ }
+ break;
+ }
+ else if ( uMsg == WM_HSCROLL )
+ {
+ HWND swnd = (HWND)lParam;
+ if ( swnd == GetDlgItem( hwndDlg, IDC_PREFS_SHUFFLE_MORPH_RATE ) )
+ {
+ config_shuffle_morph_rate = (unsigned char)SendMessageW( GetDlgItem( hwndDlg, IDC_PREFS_SHUFFLE_MORPH_RATE ), TBM_GETPOS, 0, 0 );
+ }
+ }
+ else if ( uMsg == WM_DESTROY )
+ {
+ pl_prefs_init = 0;
+ }
+
+ const int controls[] =
+ {
+ IDC_PREFS_SHUFFLE_MORPH_RATE,
+ };
+
+ if ( FALSE != DirectMouseWheel_ProcessDialogMessage( hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE( controls ) ) )
+ return TRUE;
+
+ return FALSE;
+} //shuffle \ No newline at end of file
diff --git a/Src/Winamp/options_plugins.cpp b/Src/Winamp/options_plugins.cpp
new file mode 100644
index 00000000..baf56ef6
--- /dev/null
+++ b/Src/Winamp/options_plugins.cpp
@@ -0,0 +1,203 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "Options.h"
+#include "resource.h"
+
+static int CALLBACK WINAPI BrowseCallbackProc_VIS( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ if (uMsg == BFFM_INITIALIZED)
+ {
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)VISDIR);
+
+ // this is not nice but it fixes the selection not working correctly on all OSes
+ EnumChildWindows(hwnd, browseEnumProc, 0);
+ }
+ if (uMsg == WM_CREATE) SetWindowTextW(hwnd,getStringW(IDS_SELVISDIR,NULL,0));
+ return 0;
+}
+
+static int CALLBACK WINAPI BrowseCallbackProc_DSP( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ if (uMsg == BFFM_INITIALIZED)
+ {
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)DSPDIR);
+
+ // this is not nice but it fixes the selection not working correctly on all OSes
+ EnumChildWindows(hwnd, browseEnumProc, 0);
+ }
+ if (uMsg == WM_CREATE) SetWindowTextW(hwnd,getStringW(IDS_SELDSPDIR,NULL,0));
+ return 0;
+}
+
+void SetButtonText(HWND hwndDlg, int id, wchar_t* path)
+{
+ HWND control = GetDlgItem(hwndDlg, id);
+ HDC hdc = GetDC(control);
+ RECT r = {0};
+ wchar_t temp[MAX_PATH] = {0};
+
+ lstrcpynW(temp, path, MAX_PATH);
+ SelectObject(hdc, (HFONT)SendMessageW(control, WM_GETFONT, 0, 0));
+ GetClientRect(control, &r);
+ r.left += 5;
+ r.right -= 5;
+ DrawTextW(hdc, temp, -1, &r, DT_PATH_ELLIPSIS | DT_WORD_ELLIPSIS | DT_MODIFYSTRING);
+ SetWindowTextW(control, temp);
+ ReleaseDC(control, hdc);
+}
+
+
+INT_PTR CALLBACK PlugProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={
+ {IDC_VISDIR, IDS_P_PLUG_VISDIR},
+ {IDC_DSPDIR, IDS_P_PLUG_DSPDIR},
+ {IDC_VISPRIO, IDS_P_PLUG_PRIO},
+ {IDC_AUTOEXEC, IDS_P_PLUG_AUTO},
+ {IDC_DISVIS, IDS_P_PLUG_DIS},
+ {IDC_SAFEMODE, IDS_P_PLUG_SAFEMODE},
+ {IDC_SAFEMODEALWAYS, IDS_P_PLUG_SAFEMODEALWAYS},
+ {IDC_CHECK1, IDS_P_PLUG_DISSEHVIS},
+ {IDC_CHECK5, IDS_P_PLUG_DISSEHGEN},
+ {IDC_CHECK6, IDS_P_PLUG_DISSEHDSP},
+ };
+
+ DO_HELP();
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ CheckDlgButton(hwndDlg, IDC_AUTOEXEC, config_visplugin_autoexec ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DISVIS, config_disvis ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CHECK1, (config_no_visseh & 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CHECK6, (config_no_visseh & 2) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CHECK5, (config_no_visseh & 4) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SAFEMODEALWAYS, _r_i("safemode", 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_VISPRIO, TBM_SETRANGE, TRUE, MAKELONG(0, 4));
+ SendDlgItemMessage(hwndDlg, IDC_VISPRIO, TBM_SETPOS, TRUE, config_visplugin_priority);
+ SetDlgItemTextW(hwndDlg, IDC_VISDIR, VISDIR);
+ SetButtonText(hwndDlg, IDC_VISDIR, VISDIR);
+ SetDlgItemTextW(hwndDlg, IDC_DSPDIR, DSPDIR);
+ SetButtonText(hwndDlg, IDC_DSPDIR, DSPDIR);
+
+ if (g_safeMode)
+ {
+ SetDlgItemTextW(hwndDlg, IDC_SAFEMODE, getStringW(IDS_RESTART_NORMAL, NULL, 0));
+ }
+ }
+
+ if (uMsg == WM_HSCROLL)
+ {
+ HWND swnd = (HWND)lParam;
+ if (swnd == GetDlgItem(hwndDlg, IDC_VISPRIO))
+ {
+ config_visplugin_priority = (unsigned char) SendDlgItemMessage(hwndDlg, IDC_VISPRIO, TBM_GETPOS, 0, 0);
+ vis_setprio();
+ }
+ }
+
+ if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHECK1:
+ case IDC_CHECK5:
+ case IDC_CHECK6:
+ config_no_visseh =
+ (IsDlgButtonChecked(hwndDlg, IDC_CHECK1) ? 1 : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_CHECK6) ? 2 : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_CHECK5) ? 4 : 0);
+ break;
+
+ case IDC_AUTOEXEC:
+ config_visplugin_autoexec = IsDlgButtonChecked(hwndDlg, IDC_AUTOEXEC) ? 1 : 0;
+ break;
+
+ case IDC_DISVIS:
+ config_disvis = IsDlgButtonChecked(hwndDlg, IDC_DISVIS) ? 1 : 0;
+ break;
+
+ case IDC_VISDIR:
+ {
+ BROWSEINFOW bi = {0};
+ wchar_t name[MAX_PATH] = {0};
+ bi.hwndOwner = hMainWindow;
+ bi.pszDisplayName = name;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc_VIS;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist)
+ {
+ wchar_t path[MAX_PATH] = {0};
+ SHGetPathFromIDListW(idlist, path);
+ Shell_Free(idlist);
+ lstrcpynW(VISDIR, path, MAX_PATH);
+ SetDlgItemTextW(hwndDlg, IDC_VISDIR,VISDIR);
+ _w_sW("VISDir", VISDIR);
+ SetButtonText(hwndDlg, IDC_VISDIR, VISDIR);
+ }
+ }
+ return FALSE;
+
+ case IDC_DSPDIR:
+ {
+ BROWSEINFOW bi = {0};
+ wchar_t name[MAX_PATH] = {0};
+ bi.hwndOwner = hMainWindow;
+ bi.pszDisplayName = name;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc_DSP;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist)
+ {
+ wchar_t path[MAX_PATH] = {0};
+ SHGetPathFromIDListW(idlist, path);
+ Shell_Free(idlist);
+ lstrcpynW(DSPDIR, path, MAX_PATH);
+ SetDlgItemTextW(hwndDlg, IDC_DSPDIR, DSPDIR);
+ _w_sW("DSPDir", DSPDIR);
+ SetButtonText(hwndDlg, IDC_DSPDIR, DSPDIR);
+ }
+ }
+ return FALSE;
+
+ case IDC_SAFEMODE:
+ if (LPMessageBox(hwndDlg, IDS_RESTART_SAFE, IDS_RESTART, MB_YESNO | MB_ICONQUESTION | MB_TOPMOST) == IDYES)
+ {
+ _w_i("show_prefs", 30);
+ PostMessageW(hMainWindow, WM_USER, 0, (!g_safeMode ? IPC_RESTARTSAFEWINAMP : IPC_RESTARTWINAMP));
+ }
+ return FALSE;
+
+ case IDC_SAFEMODEALWAYS:
+ {
+ int mode = (IsDlgButtonChecked(hwndDlg, IDC_SAFEMODEALWAYS) ? 1 : 0);
+ _w_i("safemode", mode);
+ if (mode != !!g_safeMode)
+ {
+ if (LPMessageBox(hwndDlg, IDS_RESTART_SAFE, IDS_RESTART, MB_YESNO | MB_ICONQUESTION | MB_TOPMOST) == IDYES)
+ {
+ _w_i("show_prefs", 30);
+ PostMessageW(hMainWindow, WM_USER, 0, (!g_safeMode ? IPC_RESTARTSAFEWINAMP : IPC_RESTARTWINAMP));
+ }
+ }
+ return FALSE;
+ }
+ }
+ }
+
+ const int controls[] =
+ {
+ IDC_VISPRIO,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ return TRUE;
+
+ return FALSE;
+} //audio \ No newline at end of file
diff --git a/Src/Winamp/options_skin.cpp b/Src/Winamp/options_skin.cpp
new file mode 100644
index 00000000..8c1bf5f2
--- /dev/null
+++ b/Src/Winamp/options_skin.cpp
@@ -0,0 +1,683 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "language.h"
+#include "../nu/AutoWide.h"
+#include "resource.h"
+#include "Options.h"
+#include "main.hpp"
+#include "language.h"
+
+static WNDPROC list_oldWndProc;
+static wchar_t rename_skin[MAX_PATH];
+static wchar_t CLASSIC_NAME[64];
+
+
+static BOOL FillEnumRec(ENUMSKIN *pes, LPCWSTR pszFileName, BOOL bDirectory, LPWSTR pszName, INT cchName, LPCWSTR pszActiveFile)
+{
+ LPCWSTR pExt, pszFile;
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ if (bDirectory)
+ {
+ if (pszFileName[0] == L'.' && ((pszFileName[1] == L'.' && pszFileName[2] == 0x00) || pszFileName[1] == 0x00)) return FALSE;
+ pes->nType = SKIN_FILETYPE_DIR;
+ pExt = pszFileName + lstrlenW(pszFileName) + 1;
+ }
+ else
+ {
+ pExt = PathFindExtensionW(pszFileName);
+ if (L'.' != *pExt) return FALSE;
+ pExt++;
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pExt, -1, L"zip", -1)) pes->nType = SKIN_FILETYPE_ZIP;
+ else if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pExt, -1, L"wal", -1)) pes->nType = SKIN_FILETYPE_WAL;
+ else if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pExt, -1, L"wsz", -1)) pes->nType = SKIN_FILETYPE_WSZ;
+ else return FALSE;
+ }
+
+ pszFile = PathFindFileNameW(pszFileName);
+ StringCchCopyNW(pszName, cchName, pszFile, (size_t)(pExt - pszFile - 1));
+
+ pes->pszFileName = pszFileName;
+ pes->pszName = pszName;
+ pes->bActive = (pszActiveFile && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszActiveFile, -1, pes->pszFileName, -1));
+ return TRUE;
+}
+
+int EnumerateSkins(ENUMSKINPROC fnEnumSkin, void *user)
+{
+ if (!fnEnumSkin) return FALSE;
+
+ HANDLE h;
+ BOOL bActiveFound, bTerminated;
+ WIN32_FIND_DATAW d;
+ wchar_t dirmask[MAX_PATH], szName[MAX_PATH], *pszActive;
+ ENUMSKIN es;
+
+ bActiveFound = FALSE;
+ bTerminated = FALSE;
+
+ if (*config_skin)
+ {
+ pszActive = PathFindFileNameW(config_skin);
+ if (pszActive != config_skin && BuildFullPath(SKINDIR, config_skin, szName, sizeof(szName)/sizeof(wchar_t)))
+ {
+ INT cr = ComparePath(szName, pszActive, SKINDIR);
+ if(cr && CSTR_EQUAL != cr && PathFileExistsW(szName))
+ {
+ if (FillEnumRec(&es, config_skin, FALSE, szName, sizeof(szName)/sizeof(wchar_t), NULL))
+ {
+ es.bActive = TRUE;
+ bActiveFound = TRUE;
+ if (!fnEnumSkin(&es, user)) return FALSE;
+ }
+ }
+ }
+ }
+ else pszActive = NULL;
+
+ PathCombineW(dirmask, SKINDIR, L"*");
+ h = FindFirstFileW(dirmask,&d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (FillEnumRec(&es, d.cFileName, (FILE_ATTRIBUTE_DIRECTORY & d.dwFileAttributes), szName, sizeof(szName)/sizeof(wchar_t), (bActiveFound) ? NULL : pszActive))
+ {
+ if (es.bActive) bActiveFound = TRUE;
+ if (!fnEnumSkin(&es, user))
+ {
+ bTerminated = TRUE;
+ break;
+ }
+ }
+
+ } while (FindNextFileW(h,&d));
+ FindClose(h);
+ }
+
+ if(!CLASSIC_NAME[0])getStringW(IDS_CLASSIC_SKIN_NAME,CLASSIC_NAME,64);
+ es.pszFileName = NULL;
+ es.pszName = CLASSIC_NAME;
+ es.nType = SKIN_FILETYPE_EMBED;
+ es.bActive = !bActiveFound;
+ bTerminated = !fnEnumSkin(&es, user);
+ return !bTerminated;
+}
+
+static int CALLBACK BrowseSkinCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ switch (uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ SetWindowTextW(hwnd, getStringW(IDS_P_SELECT_SKINDIR,NULL,0));
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)SKINDIR);
+ }
+ return 0;
+ }
+ return 0;
+}
+
+void SetDialogBoxFromFile(FILE *fp, HWND hwndDlg, int id)
+{
+ bool utf8=false, utf16=false;
+ unsigned char BOM[3] = {0, 0, 0};
+ if (fread(BOM, 3, 1, fp) == 1 && BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
+ utf8 = true;
+ else
+ {
+ fseek(fp, 0, SEEK_SET);
+ if (fread(BOM, 2, 1, fp) == 1 && BOM[0] == 0xFF && BOM[1] == 0xFE)
+ utf16=true;
+ else
+ fseek(fp, 0, SEEK_SET);
+ }
+
+ if (utf16)
+ {
+ wchar_t buffer[32768+1024] = {0},*p = buffer;
+ for (;;)
+ {
+ fgetws(p,1024,fp);
+ if (feof(fp)) break;
+ if (p[wcslen(p)-1]==L'\n')
+ p[wcslen(p)-1]=0;
+ StringCchCatW(p,32768+1024,L"\r\n");
+ p=p+wcslen(p);
+ if (p-buffer > 32768) break;
+ }
+
+ buffer[32767]=0;
+ SetDlgItemTextW(hwndDlg,id,buffer);
+ }
+ else
+ {
+ char buffer[32768+1024] = {0}, *p = buffer;
+ for (;;)
+ {
+ fgets(p,1024,fp);
+ if (feof(fp)) break;
+ if (p[lstrlenA(p)-1]=='\n')
+ p[lstrlenA(p)-1]=0;
+ StringCchCatA(p,32768+1024,"\r\n");
+ p=p+lstrlenA(p);
+ if (p-buffer > 32768) break;
+ }
+
+ buffer[32767]=0;
+ if (utf8)
+ SetDlgItemTextW(hwndDlg,id,AutoWide(buffer, CP_UTF8));
+ else
+ SetDlgItemTextA(hwndDlg,id,buffer);
+ }
+}
+
+
+static void _setreadme(HWND hwndDlg)
+{
+ if (config_skin[0])
+ {
+ LRESULT ipcRet;
+
+ if ((ipcRet=SendMessageW(hMainWindow,WM_WA_IPC,0,IPC_GETSKININFOW)) > 65536)
+ {
+ SetDlgItemTextW(hwndDlg,IDC_EDIT1,(const wchar_t *)ipcRet);
+ }
+ else if ((ipcRet=SendMessageW(hMainWindow,WM_WA_IPC,0,IPC_GETSKININFO)) > 65536)
+ {
+ SetDlgItemTextA(hwndDlg,IDC_EDIT1,(const char*)ipcRet);
+ }
+ else
+ {
+ wchar_t s[MAX_PATH]={0};
+ PathCombineW(s, skin_directory, L"readme.txt");
+ FILE *fp=_wfopen(s,L"rt");
+ if (!fp)
+ {
+ PathCombineW(s, skin_directory, L"read me.txt");
+ fp=_wfopen(s,L"rt");
+ }
+ if (!fp)
+ {
+ PathCombineW(s, skin_directory, L"file_id.diz");
+ fp=_wfopen(s,L"rt");
+ }
+ if (!fp)
+ {
+ WIN32_FIND_DATAW d;
+ PathCombineW(s, skin_directory, L"*.txt");
+
+ HANDLE h = FindFirstFileW(s,&d);
+ s[0]=0;
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (_wcsicmp(d.cFileName,L"pledit.txt") &&
+ _wcsicmp(d.cFileName,L"viscolor.txt") &&
+ _wcsicmp(d.cFileName,L"region.txt"))
+ {
+ PathCombineW(s, skin_directory, d.cFileName);
+ break;
+ }
+ } while (FindNextFileW(h,&d));
+ FindClose(h);
+ if (s && L'\0' == *s) fp=_wfopen(s,L"rb");
+ }
+ }
+
+ if (fp)
+ {
+ SetDialogBoxFromFile(fp, hwndDlg, IDC_EDIT1);
+ fclose(fp);
+ }
+ else
+ SetDlgItemTextW(hwndDlg,IDC_EDIT1,getStringW(IDS_P_SKIN_NO_INFO_FOUND,NULL,0));
+ }
+ }
+ else
+ {
+ char buf[256]={0}, form[64]={0};
+ StringCchPrintfA(buf,256, getString(IDS_CLASSIC_BASE_SKIN_VERSION,form,64),app_version);
+ SetDlgItemTextA(hwndDlg,IDC_EDIT1,buf);
+ }
+}
+
+static BOOL CALLBACK renameSkinProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextW(hwndDlg,IDC_OLD,rename_skin);
+ SetDlgItemTextW(hwndDlg,IDC_NEW,rename_skin);
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetDlgItemTextW(hwndDlg,IDC_NEW,rename_skin,MAX_PATH);
+ EndDialog(hwndDlg,!!rename_skin[0]);
+ return 0;
+ case IDCANCEL:
+ EndDialog(hwndDlg,0);
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static void SkinDeleteSkin(HWND hwndDlg, LRESULT x)
+{
+ wchar_t skin[MAX_PATH] = {0};
+ int x2 = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0);
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,(x!=-1?x:x2),(LPARAM)skin);
+
+ switch (SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,(x!=-1?x:x2),0))
+ {
+ case SKIN_FILETYPE_ZIP: StringCchCatW(skin,MAX_PATH, L".zip"); break;
+ case SKIN_FILETYPE_WSZ: StringCchCatW(skin,MAX_PATH, L".wsz"); break;
+ case SKIN_FILETYPE_WAL: StringCchCatW(skin,MAX_PATH, L".wal"); break;
+ default: break;
+ }
+
+ if (skin[0] && _wcsicmp(skin,CLASSIC_NAME) && _wcsicmp(skin,MODERN_SKIN_NAME) &&
+ _wcsicmp(skin,BENTO_SKIN_NAME) && _wcsicmp(skin,BIG_BENTO_SKIN_NAME))
+ {
+ wchar_t buf[2048] = {0};
+ StringCchPrintfW(buf, 2048, getStringW(IDS_P_SKINS_DELETESKIN_PROMPT,NULL,0),skin);
+
+ if (MessageBoxW(hwndDlg,buf,getStringW(IDS_P_SKINS_DELETESKIN,NULL,0),MB_YESNO|MB_ICONQUESTION) == IDYES)
+ {
+ PathCombineW(buf, SKINDIR, skin);
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->DeleteItem(buf);
+ registrar->CleanupDirectory(buf);
+ registrar->Release();
+ }
+
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_DELETESTRING,(x!=-1?x:x2),0);
+
+ // check if it's the current skin and if so reset to 'classic' and refresh
+ if (((x == x2) && !lstrcmpiW(config_skin, skin)) || x == -1)
+ {
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,0,0);
+ config_skin[0]=0;
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_REFRESHSKIN,0);
+ _setreadme(hwndDlg);
+ }
+ }
+ }
+}
+
+static BOOL CALLBACK AddSkinToListBox(ENUMSKIN *pes, void *user)
+{
+ int index;
+ index = SendMessageW((HWND)user, LB_ADDSTRING, 0, (LPARAM)pes->pszName);
+ if (LB_ERR != index)
+ {
+ SendMessageW((HWND)user, LB_SETITEMDATA, index, (LPARAM)pes->nType);
+ if (pes->bActive) SendMessageW((HWND)user, LB_SETCURSEL, index, 0);
+ }
+ return TRUE;
+}
+
+static void SkinRenameSkin(HWND hwndDlg, LRESULT x, int* timer_active)
+{
+ int x2 = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0);
+ int nType = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,(x!=-1?x:x2),0);
+
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,(x!=-1?x:x2),(LPARAM)rename_skin);
+
+ if (rename_skin[0] && _wcsicmp(rename_skin,CLASSIC_NAME) &&
+ (nType || (_wcsicmp(rename_skin,MODERN_SKIN_NAME) &&
+ _wcsicmp(rename_skin,BENTO_SKIN_NAME) &&
+ _wcsicmp(rename_skin,BIG_BENTO_SKIN_NAME))))
+ {
+ wchar_t oldskin[MAX_PATH] = {0};
+ StringCchCopyW(oldskin, MAX_PATH,rename_skin);
+
+ if (LPDialogBoxW(IDD_RENAMESKIN,hwndDlg,renameSkinProc) && wcscmp(oldskin,rename_skin))
+ {
+ wchar_t oldname[MAX_PATH] = {0}, newname[MAX_PATH] = {0};
+
+ PathCombineW(oldname, SKINDIR, oldskin);
+ PathCombineW(newname, SKINDIR, rename_skin);
+
+ switch (nType)
+ {
+ case SKIN_FILETYPE_ZIP: StringCchCatW(oldname,MAX_PATH, L".zip"); StringCchCatW(newname,MAX_PATH, L".zip"); break;
+ case SKIN_FILETYPE_WSZ: StringCchCatW(oldname,MAX_PATH, L".wsz"); StringCchCatW(newname,MAX_PATH, L".wsz"); break;
+ case SKIN_FILETYPE_WAL: StringCchCatW(oldname,MAX_PATH, L".wal"); StringCchCatW(newname,MAX_PATH, L".wal"); break;
+ default: break;
+ }
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ if (SUCCEEDED(registrar->RenameItem(oldname,newname, FALSE)))
+ {
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_DELETESTRING,(x!=-1?x:x2),0);
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_INSERTSTRING,(x!=-1?x:x2),(LPARAM)rename_skin);
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETITEMDATA,(x!=-1?x:x2), nType);
+
+ // check if it's the current skin and if so reset to 'classic' and refresh
+ if (((x == x2) && !lstrcmpiW(config_skin, newname)) || x == -1)
+ {
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,(x!=-1?x:x2),0);
+ KillTimer(hwndDlg,1);
+ SetTimer(hwndDlg,1,250,NULL);
+ *timer_active=1;
+ }
+ }
+ else
+ {
+ LPMessageBox(hwndDlg, IDS_P_SKINS_RN_ERR, IDS_P_SKINS_RN_ERR_CAP, MB_OK);
+ }
+
+ registrar->Release();
+ }
+ }
+ }
+}
+
+static LRESULT WINAPI list_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ if(uMsg == WM_RBUTTONUP)
+ {
+ PostMessageW(GetParent(hwndDlg),WM_USER+0x123,0,0);
+ }
+ else if(uMsg == WM_KEYDOWN && wParam == VK_DELETE)
+ {
+ SkinDeleteSkin(GetParent(hwndDlg),-1);
+ }
+ return CallWindowProcW(list_oldWndProc,hwndDlg,uMsg,wParam,lParam);
+}
+
+INT_PTR CALLBACK SkinProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static int timer_active;
+ hi helpinfo[]={{IDC_SELBOX,IDS_P_SK_SEL},
+ {IDC_RANDOM,IDS_P_SK_RND},
+ {IDC_CHDIR,IDS_P_SK_CHDR},
+ {IDC_SKIN_INSTALL_PROMPT,IDS_P_SK_PROMPT}};
+ DO_HELP();
+
+ switch (uMsg)
+ {
+ case WM_NOTIFYFORMAT:
+ {
+ return NFR_UNICODE;
+ }
+ case WM_INITDIALOG:
+ {
+ HWND listWindow = GetDlgItem(hwndDlg,IDC_SELBOX);
+ if (NULL != listWindow)
+ {
+ SendMessageW(listWindow, CCM_SETUNICODEFORMAT, TRUE, 0);
+ list_oldWndProc=(WNDPROC)SetWindowLongPtrW(listWindow,GWLP_WNDPROC,(LONG_PTR)list_newWndProc);
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, TRUE);
+ }
+ CheckDlgButton(hwndDlg, IDC_SKIN_INSTALL_PROMPT, config_skin_prompt);
+ link_startsubclass(hwndDlg, IDC_WINAMPLINK);
+ }
+ case WM_USER+50:
+ {
+ int index, en, modern = 0, bento = 0;
+ wchar_t selected[MAX_PATH] = {0};
+
+ HWND hw = GetDlgItem(hwndDlg,IDC_SELBOX);
+
+ SendMessageW(hw,WM_SETREDRAW,FALSE,0);
+
+ EnumerateSkins(AddSkinToListBox, hw);
+ index = (INT)SendMessageW(hw,LB_GETCURSEL,0,0);
+ if (LB_ERR == index || LB_ERR == SendMessageW(hw, LB_GETTEXT, index, (LPARAM)selected))
+ selected[0] = 0x00;
+
+ index = (INT)SendMessageW(hw, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)CLASSIC_NAME);
+ if (LB_ERR != index)
+ {
+ SendMessageW(hw, LB_DELETESTRING, index, 0);
+ SendMessageW(hw, LB_INSERTSTRING, 0, (LPARAM)CLASSIC_NAME);
+ }
+
+ index = (INT)SendMessageW(hw, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)MODERN_SKIN_NAME);
+ if (LB_ERR != index)
+ {
+ SendMessageW(hw, LB_DELETESTRING, index, 0);
+ SendMessageW(hw, LB_INSERTSTRING, 1, (LPARAM)MODERN_SKIN_NAME);
+ modern = 1;
+ }
+
+ index = (INT)SendMessageW(hw, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)BENTO_SKIN_NAME);
+ if (LB_ERR != index)
+ {
+ SendMessageW(hw, LB_DELETESTRING, index, 0);
+ SendMessageW(hw, LB_INSERTSTRING, 1 + modern, (LPARAM)BENTO_SKIN_NAME);
+ bento = 1;
+ }
+
+ index = (INT)SendMessageW(hw, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)BIG_BENTO_SKIN_NAME);
+ if (LB_ERR != index)
+ {
+ SendMessageW(hw, LB_DELETESTRING, index, 0);
+ SendMessageW(hw, LB_INSERTSTRING, 1 + modern + bento, (LPARAM)BIG_BENTO_SKIN_NAME);
+ }
+
+ index = (*selected) ? (INT)SendMessageW(hw, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)selected) : LB_ERR;
+ if (LB_ERR == index) index = 0;
+ SendMessageW(hw,LB_SETCURSEL, index, 0);
+
+ en = config_skin[0] && _wcsicmp(config_skin,MODERN_SKIN_NAME) &&
+ _wcsicmp(config_skin,BENTO_SKIN_NAME) &&
+ _wcsicmp(config_skin,BIG_BENTO_SKIN_NAME);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_RENAME_SKIN),en);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_DELETE_SKIN),en);
+
+ SendMessageW(hw,WM_SETREDRAW,TRUE,0);
+ CheckDlgButton(hwndDlg,IDC_RANDOM,config_randskin);
+ _setreadme(hwndDlg);
+ return FALSE;
+ }
+ case WM_USER+0x123:
+ {
+ HMENU h=GetSubMenu(GetSubMenu(top_menu,5),0);
+ if (h)
+ {
+ POINT p,ps;
+ GetCursorPos(&p);
+ ps=p;
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_SELBOX),&ps);
+ LRESULT x=SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_ITEMFROMPOINT,0,MAKELPARAM(ps.x,ps.y));
+
+ if (HIWORD(x)==0 && (x=LOWORD(x)) >= 0)
+ {
+ bool allowo=x > 0;
+ wchar_t skin[MAX_PATH] = {0};
+ int nType = SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,x,0);
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,x,(LPARAM)skin);
+ if (allowo &&
+ (!_wcsicmp(skin,MODERN_SKIN_NAME) || !_wcsicmp(skin,BENTO_SKIN_NAME) ||
+ !_wcsicmp(skin,BIG_BENTO_SKIN_NAME)) && SKIN_FILETYPE_DIR == nType)
+ allowo=0;
+
+ EnableMenuItem(h,2,MF_BYPOSITION|(allowo?MF_ENABLED:MF_GRAYED));
+ EnableMenuItem(h,3,MF_BYPOSITION|(allowo?MF_ENABLED:MF_GRAYED));
+
+ //int sel=DoTrackPopup(h,TPM_RETURNCMD|TPM_NONOTIFY|TPM_RIGHTBUTTON,p.x,p.y,hwndDlg);
+ int sel=TrackPopupMenu(h,TPM_RETURNCMD|TPM_NONOTIFY|TPM_RIGHTBUTTON,p.x,p.y,0,hwndDlg,NULL);
+ if (sel)
+ {
+ if (sel == ID_PREFS_SKIN_SWITCHTOSKIN)
+ {
+ SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_SETCURSEL,LOWORD(x),0);
+ KillTimer(hwndDlg,1);
+ SetTimer(hwndDlg,1,250,NULL);
+ timer_active=1;
+ }
+ else if (sel == ID_PREFS_SKIN_RENAMESKIN)
+ {
+ SkinRenameSkin(hwndDlg, x, &timer_active);
+ }
+ else if (sel == ID_PREFS_SKIN_DELETESKIN)
+ {
+ SkinDeleteSkin(hwndDlg,x);
+ }
+ }
+ }
+ }
+ return 0;
+ }
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_SKIN_INSTALL_PROMPT:
+ {
+ config_skin_prompt = !config_skin_prompt;
+ return 0;
+ }
+ case IDC_RENAME_SKIN:
+ {
+ SkinRenameSkin(hwndDlg, -1, &timer_active);
+ return 0;
+ }
+ case IDC_DELETE_SKIN:
+ {
+ SkinDeleteSkin(hwndDlg,-1);
+ return 0;
+ }
+ case IDC_WINAMPLINK:
+ {
+ myOpenURLWithFallback(hwndDlg,L"http://www.google.com/search?q=%22winamp+skins%22", L"http://www.google.com/search?q=%22winamp+skins%22");
+ return 0;
+ }
+ case IDC_RANDOM:
+ {
+ config_randskin = IsDlgButtonChecked(hwndDlg,IDC_RANDOM)?1:0;
+ return 0;
+ }
+ case IDC_CHDIR:
+ {
+ BROWSEINFOW bi = {0};
+ bi.hwndOwner = hwndDlg;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseSkinCallbackProc;
+ ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
+ if (idlist) {
+ wchar_t path[MAX_PATH] = {0};
+ SHGetPathFromIDListW(idlist, path);
+ Shell_Free(idlist);
+
+ if(!PathIsRootW(path)) {
+ wchar_t orig[MAX_PATH] = {0};
+ StringCchCopyW(orig, MAX_PATH, SKINDIR);
+ StringCchCopyW(SKINDIR, MAX_PATH, path);
+ _w_sW("SkinDir", SKINDIR);
+
+ wchar_t message[2048] = {0};
+ StringCchPrintfW(message,2048,getStringW(IDS_SKIN_DIR_MOVE_MESSAGE,NULL,0),orig,SKINDIR);
+ if(MessageBoxW(hwndDlg, message, getStringW(IDS_SKIN_DIR_MOVE,NULL,0),MB_YESNO|MB_ICONQUESTION)==IDYES)
+ {
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->MoveDirectoryContents(orig,SKINDIR);
+ registrar->Release();
+ }
+ }
+
+ SendMessageW(GetDlgItem(hwndDlg,IDC_SELBOX),LB_RESETCONTENT,0,0);
+ SendMessageW(hwndDlg,WM_USER+50,0,0);
+ }
+ else {
+ wchar_t message[512] = {0};
+ MessageBoxW(hwndDlg, getStringW(IDS_DIR_MOVE_ERROR, message, 512),
+ getStringW(IDS_SKIN_DIR_MOVE,NULL,0), MB_OK|MB_ICONEXCLAMATION);
+ }
+ }
+ return FALSE;
+ }
+ case IDC_SELBOX:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ {
+ SendMessageW(hwndDlg,WM_COMMAND,IDOK,0);
+ }
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ KillTimer(hwndDlg,1);
+ SetTimer(hwndDlg,1,250,NULL);
+ timer_active=1;
+ }
+ return FALSE;
+ }
+ return FALSE;
+ }
+ case WM_DESTROY:
+ {
+ HWND listWindow = GetDlgItem(hwndDlg,IDC_SELBOX);
+ if (NULL != listWindow)
+ {
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE);
+ }
+ if (!timer_active) return 0;
+ }
+ case WM_TIMER:
+ {
+ wchar_t oldbuf[MAX_PATH] = {0};
+ int x = SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETCURSEL,0,0);
+ timer_active=0;
+ KillTimer(hwndDlg,1);
+ StringCchCopyW(oldbuf,MAX_PATH,config_skin);
+ SendDlgItemMessageW(hwndDlg,IDC_SELBOX,LB_GETTEXT,x,(LPARAM)config_skin);
+
+ switch (SendDlgItemMessage(hwndDlg,IDC_SELBOX,LB_GETITEMDATA,x,0))
+ {
+ case SKIN_FILETYPE_ZIP: StringCchCatW(config_skin,MAX_PATH, L".zip"); break;
+ case SKIN_FILETYPE_WSZ: StringCchCatW(config_skin,MAX_PATH, L".wsz"); break;
+ case SKIN_FILETYPE_WAL: StringCchCatW(config_skin,MAX_PATH, L".wal"); break;
+ default: break;
+ }
+
+ if (!_wcsicmp(config_skin,CLASSIC_NAME)) config_skin[0]=0;
+ {
+ int en = config_skin[0] && _wcsicmp(config_skin,MODERN_SKIN_NAME) &&
+ _wcsicmp(config_skin,BENTO_SKIN_NAME) &&
+ _wcsicmp(config_skin,BIG_BENTO_SKIN_NAME);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_RENAME_SKIN),en);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_DELETE_SKIN),en);
+ }
+ if (_wcsicmp(oldbuf,config_skin))
+ {
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_REFRESHSKIN,0);
+ _setreadme(hwndDlg);
+ }
+ }
+ return FALSE;
+ }
+
+ if (uMsg == WM_COMMAND && LOWORD(wParam)==IDC_PLUGINVERS)
+ {
+ myOpenURLWithFallback(hwndDlg, L"http://www.google.com/search?q=%22winamp+plugins%22", L"http://www.winamp.com/plugins");
+ }
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+
+ const int controls[] =
+ {
+ IDC_EDIT1,
+ };
+ if (FALSE != DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
+ {
+ return TRUE;
+ }
+ return 0;
+} // skins \ No newline at end of file
diff --git a/Src/Winamp/options_stationinfo.cpp b/Src/Winamp/options_stationinfo.cpp
new file mode 100644
index 00000000..b45fb06a
--- /dev/null
+++ b/Src/Winamp/options_stationinfo.cpp
@@ -0,0 +1,46 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "Main.h"
+#include "Options.h"
+#include "resource.h"
+
+
+// video tab procedure
+INT_PTR CALLBACK StationInfoProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ /*
+ hi helpinfo[]={
+ {IDC_PREFS_VIDEO_VSYNC,IDS_P_O_VIDEO_VSYNC},
+ {IDC_PREFS_VIDEO_ADJASP,IDS_P_O_VIDEO_ADJASP},
+ {IDC_PREFS_VIDEO_OVERLAYS,IDS_P_O_VIDEO_OVERLAYS},
+ {IDC_PREFS_VIDEO_UPDSIZE,IDS_P_O_VIDEO_UPDSIZE},
+ {IDC_PREFS_VIDEO_AUTOCLOSE,IDS_P_O_VIDEO_AUTOCLOSE},
+ {IDC_PREFS_VIDEO_NOSS,IDS_P_O_VIDEO_NOSS},
+ {IDC_PREFS_VIDEO_OSD,IDS_P_O_VIDEO_OSD},
+ {IDC_PREFS_VIDEO_YV12,IDS_P_O_VIDEO_YV12},
+ {IDC_PREFS_VIDEO_STOPCLOSE,IDS_P_O_VIDEO_STOPCLOSE},
+ {IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP,IDS_P_O_VIDEO_REMOVE_FS_ON_STOP},
+ {IDC_PREFS_VIDEO_AUTOOPEN,IDS_P_O_VIDEO_AUTOOPEN},
+ };
+ DO_HELP();*/
+ if (uMsg == WM_INITDIALOG)
+ {
+ CheckDlgButton(hwndDlg,IDC_PREFS_STATIONINFO_AUTOSHOW,config_si_autoshow);
+ CheckDlgButton(hwndDlg,IDC_PREFS_STATIONINFO_AUTOHIDE,config_si_autohide);
+ CheckDlgButton(hwndDlg,IDC_PREFS_STATIONINFO_AUTOSIZE,config_si_autosize);
+
+ }
+
+ if (uMsg == WM_COMMAND) switch (LOWORD(wParam))
+ {
+ case IDC_PREFS_STATIONINFO_AUTOSHOW: config_si_autoshow = IsDlgButtonChecked(hwndDlg,IDC_PREFS_STATIONINFO_AUTOSHOW)?1:0; break;
+ case IDC_PREFS_STATIONINFO_AUTOHIDE: config_si_autohide = IsDlgButtonChecked(hwndDlg,IDC_PREFS_STATIONINFO_AUTOHIDE)?1:0; break;
+ case IDC_PREFS_STATIONINFO_AUTOSIZE: config_si_autosize = IsDlgButtonChecked(hwndDlg,IDC_PREFS_STATIONINFO_AUTOSIZE)?1:0; break;
+ }
+ return FALSE;
+} //video
diff --git a/Src/Winamp/options_title.cpp b/Src/Winamp/options_title.cpp
new file mode 100644
index 00000000..366e3aff
--- /dev/null
+++ b/Src/Winamp/options_title.cpp
@@ -0,0 +1,157 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
+#include "resource.h"
+#include "options.h"
+#include "api.h"
+#include <Wininet.h>
+#include "language.h"
+
+int atf_changed = 0, old_config_useexttitles = 0;
+wchar_t old_config_titlefmt[1024] = {0};
+INT_PTR CALLBACK TitleProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ extern char *g_titlefmt_default;
+ hi helpinfo[]={
+ {IDC_USEID5,IDS_P_O_ONPLAY},
+ {IDC_USEID4,IDS_P_O_ONLOAD},
+ {IDC_USEID3,IDS_P_O_ONDEM},
+ {IDC_CONVERT1,IDS_P_O_CONVERT1},
+ {IDC_CONVERT2,IDS_P_O_CONVERT2},
+ };
+ DO_HELP();
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ atf_changed = 0;
+ link_startsubclass(hwndDlg, IDC_TAGZ_HELP);
+ lstrcpynW(old_config_titlefmt,config_titlefmt,1024);
+ old_config_useexttitles = !!config_useexttitles;
+ SetDlgItemTextW(hwndDlg,IDC_FORMAT,config_titlefmt);
+ CheckDlgButton(hwndDlg,IDC_CHECK1,!!config_useexttitles);
+ CheckDlgButton(hwndDlg,IDC_USEID3,config_riol == 0?1:0);
+ CheckDlgButton(hwndDlg,IDC_USEID4,config_riol == 1?1:0);
+ CheckDlgButton(hwndDlg,IDC_USEID6,(config_riol == 4)?1:0);
+ CheckDlgButton(hwndDlg,IDC_USEID5,(config_riol != 0 && config_riol != 1 && config_riol != 4)?1:0);
+ CheckDlgButton(hwndDlg,IDC_CONVERT1,(config_fixtitles&1)?1:0);
+ CheckDlgButton(hwndDlg,IDC_CONVERT2,(config_fixtitles&2)?1:0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_TAGZ_DEFAULT),config_useexttitles);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FORMAT),config_useexttitles);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ATF_INFO),config_useexttitles);
+ return 0;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHECK1:
+ config_useexttitles=!!IsDlgButtonChecked(hwndDlg,IDC_CHECK1);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_TAGZ_DEFAULT),config_useexttitles);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FORMAT),config_useexttitles);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ATF_INFO),config_useexttitles);
+ break;
+
+ case IDC_TAGZ_HELP:
+ {
+ wchar_t dirmask[MAX_PATH] = {0}, lang_code[4] = {0};
+ lstrcpynW(lang_code, langManager->GetLanguageIdentifier(LANG_LANG_CODE), 3);
+
+ // if we're not using a language pack or it reports en-US then use the default
+ if(!config_langpack[0] || !lang_code[0] || !_wcsicmp(lang_code, L"en"))
+ {
+ GetTempPathW(MAX_PATH, dirmask);
+ PathCombineW(dirmask, dirmask, L"atf.htm");
+ if (!PathFileExistsW(dirmask))
+ {
+ save_local:
+ DWORD size = 0, written = 0;
+ HGLOBAL hResource = langManager->LoadResourceFromFile(hMainInstance, hMainInstance, RT_HTML,MAKEINTRESOURCE(IDR_ATF_HTML), &size);
+
+ HANDLE hFile = CreateFileW(dirmask, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (INVALID_HANDLE_VALUE != hFile)
+ {
+ WriteFile(hFile, hResource, size, &written, NULL);
+ CloseHandle(hFile);
+ }
+ }
+ }
+ else
+ {
+ PathCombineW(dirmask, lang_directory, L"atf.htm");
+ if (!PathFileExistsW(dirmask))
+ {
+ goto save_local;
+ }
+ }
+ myOpenURL(hwndDlg, dirmask);
+ }
+ break;
+
+ case IDC_TAGZ_DEFAULT:
+ StringCchCopyW(config_titlefmt, sizeof(config_titlefmt)/sizeof(*config_titlefmt), L"[%artist% - ]$if2(%title%,$filepart(%filename%))");
+ SetDlgItemTextW(hwndDlg,IDC_FORMAT,config_titlefmt);
+ break;
+
+ case IDC_FORMAT:
+ if (HIWORD(wParam) == EN_CHANGE)
+ {
+ GetDlgItemTextW(hwndDlg,IDC_FORMAT,config_titlefmt, sizeof(config_titlefmt)/sizeof(*config_titlefmt) - 1);
+ config_titlefmt[sizeof(config_titlefmt)/sizeof(*config_titlefmt) - 1]=0;
+ atf_changed = !!lstrcmpW(old_config_titlefmt,config_titlefmt);
+ }
+ break;
+
+ case IDC_CONVERT1:
+ case IDC_CONVERT2:
+ config_fixtitles = (IsDlgButtonChecked(hwndDlg,IDC_CONVERT1)?1:0)|(IsDlgButtonChecked(hwndDlg,IDC_CONVERT2)?2:0);
+ break;
+
+ case IDC_USEID3:
+ case IDC_USEID4:
+ case IDC_USEID5:
+ case IDC_USEID6:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ config_riol = IsDlgButtonChecked(hwndDlg,IDC_USEID4)?1:2;
+ if (config_riol==2) {
+ config_riol = IsDlgButtonChecked(hwndDlg,IDC_USEID3)?0:2;
+ }
+ if (config_riol==2) {
+ config_riol = IsDlgButtonChecked(hwndDlg,IDC_USEID6)?4:2;
+ }
+ }
+ break;
+ }
+ return 0;
+
+ case WM_DESTROY:
+ char titleStr[64] = {0};
+ if(((atf_changed && !!config_useexttitles) || (old_config_useexttitles != config_useexttitles )) &&
+ MessageBoxA(hwndDlg,getString(IDS_ATF_HAS_CHANGED,NULL,0),
+ getString(IDS_REFRESH_PLAYLIST_TITLES,titleStr,64),
+ MB_ICONQUESTION | MB_YESNO) == IDYES)
+ {
+ wchar_t ft[FILETITLE_SIZE] = {0};
+ for (int x = 0; x < PlayList_getlength(); x ++)
+ {
+ if (!PlayList_gethidden(x) && !PlayList_hasanycurtain(x))
+ {
+ wchar_t fn[FILENAME_SIZE] = {0};
+ PlayList_getitem(x, fn, ft);
+ PlayList_setitem(x, fn, PlayList_gettitle(fn, 1));
+ PlayList_setlastlen(x);
+ }
+ }
+ InvalidateRect(hPLWindow, NULL, FALSE);
+ }
+ break;
+ }
+
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/options_video.cpp b/Src/Winamp/options_video.cpp
new file mode 100644
index 00000000..2ffb1bf1
--- /dev/null
+++ b/Src/Winamp/options_video.cpp
@@ -0,0 +1,195 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "WinampAttributes.h"
+#include "Options.h"
+#include "resource.h"
+#include "video.h"
+
+void hideShowVideoOptions(HWND hwndDlg)
+{
+ int ids[] = {IDC_VIDEO_GROUP1, IDC_PREFS_VIDEO_AUTOOPEN, IDC_PREFS_VIDEO_AUTOCLOSE, IDC_PREFS_VIDEO_STOPCLOSE,
+ IDC_PREFS_VIDEO_UPDSIZE, IDC_PREFS_VIDEO_NOSS, IDC_PREFS_VIDEO_LOGO, IDC_VIDEO_GROUP2, IDC_PREFS_VIDEO_AUTO_FS_ON_START,
+ IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP, IDC_PREFS_VIDEO_OSD, IDC_VIDEO_GROUP3, IDC_PREFS_VIDEO_FLIPRGB,
+ IDC_PREFS_VIDEO_ADJASP, IDC_USE_SCREENSHAPE, IDC_SCREENSHAPE1, IDC_STATIC1, IDC_SCREENSHAPE2,
+ IDC_STATIC2, IDC_PREFS_VIDEO_VSYNC};
+ for (int i = 0; i < ARRAYSIZE(ids); i++)
+ {
+ ShowWindow(GetDlgItem(hwndDlg, ids[i]), !g_no_video_loaded);
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_VIDEO_RESTART), !g_no_video_loaded != IsDlgButtonChecked(hwndDlg, IDC_PREFS_VIDEO_ENABLE));
+ if (g_no_video_loaded) ShowWindow(GetDlgItem(hwndDlg, IDC_PREFS_VIDEO_HIDE_PREFS), SW_SHOW);
+}
+
+void hideShowOverlayItems(HWND hwndDlg)
+{
+ int enabled = IsDlgButtonChecked(hwndDlg, IDC_PREFS_VIDEO_OVERLAYS);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PREFS_VIDEO_YV12), enabled);
+}
+
+void hideShowAspectRatioItems(HWND hwndDlg)
+{
+ int enabled = IsDlgButtonChecked(hwndDlg, IDC_PREFS_VIDEO_ADJASP);
+ int subenabled = IsDlgButtonChecked(hwndDlg, IDC_USE_SCREENSHAPE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_USE_SCREENSHAPE), enabled);
+ int ids[] = {IDC_SCREENSHAPE1, IDC_SCREENSHAPE2, IDC_STATIC1, IDC_STATIC2};
+ for (int i = 0; i < ARRAYSIZE(ids); i++)
+ {
+ EnableWindow(GetDlgItem(hwndDlg, ids[i]), enabled && subenabled);
+ }
+}
+
+// video tab procedure
+INT_PTR CALLBACK VideoProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={
+ {IDC_PREFS_VIDEO_ENABLE,IDS_P_O_VIDEO_ENABLE},
+ {IDC_PREFS_VIDEO_HIDE_PREFS,IDS_P_O_VIDEO_HIDE_PREFS},
+ {IDC_PREFS_VIDEO_VSYNC,IDS_P_O_VIDEO_VSYNC},
+ {IDC_PREFS_VIDEO_ADJASP,IDS_P_O_VIDEO_ADJASP},
+ {IDC_PREFS_VIDEO_OVERLAYS,IDS_P_O_VIDEO_OVERLAYS},
+ {IDC_PREFS_VIDEO_UPDSIZE,IDS_P_O_VIDEO_UPDSIZE},
+ {IDC_PREFS_VIDEO_AUTOCLOSE,IDS_P_O_VIDEO_AUTOCLOSE},
+ {IDC_PREFS_VIDEO_NOSS,IDS_P_O_VIDEO_NOSS},
+ {IDC_PREFS_VIDEO_OSD,IDS_P_O_VIDEO_OSD},
+ {IDC_PREFS_VIDEO_YV12,IDS_P_O_VIDEO_YV12},
+ {IDC_PREFS_VIDEO_STOPCLOSE,IDS_P_O_VIDEO_STOPCLOSE},
+ {IDC_PREFS_VIDEO_AUTO_FS_ON_START,IDS_P_O_VIDEO_AUTO_FS_ON_START},
+ {IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP,IDS_P_O_VIDEO_REMOVE_FS_ON_STOP},
+ {IDC_PREFS_VIDEO_AUTOOPEN,IDS_P_O_VIDEO_AUTOOPEN},
+ {IDC_PREFS_VIDEO_FLIPRGB,IDS_P_O_VIDEO_FLIPRGB},
+ };
+ DO_HELP();
+ if (uMsg == WM_INITDIALOG)
+ {
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_ENABLE,!_r_i("no_video", 0));
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_HIDE_PREFS,_r_i("no_video", 0) == 2);
+
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_VSYNC,config_video_vsync2);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_ADJASP,config_video_aspectadj);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_OVERLAYS,config_video_overlays);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_UPDSIZE,config_video_updsize);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_AUTOOPEN,config_video_autoopen);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_AUTOCLOSE,config_video_autoclose);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_NOSS,!!config_video_noss);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_LOGO,!!config_video_logo);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_OSD,config_video_osd);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_YV12,config_video_yv12);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_STOPCLOSE,config_video_stopclose);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_AUTO_FS_ON_START,config_video_auto_fs);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP,config_video_remove_fs_on_stop);
+ CheckDlgButton(hwndDlg,IDC_PREFS_VIDEO_FLIPRGB,config_video_fliprgb);
+ //EnableWindow(GetDlgItem(hwndDlg,IDC_PREFS_VIDEO_YV12),config_video_overlays);
+ if (config_video_useratio) CheckDlgButton(hwndDlg,IDC_USE_SCREENSHAPE,BST_CHECKED);
+ SetDlgItemInt(hwndDlg,IDC_SCREENSHAPE1,config_video_ratio1,FALSE);
+ SetDlgItemInt(hwndDlg,IDC_SCREENSHAPE2,config_video_ratio2,FALSE);
+
+#ifdef EXPERIMENTAL_CONTRAST
+ SendDlgItemMessage(hwndDlg,IDC_PREFS_VIDEO_CONTRAST,TBM_SETRANGE,TRUE,MAKELONG(0,255));
+ SendDlgItemMessage(hwndDlg,IDC_PREFS_VIDEO_CONTRAST,TBM_SETPOS,TRUE,config_video_contrast);
+ SendDlgItemMessage(hwndDlg,IDC_PREFS_VIDEO_BRIGHTNESS,TBM_SETRANGE,TRUE,MAKELONG(0,255));
+ SendDlgItemMessage(hwndDlg,IDC_PREFS_VIDEO_BRIGHTNESS,TBM_SETPOS,TRUE,config_video_brightness);
+#endif
+ hideShowAspectRatioItems(hwndDlg);
+ hideShowOverlayItems(hwndDlg);
+ hideShowVideoOptions(hwndDlg);
+ }
+#ifdef EXPERIMENTAL_CONTRAST
+ if (uMsg == WM_HSCROLL)
+ {
+ HWND swnd = (HWND) lParam;
+ if (swnd == GetDlgItem(hwndDlg, IDC_PREFS_VIDEO_CONTRAST))
+ {
+ config_video_contrast = (unsigned char) SendMessageW(GetDlgItem(hwndDlg,IDC_PREFS_VIDEO_CONTRAST),TBM_GETPOS,0,0);
+ }
+ if (swnd == GetDlgItem(hwndDlg, IDC_PREFS_VIDEO_BRIGHTNESS))
+ {
+ config_video_brightness = (unsigned char) SendMessageW(GetDlgItem(hwndDlg,IDC_PREFS_VIDEO_BRIGHTNESS),TBM_GETPOS,0,0);
+ }
+ }
+#endif
+ if (uMsg == WM_COMMAND) switch (LOWORD(wParam))
+ {
+ case IDC_PREFS_VIDEO_ENABLE:
+ {
+ int val = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_ENABLE)?1:0;
+ if (val == _r_i("no_video", 0))
+ {
+ _w_i("no_video", !val);
+ if (val == g_no_video_loaded &&
+ LPMessageBox(hwndDlg, IDS_P_VIDEO_CHANGE_MSG, IDS_P_VIDEO_CHANGE, MB_YESNO | MB_ICONQUESTION) == IDYES)
+ {
+ PostMessageW(hMainWindow,WM_USER,0,IPC_RESTARTWINAMP);
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_VIDEO_RESTART), !g_no_video_loaded != IsDlgButtonChecked(hwndDlg, IDC_PREFS_VIDEO_ENABLE));
+ }
+ }
+ break;
+ case IDC_PREFS_VIDEO_HIDE_PREFS:
+ {
+ _w_i("no_video", IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_HIDE_PREFS)?2:1);
+ prefsDlgRec t = {0};
+ t._id = 24;
+ prefs_liveDlgRemove(&t);
+ prefs_last_page = 0;
+ prefs_dialog(1);
+ }
+ break;
+ case IDC_PREFS_VIDEO_VSYNC: config_video_vsync2 = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_VSYNC)?1:0; break;
+ case IDC_PREFS_VIDEO_ADJASP: config_video_aspectadj = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_ADJASP)?1:0; hideShowAspectRatioItems(hwndDlg); videoReinit(); break;
+ case IDC_PREFS_VIDEO_OVERLAYS: config_video_overlays = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_OVERLAYS)?1:0; hideShowOverlayItems(hwndDlg); videoReinit(); break;
+ case IDC_PREFS_VIDEO_UPDSIZE: config_video_updsize = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_UPDSIZE)?1:0; break;
+ case IDC_PREFS_VIDEO_AUTOOPEN: config_video_autoopen = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_AUTOOPEN)?1:0; break;
+ case IDC_PREFS_VIDEO_AUTOCLOSE: config_video_autoclose = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_AUTOCLOSE)?1:0; break;
+ case IDC_PREFS_VIDEO_NOSS: config_video_noss = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_NOSS)?1:0; break;
+ case IDC_PREFS_VIDEO_LOGO:
+ {
+ config_video_logo = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_LOGO)?1:0;
+ if (IsWindow(hVideoWindow))
+ {
+ RedrawWindow(hVideoWindow, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN);
+ }
+ break;
+ }
+ case IDC_PREFS_VIDEO_OSD: config_video_osd = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_OSD)?1:0; break;
+ case IDC_PREFS_VIDEO_YV12: config_video_yv12 = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_YV12)?1:0; break;
+ case IDC_PREFS_VIDEO_STOPCLOSE: config_video_stopclose = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_STOPCLOSE)?1:0; break;
+ case IDC_PREFS_VIDEO_AUTO_FS_ON_START: config_video_auto_fs = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_AUTO_FS_ON_START)?1:0; break;
+ case IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP: config_video_remove_fs_on_stop = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP)?1:0; break;
+ case IDC_PREFS_VIDEO_FLIPRGB:
+ {
+ int new_fliprgb = IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_FLIPRGB)?1:0;
+ config_video_fliprgb = 0;
+ videoSetFlip(new_fliprgb);
+ config_video_fliprgb = new_fliprgb;
+ }
+ break;
+ case IDC_USE_SCREENSHAPE:
+ config_video_useratio=!!IsDlgButtonChecked(hwndDlg,IDC_USE_SCREENSHAPE);
+ hideShowAspectRatioItems(hwndDlg);
+ videoReinit();
+ break;
+ case IDC_SCREENSHAPE1:
+ {
+ BOOL t;
+ config_video_ratio1 = GetDlgItemInt(hwndDlg,IDC_SCREENSHAPE1,&t,FALSE);
+ if (!t || !config_video_ratio1) config_video_ratio1=4;
+ if (config_video_useratio) videoReinit();
+ }
+ break;
+ case IDC_SCREENSHAPE2:
+ {
+ BOOL t;
+ config_video_ratio2 = GetDlgItemInt(hwndDlg,IDC_SCREENSHAPE2,&t,FALSE);
+ if (!t || !config_video_ratio2) config_video_ratio2=3;
+ if (config_video_useratio) videoReinit();
+ }
+ break;
+ }
+ return FALSE;
+} //video \ No newline at end of file
diff --git a/Src/Winamp/options_vis.cpp b/Src/Winamp/options_vis.cpp
new file mode 100644
index 00000000..68d8803a
--- /dev/null
+++ b/Src/Winamp/options_vis.cpp
@@ -0,0 +1,434 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "Main.h"
+#include "resource.h"
+#include "Options.h"
+#include "vis.h"
+#include "main.hpp"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+
+static void VisUpdateSel(HWND hwndDlg, HWND listWindow, INT iItem)
+{
+ if (ListView_GetNextItem(listWindow, -1, LVIS_SELECTED) != -1)
+ {
+ wchar_t fn[FILENAME_SIZE] = {0}, b[1024] = {0}, namestr[MAX_PATH] = {0};
+ ListView_GetItemTextW(listWindow, iItem, 1, fn, ARRAYSIZE(fn));
+
+ if (wcscmp(config_visplugin_name, fn))
+ config_visplugin_num = 0;
+
+ StringCchCopyW(config_visplugin_name, MAX_PATH, fn);
+ SendDlgItemMessageA(hwndDlg,IDC_VISMOD,CB_RESETCONTENT,0,0);
+ PathCombineW(b, VISDIR, fn);
+
+ HINSTANCE hLib = LoadLibraryW(b);
+ if (hLib)
+ {
+ winampVisGetHeaderType pr = (winampVisGetHeaderType) GetProcAddress(hLib,"winampVisGetHeader");
+ if (pr)
+ {
+ for(int i = 0;;)
+ {
+ winampVisModule *l_module = pr(hMainWindow)->getModule(i++);
+
+ if (!l_module )
+ break;
+
+ SendDlgItemMessageA(hwndDlg, IDC_VISMOD, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)l_module->description);
+ }
+
+ ListView_DeleteItem(listWindow, iItem);
+
+ StringCchCopyW(namestr, MAX_PATH, AutoWide(pr(hMainWindow)->description));
+ LVITEMW lvi = {LVIF_TEXT, 0, 0};
+ lvi.pszText = namestr;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = fn;
+ ListView_SetItemW(listWindow, &lvi);
+
+ ListView_SetItemState(listWindow, lvi.iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ }
+ FreeModule(hLib);
+ }
+ }
+
+ int count = SendDlgItemMessageA(hwndDlg, IDC_VISMOD, CB_GETCOUNT, 0, 0);
+ SendDlgItemMessageA(hwndDlg, IDC_VISMOD, CB_SETCURSEL, (config_visplugin_num < count ? config_visplugin_num : (config_visplugin_num = 0)), 0);
+}
+
+// vis tab procedure
+static bool pluginsLoaded;
+INT_PTR CALLBACK VisProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ hi helpinfo[]={
+ {IDC_VISLIB,IDS_P_VIS_LIB},
+ {IDC_VISMOD,IDS_P_VIS_MOD},
+ {IDC_VISCONF,IDS_P_VIS_CONF},
+ {IDC_VISSTOP,IDS_P_VIS_STOP},
+ {IDC_VISTEST,IDS_P_VIS_START},
+ {IDC_UNINSTVIS,IDS_P_VIS_UNINST},
+ };
+
+ DO_HELP();
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ pluginsLoaded = false;
+
+ link_startsubclass(hwndDlg, IDC_PLUGINVERS);
+
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_VISLIB);
+ if (IsWindow(listWindow))
+ {
+ RECT r = {0}, rc = {0};
+ GetWindowRect(listWindow, &r);
+ GetClientRect(listWindow, &r);
+ MapWindowPoints(listWindow, hwndDlg, (LPPOINT)&r, 2);
+ InflateRect(&r, 2, 2);
+ DestroyWindow(listWindow);
+ listWindow = CreateWindowExW(WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, WC_LISTVIEWW, L"",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL |
+ LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER,
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ hwndDlg, (HMENU)IDC_VISLIB, NULL, NULL);
+ SetWindowPos(listWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+ ListView_SetExtendedListViewStyleEx(listWindow, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+ SendMessageW(listWindow, WM_SETFONT, SendMessageW(hwndDlg, WM_GETFONT, 0, 0), FALSE);
+
+ LVCOLUMNW lvc = {0};
+ ListView_InsertColumnW(listWindow, 0, &lvc);
+ ListView_InsertColumnW(listWindow, 1, &lvc);
+
+
+ WIN32_FIND_DATAW d = {0};
+ wchar_t dirstr[MAX_PATH+128] = {0};
+ PathCombineW(dirstr,VISDIR,L"*.DLL");
+ HANDLE h = FindFirstFileW(dirstr,&d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (_wcsnicmp(d.cFileName,L"dsp_",4)
+ && _wcsnicmp(d.cFileName,L"in_",3)
+ && _wcsnicmp(d.cFileName,L"gen_",4)
+ && _wcsnicmp(d.cFileName,L"ml_",3)
+ && _wcsnicmp(d.cFileName,L"enc_",4)
+ && _wcsnicmp(d.cFileName,L"CDDB",4)
+ && _wcsnicmp(d.cFileName,L"out_",4)
+ && _wcsnicmp(d.cFileName, L"pmp_", 4))
+ {
+ wchar_t b[1024] = {0}, namestr[MAX_PATH] = {0};
+ PathCombineW(b, VISDIR, d.cFileName);
+ HINSTANCE hLib = LoadLibrary(b);
+ if (hLib)
+ {
+ winampVisGetHeaderType pr = (winampVisGetHeaderType) GetProcAddress(hLib,"winampVisGetHeader");
+ if (pr)
+ {
+ if (!g_safeMode)
+ {
+ winampVisHeader* pv = pr(hMainWindow);
+ if (pv)
+ {
+ StringCchCopyW(namestr,MAX_PATH+256,AutoWide(pv->description));
+ }
+ else
+ {
+ StringCchCopyW(namestr,MAX_PATH+256,L"!");
+ }
+ }
+ }
+ else
+ {
+ StringCchCopyW(namestr,MAX_PATH+256,L"!");
+ }
+ FreeModule(hLib);
+ }
+ else
+ {
+ StringCchCopyW(namestr,MAX_PATH+256,L"!");
+ }
+
+ if (wcscmp(namestr,L"!"))
+ {
+ LVITEMW lvi = {LVIF_TEXT, 0, 0};
+ lvi.pszText = namestr;
+ lvi.iItem = ListView_InsertItemW(listWindow, &lvi);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = d.cFileName;
+ ListView_SetItemW(listWindow, &lvi);
+
+ if (!_wcsicmp(d.cFileName, config_visplugin_name))
+ {
+ ListView_SetItemState(listWindow, lvi.iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ VisUpdateSel(hwndDlg, listWindow, lvi.iItem);
+ }
+ }
+ }
+ } while (FindNextFileW(h,&d));
+
+ FindClose(h);
+ }
+
+ // [5.55+] only send this to correct the page state if we have no valid vis plugins available and loaded
+ if(!ListView_GetItemCount(listWindow) ||
+ (ListView_GetNextItem(listWindow, -1, LVIS_SELECTED) == -1) ||
+ g_safeMode || !config_visplugin_name[0])
+ {
+ VisUpdateSel(hwndDlg, listWindow, -1);
+
+ int enable = (ListView_GetSelectionMark(listWindow) != -1);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISTEST),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISSTOP),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISCONF),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UNINSTVIS),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISMOD),enable);
+ }
+
+ GetClientRect(listWindow, &r);
+ ListView_SetColumnWidth(listWindow, 1, LVSCW_AUTOSIZE);
+ ListView_SetColumnWidth(listWindow, 0, (r.right - r.left) - ListView_GetColumnWidth(listWindow, 1));
+
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, TRUE);
+
+ pluginsLoaded = true;
+ }
+ }
+ else if (uMsg == WM_DESTROY)
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_VISLIB);
+ if (IsWindow(listWindow))
+ DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE);
+ }
+ else if (uMsg == WM_NOTIFY)
+ {
+ static int own_update;
+ LPNMHDR p = (LPNMHDR)lParam;
+ if (p->idFrom == IDC_VISLIB)
+ {
+ if (p->code == LVN_ITEMCHANGED && pluginsLoaded && !own_update)
+ {
+ if (!g_safeMode)
+ {
+ LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+ LVITEM lvi = {LVIF_PARAM, pnmv->iItem};
+ if (ListView_GetItem(p->hwndFrom, &lvi) && (pnmv->uNewState & LVIS_SELECTED))
+ {
+ own_update = 1;
+ VisUpdateSel(hwndDlg, p->hwndFrom, pnmv->iItem);
+ own_update = 0;
+ }
+ }
+
+ int enable = (ListView_GetSelectionMark(p->hwndFrom) != -1);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISTEST),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISSTOP),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISCONF),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UNINSTVIS),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_VISMOD),enable);
+ }
+ else if (p->code == NM_DBLCLK || p->code == NM_CLICK)
+ {
+ // helps to keep the selection on things...
+ LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
+ if (lpnmitem->iItem == -1)
+ {
+ int which = ListView_GetNextItem(p->hwndFrom, -1, LVIS_SELECTED);
+ if (which == -1)
+ {
+ for (int i = 0; i < ListView_GetItemCount(p->hwndFrom); i++)
+ {
+ wchar_t fn[MAX_PATH*2] = {0};
+ ListView_GetItemTextW(p->hwndFrom, i, 1, fn, ARRAYSIZE(fn));
+
+ if (!_wcsicmp(fn, config_visplugin_name))
+ {
+ ListView_SetItemState(p->hwndFrom, i, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ break;
+ }
+ }
+ }
+ else ListView_SetItemState(p->hwndFrom, which, LVIS_SELECTED, LVIS_SELECTED);
+ }
+
+ if (p->code == NM_DBLCLK)
+ {
+ PostMessageW(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_VISTEST, 0), (LPARAM)GetDlgItem(hwndDlg, IDC_VISTEST));
+ }
+ }
+ }
+ else if (p->code == HDN_ITEMCHANGINGW)
+ {
+ if (pluginsLoaded)
+ {
+#ifdef WIN64
+ SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
+#else
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
+#endif
+ return TRUE;
+ }
+ }
+ }
+ else if (uMsg == WM_COMMAND)
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_VISMOD:
+ if (HIWORD(wParam) == CBN_SELCHANGE)
+ {
+ config_visplugin_num = (unsigned char) SendDlgItemMessageA(hwndDlg,IDC_VISMOD,CB_GETCURSEL,0,0);
+
+ if (config_visplugin_num == CB_ERR)
+ config_visplugin_num = 0;
+ }
+ return FALSE;
+
+ case IDC_VISCONF:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_VISCONF)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_VISLIB);
+ int which = ListView_GetNextItem(listWindow, -1, LVIS_SELECTED);
+ if (which >= 0 && which < ListView_GetItemCount(listWindow))
+ {
+ wchar_t b[MAX_PATH] = {0}, fn[MAX_PATH*2] = {0};
+ ListView_GetItemTextW(listWindow, which, 1, fn, ARRAYSIZE(fn));
+
+ PathCombineW(b, VISDIR, fn);
+ HINSTANCE hLib = LoadLibraryW(b);
+ if (hLib)
+ {
+ winampVisGetHeaderType pr = (winampVisGetHeaderType) GetProcAddress(hLib,"winampVisGetHeader");
+ winampVisModule *module = pr(hMainWindow)->getModule(SendDlgItemMessageA(hwndDlg,IDC_VISMOD,CB_GETCURSEL,0,0));
+ if (module)
+ {
+ module->hDllInstance = hLib;
+ module->hwndParent = hMainWindow;
+ if (!(config_no_visseh&1))
+ {
+ try {
+ module->Config(module);
+ }
+ catch(...)
+ {
+ LPMessageBox(hwndDlg, IDS_PLUGINERROR, IDS_ERROR, MB_OK|MB_ICONEXCLAMATION);
+ }
+ }
+ else
+ {
+ module->Config(module);
+ }
+ }
+ else
+ {
+ LPMessageBox(hwndDlg, IDS_ERRORLOADINGPLUGIN, IDS_ERROR, MB_OK);
+ }
+ FreeLibrary(hLib);
+ }
+ else
+ {
+ LPMessageBox(hwndDlg, IDS_ERRORLOADINGPLUGIN, IDS_ERROR, MB_OK);
+ }
+ }
+ }
+ }
+ return FALSE;
+
+ case IDC_VISSTOP:
+ {
+ vis_stop();
+ }
+ return FALSE;
+
+ case IDC_VISTEST:
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_VISTEST)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_VISLIB);
+ int which = ListView_GetNextItem(listWindow, -1, LVIS_SELECTED);
+ if (which >= 0 && which < ListView_GetItemCount(listWindow))
+ {
+ wchar_t fn[MAX_PATH] = {0};
+ ListView_GetItemTextW(listWindow, which, 1, fn, ARRAYSIZE(fn));
+ StringCchCopyW(config_visplugin_name, MAX_PATH, fn);
+ config_visplugin_num = (unsigned char)SendDlgItemMessageA(hwndDlg, IDC_VISMOD, CB_GETCURSEL, 0, 0);
+ }
+ }
+
+ vis_start(hMainWindow,NULL);
+ }
+ return FALSE;
+
+ case IDC_UNINSTVIS:
+ vis_stop();
+ {
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_UNINSTVIS)))
+ {
+ HWND listWindow = GetDlgItem(hwndDlg, IDC_VISLIB);
+ int which = ListView_GetNextItem(listWindow, -1, LVIS_SELECTED);
+ wchar_t b[MAX_PATH] = {0}, fn[FILENAME_SIZE] = {0};
+ ListView_GetItemTextW(listWindow, which, 1, fn, ARRAYSIZE(fn));
+ PathCombineW(b, VISDIR, fn);
+
+ HINSTANCE hLib = LoadLibraryW(b);
+ if (hLib)
+ {
+ wchar_t buf[MAX_PATH] = {0};
+ GetModuleFileNameW(hLib, buf, MAX_PATH);
+ int ret=0;
+
+ int (*pr)
+ (HINSTANCE hDllInst, HWND hwndDlg, int param);
+
+ *(void**)&pr = (void*)GetProcAddress(hLib,"winampUninstallPlugin");
+
+ if (pr)
+ ret=pr(hLib,hwndDlg,0);
+
+ FreeLibrary(hLib);
+
+ if (!ret)
+ {
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ if (registrar->DeleteItem(buf) != S_OK)
+ {
+ _w_sW("remove_genplug", buf);
+ _w_i("show_prefs", 33);
+ PostMessageW(hMainWindow, WM_USER, 0, IPC_RESTARTWINAMP);
+ }
+ else
+ ListView_DeleteItem(listWindow, which);
+
+ registrar->Release();
+ }
+
+ SendDlgItemMessageA(hwndDlg,IDC_VISMOD,CB_RESETCONTENT,0,0);
+ }
+ }
+ }
+ }
+ return FALSE;
+
+ case IDC_PLUGINVERS:
+ myOpenURLWithFallback(hwndDlg, L"http://www.google.com/search?q=Winamp+Visualization+Plugins", L"http://www.google.com/search?q=Winamp+Visualization+Plugins");
+ return TRUE;
+ }
+ }
+
+ link_handledraw(hwndDlg,uMsg,wParam,lParam);
+ return FALSE;
+} //vis \ No newline at end of file
diff --git a/Src/Winamp/paths.cpp b/Src/Winamp/paths.cpp
new file mode 100644
index 00000000..1bb9101a
--- /dev/null
+++ b/Src/Winamp/paths.cpp
@@ -0,0 +1,164 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+#include <shlobj.h>
+#include <shellapi.h>
+#include "../Winamp/in2.h"
+extern In_Module mod;
+#ifdef __cplusplus
+extern "C" BOOL UtilGetSpecialFolderPath(HWND hwnd, TCHAR *path, int folder)
+#else
+BOOL UtilGetSpecialFolderPath(HWND hwnd, TCHAR *path, int folder)
+#endif
+{
+ ITEMIDLIST *pidl; // Shell Item ID List ptr
+ IMalloc *imalloc; // Shell IMalloc interface ptr
+ BOOL result; // Return value
+
+ if (SHGetSpecialFolderLocation(hwnd, folder, &pidl) != NOERROR)
+ return FALSE;
+
+ result = SHGetPathFromIDList (pidl, path);
+
+ if (SHGetMalloc (&imalloc) == NOERROR)
+ {
+#ifdef __cplusplus
+ imalloc->Free(pidl);
+ imalloc->Release();
+#else
+ imalloc->lpVtbl->Free(imalloc, pidl);
+ imalloc->lpVtbl->Release(imalloc);
+#endif
+ }
+
+ return result;
+}
+
+
+/*
+This ugly function converts our specially coded paths
+environment variables are surrounded with %'s and CSIDLs are surrounded with {}
+note that CSIDLs need to be DECIMAL!
+*/
+#ifdef __cplusplus
+extern "C" void ResolveEnvironmentVariables2(wchar_t *string, wchar_t *destString, size_t stringSize)
+#else
+void ResolveEnvironmentVariables2(TCHAR *string, TCHAR *destString, size_t stringSize)
+#endif
+{
+ //char *saveStart = string;
+ wchar_t *p = string;
+ int inPercent = 0, inBrace = 0;
+ wchar_t environString[MAX_PATH] = {0};
+ wchar_t *dest = destString;
+ wchar_t helper[MAX_PATH] = {0};
+ wchar_t *pEnv = environString;
+
+ *dest = 0;
+
+ while (p && *p)
+ {
+ if (*p == L'%')
+ {
+ if (inPercent)
+ {
+ *pEnv = 0;
+ helper[0] = 0;
+ GetEnvironmentVariableW(environString, helper, MAX_PATH);
+ StringCchCatW(dest, stringSize, helper);
+ pEnv = environString;
+ string = CharNextW(p);
+ *p = 0;
+ p = string;
+ }
+ else
+ {
+ wchar_t *newP = CharNextW(p);
+ *p = 0;
+ StringCchCatW(dest, stringSize, string);
+ string = p = newP;
+ }
+
+ inPercent = !inPercent;
+ }
+ else if (*p == L'{')
+ {
+ if (inPercent)
+ {
+ ptrdiff_t count = CharNextW(p) - p;
+ while (count-- && (pEnv - environString) < MAX_PATH)
+ *pEnv++ = *p++;
+ }
+ else
+ {
+ wchar_t *newP = CharNextW(p);
+ *p = 0;
+ StringCchCatW(dest, stringSize, string);
+ string = p = newP;
+ inBrace = 1;
+ }
+ }
+ else if (*p == L'}')
+ {
+ if (inPercent)
+ {
+ ptrdiff_t count = CharNextW(p) - p;
+ while (count-- && (pEnv - environString) < MAX_PATH)
+ *pEnv++ = *p++;
+ }
+ *pEnv = 0;
+ //SHGetSpecialFolderPath(NULL, helper, atoi(environString), FALSE);
+#if defined(UNICODE) || defined(_UNICODE)
+ SHGetSpecialFolderPath(NULL, helper, StrToInt(environString), FALSE);
+ //UtilGetSpecialFolderPath(NULL, helper, _wtoi(environString));
+#else
+ SHGetSpecialFolderPathW(NULL, helper, StrToIntW(environString), FALSE);
+ //UtilGetSpecialFolderPath(NULL, helper, _aoi(environString));
+#endif
+ StringCchCatW(dest, stringSize, helper);
+ pEnv = environString;
+ string = CharNextW(p);
+ *p = 0;
+ p = string;
+ inBrace = 0;
+ }
+ else
+ {
+ if (inPercent || inBrace)
+ {
+ ptrdiff_t count = CharNextW(p) - p;
+ while (count-- && (pEnv - environString) < MAX_PATH)
+ *pEnv++ = *p++;
+ }
+ else
+ p = CharNextW(p);
+ }
+ }
+
+ StringCchCatW(dest, stringSize, string);
+}
+
+#ifndef NO_INPLACE_RESOLVE
+#include <malloc.h>
+// call this function if you want to modify in-place
+#include "main.h"
+
+#ifdef __cplusplus
+extern "C" void ResolveEnvironmentVariables(wchar_t *string, size_t stringSize) //
+#else
+void ResolveEnvironmentVariables(wchar_t *string, size_t stringSize) //
+#endif
+{
+ wchar_t *dest = (wchar_t *) alloca(stringSize * sizeof(dest[0]));
+ ResolveEnvironmentVariables2(string, dest, stringSize);
+ StringCchCopyW(string, stringSize, dest);
+}
+#endif \ No newline at end of file
diff --git a/Src/Winamp/plush/CAM.C b/Src/Winamp/plush/CAM.C
new file mode 100644
index 00000000..3d122a13
--- /dev/null
+++ b/Src/Winamp/plush/CAM.C
@@ -0,0 +1,52 @@
+/******************************************************************************
+Plush Version 1.2
+cam.c
+Camera Control
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+void plCamDelete(pl_Cam *c) {
+ if (c) free(c);
+}
+
+void plCamSetTarget(pl_Cam *c, pl_Float x, pl_Float y, pl_Float z) {
+ double dx, dy, dz;
+ dx = x - c->X;
+ dy = y - c->Y;
+ dz = z - c->Z;
+ c->Roll = 0;
+ if (dz > 0.0001f) {
+ c->Pan = (pl_Float) (-atan(dx/dz)*(180.0/PL_PI));
+ dz /= cos(c->Pan*(PL_PI/180.0));
+ c->Pitch = (pl_Float) (atan(dy/dz)*(180.0/PL_PI));
+ } else if (dz < -0.0001f) {
+ c->Pan = (pl_Float) (180.0-atan(dx/dz)*(180.0/PL_PI));
+ dz /= cos((c->Pan-180.0f)*(PL_PI/180.0));
+ c->Pitch = (pl_Float) (-atan(dy/dz)*(180.0/PL_PI));
+ } else {
+ c->Pan = 0.0f;
+ c->Pitch = -90.0f;
+ }
+}
+
+pl_Cam *plCamCreate(pl_uInt sw, pl_uInt sh, pl_Float ar, pl_Float fov,
+ pl_uChar *fb, pl_ZBuffer *zb) {
+ pl_Cam *c;
+ c = malloc(sizeof(pl_Cam));
+ if (!c) return 0;
+ memset(c,0,sizeof(pl_Cam));
+ c->Fov = fov;
+ c->AspectRatio = ar;
+ c->ClipRight = c->ScreenWidth = sw;
+ c->ClipBottom = c->ScreenHeight = sh;
+ c->CenterX = sw>>1;
+ c->CenterY = sh>>1;
+ c->ClipBack = 8.0e30f;
+ c->frameBuffer = fb;
+ c->zBuffer = zb;
+ c->Sort = 1;
+ if (zb) c->Sort = 0;
+ return (c);
+}
diff --git a/Src/Winamp/plush/CLIP.C b/Src/Winamp/plush/CLIP.C
new file mode 100644
index 00000000..5cbd06fe
--- /dev/null
+++ b/Src/Winamp/plush/CLIP.C
@@ -0,0 +1,255 @@
+/******************************************************************************
+Plush Version 1.2
+clip.c
+3D Frustum Clipping
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+#define NUM_CLIP_PLANES 5
+
+typedef struct
+{
+ pl_Vertex newVertices[8];
+ double Shades[8];
+ double MappingU[8];
+ double MappingV[8];
+ double eMappingU[8];
+ double eMappingV[8];
+} _clipInfo;
+
+
+static _clipInfo m_cl[2];
+
+
+static double m_clipPlanes[NUM_CLIP_PLANES][4];
+static pl_Cam *m_cam;
+static pl_sInt32 m_cx, m_cy;
+static double m_fov;
+static double m_adj_asp;
+
+static void _FindNormal(double x2, double x3,
+ double y2, double y3,
+ double zv,
+ double *res);
+
+ /* Returns: 0 if nothing gets in, 1 or 2 if pout1 & pout2 get in */
+static pl_uInt _ClipToPlane(pl_uInt numVerts, double *plane);
+
+void plClipSetFrustum(pl_Cam *cam) {
+ m_adj_asp = 1.0 / cam->AspectRatio;
+ m_fov = plMin(plMax(cam->Fov,1.0),179.0);
+ m_fov = (1.0/tan(m_fov*(PL_PI/360.0)))*(double) (cam->ClipRight-cam->ClipLeft);
+ m_cx = cam->CenterX<<20;
+ m_cy = cam->CenterY<<20;
+ m_cam = cam;
+ memset(m_clipPlanes,0,sizeof(m_clipPlanes));
+
+ /* Back */
+ m_clipPlanes[0][2] = -1.0;
+ m_clipPlanes[0][3] = -cam->ClipBack;
+
+ /* Left */
+ m_clipPlanes[1][3] = 0.00000001;
+ if (cam->ClipLeft == cam->CenterX) {
+ m_clipPlanes[1][0] = 1.0;
+ }
+ else _FindNormal(-100,-100,
+ 100, -100,
+ m_fov*-100.0/(cam->ClipLeft-cam->CenterX),
+ m_clipPlanes[1]);
+ if (cam->ClipLeft > cam->CenterX) {
+ m_clipPlanes[1][0] = -m_clipPlanes[1][0];
+ m_clipPlanes[1][1] = -m_clipPlanes[1][1];
+ m_clipPlanes[1][2] = -m_clipPlanes[1][2];
+ }
+
+ /* Right */
+ m_clipPlanes[2][3] = 0.00000001;
+ if (cam->ClipRight == cam->CenterX) {
+ m_clipPlanes[2][0] = -1.0;
+ }
+ else _FindNormal(100,100,
+ -100, 100,
+ m_fov*100.0/(cam->ClipRight-cam->CenterX),
+ m_clipPlanes[2]);
+ if (cam->ClipRight < cam->CenterX) {
+ m_clipPlanes[2][0] = -m_clipPlanes[2][0];
+ m_clipPlanes[2][1] = -m_clipPlanes[2][1];
+ m_clipPlanes[2][2] = -m_clipPlanes[2][2];
+ }
+ /* Top */
+ m_clipPlanes[3][3] = 0.00000001;
+ if (cam->ClipTop == cam->CenterY) {
+ m_clipPlanes[3][1] = -1.0;
+ } else _FindNormal(100, -100,
+ 100, 100,
+ m_fov*m_adj_asp*100.0/(cam->CenterY-cam->ClipTop),
+ m_clipPlanes[3]);
+ if (cam->ClipTop > cam->CenterY) {
+ m_clipPlanes[3][0] = -m_clipPlanes[3][0];
+ m_clipPlanes[3][1] = -m_clipPlanes[3][1];
+ m_clipPlanes[3][2] = -m_clipPlanes[3][2];
+ }
+
+ /* Bottom */
+ m_clipPlanes[4][3] = 0.00000001;
+ if (cam->ClipBottom == cam->CenterY) {
+ m_clipPlanes[4][1] = 1.0;
+ } else _FindNormal(-100, 100,
+ -100, -100,
+ m_fov*m_adj_asp*-100.0/(cam->CenterY-cam->ClipBottom),
+ m_clipPlanes[4]);
+ if (cam->ClipBottom < cam->CenterY) {
+ m_clipPlanes[4][0] = -m_clipPlanes[4][0];
+ m_clipPlanes[4][1] = -m_clipPlanes[4][1];
+ m_clipPlanes[4][2] = -m_clipPlanes[4][2];
+ }
+}
+
+
+void plClipRenderFace(pl_Face *face) {
+ pl_uInt k, a, w, numVerts, q;
+ double tmp, tmp2;
+ pl_Face newface;
+
+ for (a = 0; a < 3; a ++) {
+ m_cl[0].newVertices[a] = *(face->Vertices[a]);
+ m_cl[0].Shades[a] = face->Shades[a];
+ m_cl[0].MappingU[a] = face->MappingU[a];
+ m_cl[0].MappingV[a] = face->MappingV[a];
+ m_cl[0].eMappingU[a] = face->eMappingU[a];
+ m_cl[0].eMappingV[a] = face->eMappingV[a];
+ }
+
+ numVerts = 3;
+ q = 0;
+ a = (m_clipPlanes[0][3] < 0.0 ? 0 : 1);
+ while (a < NUM_CLIP_PLANES && numVerts > 2)
+ {
+ numVerts = _ClipToPlane(numVerts, m_clipPlanes[a]);
+ memcpy(&m_cl[0],&m_cl[1],sizeof(m_cl)/2);
+ a++;
+ }
+ if (numVerts > 2) {
+ memcpy(&newface,face,sizeof(pl_Face));
+ for (k = 2; k < numVerts; k ++) {
+ newface.fShade = plMax(0,plMin(face->fShade,1));
+ for (a = 0; a < 3; a ++) {
+ if (a == 0) w = 0;
+ else w = a+(k-2);
+ newface.Vertices[a] = m_cl[0].newVertices+w;
+ newface.Shades[a] = (pl_Float) m_cl[0].Shades[w];
+ newface.MappingU[a] = (pl_sInt32)m_cl[0].MappingU[w];
+ newface.MappingV[a] = (pl_sInt32)m_cl[0].MappingV[w];
+ newface.eMappingU[a] = (pl_sInt32)m_cl[0].eMappingU[w];
+ newface.eMappingV[a] = (pl_sInt32)m_cl[0].eMappingV[w];
+ newface.Scrz[a] = 1.0f/newface.Vertices[a]->xformedz;
+ tmp2 = m_fov * newface.Scrz[a];
+ tmp = tmp2*newface.Vertices[a]->xformedx;
+ tmp2 *= newface.Vertices[a]->xformedy;
+ newface.Scrx[a] = m_cx + ((pl_sInt32)((tmp*(float) (1<<20))));
+ newface.Scry[a] = m_cy - ((pl_sInt32)((tmp2*m_adj_asp*(float) (1<<20))));
+ }
+ newface.Material->_PutFace(m_cam,&newface);
+ plRender_TriStats[3] ++;
+ }
+ plRender_TriStats[2] ++;
+ }
+}
+
+pl_sInt plClipNeeded(pl_Face *face) {
+ double dr,dl,db,dt;
+ double f;
+ dr = (m_cam->ClipRight-m_cam->CenterX);
+ dl = (m_cam->ClipLeft-m_cam->CenterX);
+ db = (m_cam->ClipBottom-m_cam->CenterY);
+ dt = (m_cam->ClipTop-m_cam->CenterY);
+ f = m_fov*m_adj_asp;
+ return ((m_cam->ClipBack <= 0.0 ||
+ face->Vertices[0]->xformedz <= m_cam->ClipBack ||
+ face->Vertices[1]->xformedz <= m_cam->ClipBack ||
+ face->Vertices[2]->xformedz <= m_cam->ClipBack) &&
+ (face->Vertices[0]->xformedz >= 0 ||
+ face->Vertices[1]->xformedz >= 0 ||
+ face->Vertices[2]->xformedz >= 0) &&
+ (face->Vertices[0]->xformedx*m_fov<=dr*face->Vertices[0]->xformedz ||
+ face->Vertices[1]->xformedx*m_fov<=dr*face->Vertices[1]->xformedz ||
+ face->Vertices[2]->xformedx*m_fov<=dr*face->Vertices[2]->xformedz) &&
+ (face->Vertices[0]->xformedx*m_fov>=dl*face->Vertices[0]->xformedz ||
+ face->Vertices[1]->xformedx*m_fov>=dl*face->Vertices[1]->xformedz ||
+ face->Vertices[2]->xformedx*m_fov>=dl*face->Vertices[2]->xformedz) &&
+ (face->Vertices[0]->xformedy*f<=db*face->Vertices[0]->xformedz ||
+ face->Vertices[1]->xformedy*f<=db*face->Vertices[1]->xformedz ||
+ face->Vertices[2]->xformedy*f<=db*face->Vertices[2]->xformedz) &&
+ (face->Vertices[0]->xformedy*f>=dt*face->Vertices[0]->xformedz ||
+ face->Vertices[1]->xformedy*f>=dt*face->Vertices[1]->xformedz ||
+ face->Vertices[2]->xformedy*f>=dt*face->Vertices[2]->xformedz));
+}
+
+
+
+static void _FindNormal(double x2, double x3,double y2, double y3,
+ double zv, double *res) {
+ res[0] = zv*(y2-y3);
+ res[1] = zv*(x3-x2);
+ res[2] = x2*y3 - y2*x3;
+}
+
+ /* Returns: 0 if nothing gets in, 1 or 2 if pout1 & pout2 get in */
+static pl_uInt _ClipToPlane(pl_uInt numVerts, double *plane)
+{
+ pl_uInt i, nextvert, curin, nextin;
+ double curdot, nextdot, scale;
+ pl_uInt invert, outvert;
+ invert = 0;
+ outvert = 0;
+ curdot = m_cl[0].newVertices[0].xformedx*plane[0] +
+ m_cl[0].newVertices[0].xformedy*plane[1] +
+ m_cl[0].newVertices[0].xformedz*plane[2];
+ curin = (curdot >= plane[3]);
+
+ for (i=0 ; i < numVerts; i++) {
+ nextvert = (i + 1) % numVerts;
+ if (curin) {
+ m_cl[1].Shades[outvert] = m_cl[0].Shades[invert];
+ m_cl[1].MappingU[outvert] = m_cl[0].MappingU[invert];
+ m_cl[1].MappingV[outvert] = m_cl[0].MappingV[invert];
+ m_cl[1].eMappingU[outvert] = m_cl[0].eMappingU[invert];
+ m_cl[1].eMappingV[outvert] = m_cl[0].eMappingV[invert];
+ m_cl[1].newVertices[outvert++] = m_cl[0].newVertices[invert];
+ }
+ nextdot = m_cl[0].newVertices[nextvert].xformedx*plane[0] +
+ m_cl[0].newVertices[nextvert].xformedy*plane[1] +
+ m_cl[0].newVertices[nextvert].xformedz*plane[2];
+ nextin = (nextdot >= plane[3]);
+ if (curin != nextin) {
+ scale = (plane[3] - curdot) / (nextdot - curdot);
+ m_cl[1].newVertices[outvert].xformedx = (pl_Float) (m_cl[0].newVertices[invert].xformedx +
+ (m_cl[0].newVertices[nextvert].xformedx - m_cl[0].newVertices[invert].xformedx)
+ * scale);
+ m_cl[1].newVertices[outvert].xformedy = (pl_Float) (m_cl[0].newVertices[invert].xformedy +
+ (m_cl[0].newVertices[nextvert].xformedy - m_cl[0].newVertices[invert].xformedy)
+ * scale);
+ m_cl[1].newVertices[outvert].xformedz = (pl_Float) (m_cl[0].newVertices[invert].xformedz +
+ (m_cl[0].newVertices[nextvert].xformedz - m_cl[0].newVertices[invert].xformedz)
+ * scale);
+ m_cl[1].Shades[outvert] = m_cl[0].Shades[invert] +
+ (m_cl[0].Shades[nextvert] - m_cl[0].Shades[invert]) * scale;
+ m_cl[1].MappingU[outvert] = m_cl[0].MappingU[invert] +
+ (m_cl[0].MappingU[nextvert] - m_cl[0].MappingU[invert]) * scale;
+ m_cl[1].MappingV[outvert] = m_cl[0].MappingV[invert] +
+ (m_cl[0].MappingV[nextvert] - m_cl[0].MappingV[invert]) * scale;
+ m_cl[1].eMappingU[outvert] = m_cl[0].eMappingU[invert] +
+ (m_cl[0].eMappingU[nextvert] - m_cl[0].eMappingU[invert]) * scale;
+ m_cl[1].eMappingV[outvert] = m_cl[0].eMappingV[invert] +
+ (m_cl[0].eMappingV[nextvert] - m_cl[0].eMappingV[invert]) * scale;
+ outvert++;
+ }
+ curdot = nextdot;
+ curin = nextin;
+ invert++;
+ }
+ return outvert;
+}
diff --git a/Src/Winamp/plush/LIGHT.C b/Src/Winamp/plush/LIGHT.C
new file mode 100644
index 00000000..69f3b79a
--- /dev/null
+++ b/Src/Winamp/plush/LIGHT.C
@@ -0,0 +1,46 @@
+/******************************************************************************
+Plush Version 1.2
+light.c
+Light Control
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+pl_Light *plLightSet(pl_Light *light, pl_uChar mode, pl_Float x, pl_Float y,
+ pl_Float z, pl_Float intensity, pl_Float halfDist) {
+ pl_Float m[16], m2[16];
+ light->Type = mode;
+ light->Intensity = intensity;
+ light->HalfDistSquared = halfDist*halfDist;
+ switch (mode) {
+ case PL_LIGHT_VECTOR:
+ plMatrixRotate(m,1,x);
+ plMatrixRotate(m2,2,y);
+ plMatrixMultiply(m,m2);
+ plMatrixRotate(m2,3,z);
+ plMatrixMultiply(m,m2);
+ plMatrixApply(m,0.0,0.0,-1.0,&light->Xp, &light->Yp, &light->Zp);
+ break;
+ case PL_LIGHT_POINT_ANGLE:
+ case PL_LIGHT_POINT_DISTANCE:
+ case PL_LIGHT_POINT:
+ light->Xp = x;
+ light->Yp = y;
+ light->Zp = z;
+ break;
+ }
+ return light;
+}
+
+pl_Light *plLightCreate() {
+ pl_Light *l;
+ l = malloc(sizeof(pl_Light));
+ if (!l) return 0;
+ memset(l,0,sizeof(pl_Light));
+ return (l);
+}
+
+void plLightDelete(pl_Light *l) {
+ if (l) free(l);
+}
diff --git a/Src/Winamp/plush/MAKE.C b/Src/Winamp/plush/MAKE.C
new file mode 100644
index 00000000..9f59a1c2
--- /dev/null
+++ b/Src/Winamp/plush/MAKE.C
@@ -0,0 +1,480 @@
+/******************************************************************************
+Plush Version 1.2
+make.c
+Object Primitives
+Copyright (c) 1996-2000, Justin Frankel
+*******************************************************************************
+ Notes:
+ Most of these routines are highly unoptimized.
+ They could all use some work, such as more capable divisions (Box is
+ most notable), etc... The mapping coordinates are all set up nicely,
+ though.
+******************************************************************************/
+
+#include "plush.h"
+
+pl_Obj *plMakeTorus(pl_Float r1, pl_Float r2, pl_uInt divrot, pl_uInt divrad,
+ pl_Mat *m) {
+ pl_Obj *o;
+ pl_Vertex *v;
+ pl_Face *f;
+ pl_uInt x, y;
+ double ravg, rt, a, da, al, dal;
+ pl_sInt32 U,V,dU,dV;
+ if (divrot < 3) divrot = 3;
+ if (divrad < 3) divrad = 3;
+ ravg = (r1+r2)*0.5;
+ rt = (r2-r1)*0.5;
+ o = plObjCreate(divrad*divrot,divrad*divrot*2);
+ if (!o) return 0;
+ v = o->Vertices;
+ a = 0.0;
+ da = 2*PL_PI/divrot;
+ for (y = 0; y < divrot; y ++) {
+ al = 0.0;
+ dal = 2*PL_PI/divrad;
+ for (x = 0; x < divrad; x ++) {
+ v->x = (pl_Float) (cos((double) a)*(ravg + cos((double) al)*rt));
+ v->z = (pl_Float) (sin((double) a)*(ravg + cos((double) al)*rt));
+ v->y = (pl_Float) (sin((double) al)*rt);
+ v++;
+ al += dal;
+ }
+ a += da;
+ }
+ v = o->Vertices;
+ f = o->Faces;
+ dV = 65535/divrad;
+ dU = 65535/divrot;
+ U = 0;
+ for (y = 0; y < divrot; y ++) {
+ V = -32768;
+ for (x = 0; x < divrad; x ++) {
+ f->Vertices[0] = v+x+y*divrad;
+ f->MappingU[0] = U;
+ f->MappingV[0] = V;
+ f->Vertices[1] = v+(x+1==divrad?0:x+1)+y*divrad;
+ f->MappingU[1] = U;
+ f->MappingV[1] = V+dV;
+ f->Vertices[2] = v+x+(y+1==divrot?0:(y+1)*divrad);
+ f->MappingU[2] = U+dU;
+ f->MappingV[2] = V;
+ f->Material = m;
+ f++;
+ f->Vertices[0] = v+x+(y+1==divrot?0:(y+1)*divrad);
+ f->MappingU[0] = U+dU;
+ f->MappingV[0] = V;
+ f->Vertices[1] = v+(x+1==divrad?0:x+1)+y*divrad;
+ f->MappingU[1] = U;
+ f->MappingV[1] = V+dV;
+ f->Vertices[2] = v+(x+1==divrad?0:x+1)+(y+1==divrot?0:(y+1)*divrad);
+ f->MappingU[2] = U+dU;
+ f->MappingV[2] = V+dV;
+ f->Material = m;
+ f++;
+ V += dV;
+ }
+ U += dU;
+ }
+ plObjCalcNormals(o);
+ return (o);
+}
+
+pl_Obj *plMakeSphere(pl_Float r, pl_uInt divr, pl_uInt divh, pl_Mat *m) {
+ pl_Obj *o;
+ pl_Vertex *v;
+ pl_Face *f;
+ pl_uInt x, y;
+ double a, da, yp, ya, yda, yf;
+ pl_sInt32 U,V,dU,dV;
+ if (divh < 3) divh = 3;
+ if (divr < 3) divr = 3;
+ o = plObjCreate(2+(divh-2)*(divr),2*divr+(divh-3)*divr*2);
+ if (!o) return 0;
+ v = o->Vertices;
+ v->x = v->z = 0.0; v->y = r; v++;
+ v->x = v->z = 0.0; v->y = -r; v++;
+ ya = 0.0;
+ yda = PL_PI/(divh-1);
+ da = (PL_PI*2.0)/divr;
+ for (y = 0; y < divh - 2; y ++) {
+ ya += yda;
+ yp = cos((double) ya)*r;
+ yf = sin((double) ya)*r;
+ a = 0.0;
+ for (x = 0; x < divr; x ++) {
+ v->y = (pl_Float) yp;
+ v->x = (pl_Float) (cos((double) a)*yf);
+ v->z = (pl_Float) (sin((double) a)*yf);
+ v++;
+ a += da;
+ }
+ }
+ f = o->Faces;
+ v = o->Vertices + 2;
+ a = 0.0;
+ U = 0;
+ dU = 65535/divr;
+ dV = V = 65535/divh;
+ for (x = 0; x < divr; x ++) {
+ f->Vertices[0] = o->Vertices;
+ f->Vertices[1] = v + (x+1==divr ? 0 : x+1);
+ f->Vertices[2] = v + x;
+ f->MappingU[0] = U;
+ f->MappingV[0] = 0;
+ f->MappingU[1] = U+dU;
+ f->MappingV[1] = V;
+ f->MappingU[2] = U;
+ f->MappingV[2] = V;
+ f->Material = m;
+ f++;
+ U += dU;
+ }
+ da = 1.0/(divr+1);
+ v = o->Vertices + 2;
+ for (x = 0; x < (divh-3); x ++) {
+ U = 0;
+ for (y = 0; y < divr; y ++) {
+ f->Vertices[0] = v+y;
+ f->Vertices[1] = v+divr+(y+1==divr?0:y+1);
+ f->Vertices[2] = v+y+divr;
+ f->MappingU[0] = U;
+ f->MappingV[0] = V;
+ f->MappingU[1] = U+dU;
+ f->MappingV[1] = V+dV;
+ f->MappingU[2] = U;
+ f->MappingV[2] = V+dV;
+ f->Material = m; f++;
+ f->Vertices[0] = v+y;
+ f->Vertices[1] = v+(y+1==divr?0:y+1);
+ f->Vertices[2] = v+(y+1==divr?0:y+1)+divr;
+ f->MappingU[0] = U;
+ f->MappingV[0] = V;
+ f->MappingU[1] = U+dU;
+ f->MappingV[1] = V;
+ f->MappingU[2] = U+dU;
+ f->MappingV[2] = V+dV;
+ f->Material = m; f++;
+ U += dU;
+ }
+ V += dV;
+ v += divr;
+ }
+ v = o->Vertices + o->NumVertices - divr;
+ U = 0;
+ for (x = 0; x < divr; x ++) {
+ f->Vertices[0] = o->Vertices + 1;
+ f->Vertices[1] = v + x;
+ f->Vertices[2] = v + (x+1==divr ? 0 : x+1);
+ f->MappingU[0] = U;
+ f->MappingV[0] = 65535;
+ f->MappingU[1] = U;
+ f->MappingV[1] = V;
+ f->MappingU[2] = U+dU;
+ f->MappingV[2] = V;
+ f->Material = m;
+ f++;
+ U += dU;
+ }
+ plObjCalcNormals(o);
+ return (o);
+}
+
+pl_Obj *plMakeCylinder(pl_Float r, pl_Float h, pl_uInt divr, pl_Bool captop,
+ pl_Bool capbottom, pl_Mat *m) {
+ pl_Obj *o;
+ pl_Vertex *v, *topverts, *bottomverts, *topcapvert=0, *bottomcapvert=0;
+ pl_Face *f;
+ pl_uInt32 i;
+ double a, da;
+ if (divr < 3) divr = 3;
+ o = plObjCreate(divr*2+((divr==3)?0:(captop?1:0)+(capbottom?1:0)),
+ divr*2+(divr==3 ? (captop ? 1 : 0) + (capbottom ? 1 : 0) :
+ (captop ? divr : 0) + (capbottom ? divr : 0)));
+ if (!o) return 0;
+ a = 0.0;
+ da = (2.0*PL_PI)/divr;
+ v = o->Vertices;
+ topverts = v;
+ for (i = 0; i < divr; i ++) {
+ v->y = h/2.0f;
+ v->x = (pl_Float) (r*cos((double) a));
+ v->z = (pl_Float)(r*sin(a));
+ v->xformedx = (pl_Float) (32768.0 + (32768.0*cos((double) a))); // temp
+ v->xformedy = (pl_Float) (32768.0 + (32768.0*sin((double) a))); // use xf
+ v++;
+ a += da;
+ }
+ bottomverts = v;
+ a = 0.0;
+ for (i = 0; i < divr; i ++) {
+ v->y = -h/2.0f;
+ v->x = (pl_Float) (r*cos((double) a));
+ v->z = (pl_Float) (r*sin(a));
+ v->xformedx = (pl_Float) (32768.0 + (32768.0*cos((double) a)));
+ v->xformedy = (pl_Float) (32768.0 + (32768.0*sin((double) a)));
+ v++; a += da;
+ }
+ if (captop && divr != 3) {
+ topcapvert = v;
+ v->y = h / 2.0f;
+ v->x = v->z = 0.0f;
+ v++;
+ }
+ if (capbottom && divr != 3) {
+ bottomcapvert = v;
+ v->y = -h / 2.0f;
+ v->x = v->z = 0.0f;
+ v++;
+ }
+ f = o->Faces;
+ for (i = 0; i < divr; i ++) {
+ f->Vertices[0] = bottomverts + i;
+ f->Vertices[1] = topverts + i;
+ f->Vertices[2] = bottomverts + (i == divr-1 ? 0 : i+1);
+ f->MappingV[0] = f->MappingV[2] = 65535; f->MappingV[1] = 0;
+ f->MappingU[0] = f->MappingU[1] = (i<<16)/divr;
+ f->MappingU[2] = ((i+1)<<16)/divr;
+ f->Material = m; f++;
+ f->Vertices[0] = bottomverts + (i == divr-1 ? 0 : i+1);
+ f->Vertices[1] = topverts + i;
+ f->Vertices[2] = topverts + (i == divr-1 ? 0 : i+1);
+ f->MappingV[1] = f->MappingV[2] = 0; f->MappingV[0] = 65535;
+ f->MappingU[0] = f->MappingU[2] = ((i+1)<<16)/divr;
+ f->MappingU[1] = (i<<16)/divr;
+ f->Material = m; f++;
+ }
+ if (captop) {
+ if (divr == 3) {
+ f->Vertices[0] = topverts + 0;
+ f->Vertices[1] = topverts + 2;
+ f->Vertices[2] = topverts + 1;
+ f->MappingU[0] = (pl_sInt32) topverts[0].xformedx;
+ f->MappingV[0] = (pl_sInt32) topverts[0].xformedy;
+ f->MappingU[1] = (pl_sInt32) topverts[1].xformedx;
+ f->MappingV[1] = (pl_sInt32) topverts[1].xformedy;
+ f->MappingU[2] = (pl_sInt32) topverts[2].xformedx;
+ f->MappingV[2] = (pl_sInt32) topverts[2].xformedy;
+ f->Material = m; f++;
+ } else {
+ for (i = 0; i < divr; i ++) {
+ f->Vertices[0] = topverts + (i == divr-1 ? 0 : i + 1);
+ f->Vertices[1] = topverts + i;
+ f->Vertices[2] = topcapvert;
+ f->MappingU[0] = (pl_sInt32) topverts[(i==divr-1?0:i+1)].xformedx;
+ f->MappingV[0] = (pl_sInt32) topverts[(i==divr-1?0:i+1)].xformedy;
+ f->MappingU[1] = (pl_sInt32) topverts[i].xformedx;
+ f->MappingV[1] = (pl_sInt32) topverts[i].xformedy;
+ f->MappingU[2] = f->MappingV[2] = 32768;
+ f->Material = m; f++;
+ }
+ }
+ }
+ if (capbottom) {
+ if (divr == 3) {
+ f->Vertices[0] = bottomverts + 0;
+ f->Vertices[1] = bottomverts + 1;
+ f->Vertices[2] = bottomverts + 2;
+ f->MappingU[0] = (pl_sInt32) bottomverts[0].xformedx;
+ f->MappingV[0] = (pl_sInt32) bottomverts[0].xformedy;
+ f->MappingU[1] = (pl_sInt32) bottomverts[1].xformedx;
+ f->MappingV[1] = (pl_sInt32) bottomverts[1].xformedy;
+ f->MappingU[2] = (pl_sInt32) bottomverts[2].xformedx;
+ f->MappingV[2] = (pl_sInt32) bottomverts[2].xformedy;
+ f->Material = m; f++;
+ } else {
+ for (i = 0; i < divr; i ++) {
+ f->Vertices[0] = bottomverts + i;
+ f->Vertices[1] = bottomverts + (i == divr-1 ? 0 : i + 1);
+ f->Vertices[2] = bottomcapvert;
+ f->MappingU[0] = (pl_sInt32) bottomverts[i].xformedx;
+ f->MappingV[0] = (pl_sInt32) bottomverts[i].xformedy;
+ f->MappingU[1] = (pl_sInt32) bottomverts[(i==divr-1?0:i+1)].xformedx;
+ f->MappingV[1] = (pl_sInt32) bottomverts[(i==divr-1?0:i+1)].xformedy;
+ f->MappingU[2] = f->MappingV[2] = 32768;
+ f->Material = m; f++;
+ }
+ }
+ }
+ plObjCalcNormals(o);
+ return (o);
+}
+
+pl_Obj *plMakeCone(pl_Float r, pl_Float h, pl_uInt div,
+ pl_Bool cap, pl_Mat *m) {
+ pl_Obj *o;
+ pl_Vertex *v;
+ pl_Face *f;
+ pl_uInt32 i;
+ double a, da;
+ if (div < 3) div = 3;
+ o = plObjCreate(div + (div == 3 ? 1 : (cap ? 2 : 1)),
+ div + (div == 3 ? 1 : (cap ? div : 0)));
+ if (!o) return 0;
+ v = o->Vertices;
+ v->x = v->z = 0; v->y = h/2;
+ v->xformedx = 1<<15;
+ v->xformedy = 1<<15;
+ v++;
+ a = 0.0;
+ da = (2.0*PL_PI)/div;
+ for (i = 1; i <= div; i ++) {
+ v->y = h/-2.0f;
+ v->x = (pl_Float) (r*cos((double) a));
+ v->z = (pl_Float) (r*sin((double) a));
+ v->xformedx = (pl_Float) (32768.0 + (cos((double) a)*32768.0));
+ v->xformedy = (pl_Float) (32768.0 + (sin((double) a)*32768.0));
+ a += da;
+ v++;
+ }
+ if (cap && div != 3) {
+ v->y = h / -2.0f;
+ v->x = v->z = 0.0f;
+ v->xformedx = (pl_Float) (1<<15);
+ v->xformedy = (pl_Float) (1<<15);
+ v++;
+ }
+ f = o->Faces;
+ for (i = 1; i <= div; i ++) {
+ f->Vertices[0] = o->Vertices;
+ f->Vertices[1] = o->Vertices + (i == div ? 1 : i + 1);
+ f->Vertices[2] = o->Vertices + i;
+ f->MappingU[0] = (pl_sInt32) o->Vertices[0].xformedx;
+ f->MappingV[0] = (pl_sInt32) o->Vertices[0].xformedy;
+ f->MappingU[1] = (pl_sInt32) o->Vertices[(i==div?1:i+1)].xformedx;
+ f->MappingV[1] = (pl_sInt32) o->Vertices[(i==div?1:i+1)].xformedy;
+ f->MappingU[2] = (pl_sInt32) o->Vertices[i].xformedx;
+ f->MappingV[2] = (pl_sInt32) o->Vertices[i].xformedy;
+ f->Material = m;
+ f++;
+ }
+ if (cap) {
+ if (div == 3) {
+ f->Vertices[0] = o->Vertices + 1;
+ f->Vertices[1] = o->Vertices + 2;
+ f->Vertices[2] = o->Vertices + 3;
+ f->MappingU[0] = (pl_sInt32) o->Vertices[1].xformedx;
+ f->MappingV[0] = (pl_sInt32) o->Vertices[1].xformedy;
+ f->MappingU[1] = (pl_sInt32) o->Vertices[2].xformedx;
+ f->MappingV[1] = (pl_sInt32) o->Vertices[2].xformedy;
+ f->MappingU[2] = (pl_sInt32) o->Vertices[3].xformedx;
+ f->MappingV[2] = (pl_sInt32) o->Vertices[3].xformedy;
+ f->Material = m;
+ f++;
+ } else {
+ for (i = 1; i <= div; i ++) {
+ f->Vertices[0] = o->Vertices + div + 1;
+ f->Vertices[1] = o->Vertices + i;
+ f->Vertices[2] = o->Vertices + (i==div ? 1 : i+1);
+ f->MappingU[0] = (pl_sInt32) o->Vertices[div+1].xformedx;
+ f->MappingV[0] = (pl_sInt32) o->Vertices[div+1].xformedy;
+ f->MappingU[1] = (pl_sInt32) o->Vertices[i].xformedx;
+ f->MappingV[1] = (pl_sInt32) o->Vertices[i].xformedy;
+ f->MappingU[2] = (pl_sInt32) o->Vertices[i==div?1:i+1].xformedx;
+ f->MappingV[2] = (pl_sInt32) o->Vertices[i==div?1:i+1].xformedy;
+ f->Material = m;
+ f++;
+ }
+ }
+ }
+ plObjCalcNormals(o);
+ return (o);
+}
+
+static pl_uChar verts[6*6] = {
+ 0,4,1, 1,4,5, 0,1,2, 3,2,1, 2,3,6, 3,7,6,
+ 6,7,4, 4,7,5, 1,7,3, 7,1,5, 2,6,0, 4,0,6
+};
+static pl_uChar map[24*2*3] = {
+ 1,0, 1,1, 0,0, 0,0, 1,1, 0,1,
+ 0,0, 1,0, 0,1, 1,1, 0,1, 1,0,
+ 0,0, 1,0, 0,1, 1,0, 1,1, 0,1,
+ 0,0, 1,0, 0,1, 0,1, 1,0, 1,1,
+ 1,0, 0,1, 0,0, 0,1, 1,0, 1,1,
+ 1,0, 1,1, 0,0, 0,1, 0,0, 1,1
+};
+
+
+pl_Obj *plMakeBox(pl_Float w, pl_Float d, pl_Float h, pl_Mat *m) {
+ pl_uChar *mm = map;
+ pl_uChar *vv = verts;
+ pl_Obj *o;
+ pl_Vertex *v;
+ pl_Face *f;
+ pl_uInt x;
+ o = plObjCreate(8,12);
+ if (!o) return 0;
+ v = o->Vertices;
+ v->x = -w/2; v->y = h/2; v->z = d/2; v++;
+ v->x = w/2; v->y = h/2; v->z = d/2; v++;
+ v->x = -w/2; v->y = h/2; v->z = -d/2; v++;
+ v->x = w/2; v->y = h/2; v->z = -d/2; v++;
+ v->x = -w/2; v->y = -h/2; v->z = d/2; v++;
+ v->x = w/2; v->y = -h/2; v->z = d/2; v++;
+ v->x = -w/2; v->y = -h/2; v->z = -d/2; v++;
+ v->x = w/2; v->y = -h/2; v->z = -d/2; v++;
+ f = o->Faces;
+ for (x = 0; x < 12; x ++) {
+ f->Vertices[0] = o->Vertices + *vv++;
+ f->Vertices[1] = o->Vertices + *vv++;
+ f->Vertices[2] = o->Vertices + *vv++;
+ f->MappingU[0] = (pl_sInt32) ((double)*mm++ * 65535.0);
+ f->MappingV[0] = (pl_sInt32) ((double)*mm++ * 65535.0);
+ f->MappingU[1] = (pl_sInt32) ((double)*mm++ * 65535.0);
+ f->MappingV[1] = (pl_sInt32) ((double)*mm++ * 65535.0);
+ f->MappingU[2] = (pl_sInt32) ((double)*mm++ * 65535.0);
+ f->MappingV[2] = (pl_sInt32) ((double)*mm++ * 65535.0);
+ f->Material = m;
+ f++;
+ }
+
+ plObjCalcNormals(o);
+ return (o);
+}
+
+pl_Obj *plMakePlane(pl_Float w, pl_Float d, pl_uInt res, pl_Mat *m) {
+ pl_Obj *o;
+ pl_Vertex *v;
+ pl_Face *f;
+ pl_uInt x, y;
+ o = plObjCreate((res+1)*(res+1),res*res*2);
+ if (!o) return 0;
+ v = o->Vertices;
+ for (y = 0; y <= res; y ++) {
+ for (x = 0; x <= res; x ++) {
+ v->y = 0;
+ v->x = ((x*w)/res) - w/2;
+ v->z = ((y*d)/res) - d/2;
+ v++;
+ }
+ }
+ f = o->Faces;
+ for (y = 0; y < res; y ++) {
+ for (x = 0; x < res; x ++) {
+ f->Vertices[0] = o->Vertices + x+(y*(res+1));
+ f->MappingU[0] = (x<<16)/res;
+ f->MappingV[0] = (y<<16)/res;
+ f->Vertices[2] = o->Vertices + x+1+(y*(res+1));
+ f->MappingU[2] = ((x+1)<<16)/res;
+ f->MappingV[2] = (y<<16)/res;
+ f->Vertices[1] = o->Vertices + x+((y+1)*(res+1));
+ f->MappingU[1] = (x<<16)/res;
+ f->MappingV[1] = ((y+1)<<16)/res;
+ f->Material = m;
+ f++;
+ f->Vertices[0] = o->Vertices + x+((y+1)*(res+1));
+ f->MappingU[0] = (x<<16)/res;
+ f->MappingV[0] = ((y+1)<<16)/res;
+ f->Vertices[2] = o->Vertices + x+1+(y*(res+1));
+ f->MappingU[2] = ((x+1)<<16)/res;
+ f->MappingV[2] = (y<<16)/res;
+ f->Vertices[1] = o->Vertices + x+1+((y+1)*(res+1));
+ f->MappingU[1] = ((x+1)<<16)/res;
+ f->MappingV[1] = ((y+1)<<16)/res;
+ f->Material = m;
+ f++;
+ }
+ }
+ plObjCalcNormals(o);
+ return (o);
+}
diff --git a/Src/Winamp/plush/MAT.C b/Src/Winamp/plush/MAT.C
new file mode 100644
index 00000000..801e8d34
--- /dev/null
+++ b/Src/Winamp/plush/MAT.C
@@ -0,0 +1,453 @@
+/******************************************************************************
+Plush Version 1.2
+mat.c
+Material Control
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+static void _plGenerateSinglePalette(pl_Mat *);
+static void _plGeneratePhongPalette(pl_Mat *);
+static void _plGenerateTextureEnvPalette(pl_Mat *);
+static void _plGenerateTexturePalette(pl_Mat *, pl_Texture *);
+static void _plGeneratePhongTexturePalette(pl_Mat *, pl_Texture *);
+static void _plGeneratePhongTransparentPalette(pl_Mat *m);
+static void _plGenerateTransparentPalette(pl_Mat *);
+static void _plSetMaterialPutFace(pl_Mat *m);
+static void _plMatSetupTransparent(pl_Mat *m, pl_uChar *pal);
+
+pl_Mat *plMatCreate() {
+ pl_Mat *m;
+ m = (pl_Mat *) malloc(sizeof(pl_Mat));
+ if (!m) return 0;
+ memset(m,0,sizeof(pl_Mat));
+ m->EnvScaling = 1.0f;
+ m->TexScaling = 1.0f;
+ m->Ambient[0] = m->Ambient[1] = m->Ambient[2] = 0;
+ m->Diffuse[0] = m->Diffuse[1] = m->Diffuse[2] = 128;
+ m->Specular[0] = m->Specular[1] = m->Specular[2] = 128;
+ m->Shininess = 4;
+ m->NumGradients = 32;
+ m->FadeDist = 1000.0;
+ m->zBufferable = 1;
+ return m;
+}
+
+void plMatDelete(pl_Mat *m) {
+ if (m) {
+ if (m->_ReMapTable) free(m->_ReMapTable);
+ if (m->_RequestedColors) free(m->_RequestedColors);
+ if (m->_AddTable) free(m->_AddTable);
+ free(m);
+ }
+}
+
+void plMatInit(pl_Mat *m) {
+ if (m->Shininess < 1) m->Shininess = 1;
+ m->_ft = ((m->Environment ? PL_FILL_ENVIRONMENT : 0) |
+ (m->Texture ? PL_FILL_TEXTURE : 0));
+ m->_st = m->ShadeType;
+
+ if (m->Transparent) m->_ft = PL_FILL_TRANSPARENT;
+
+ if (m->_ft == (PL_FILL_TEXTURE|PL_FILL_ENVIRONMENT))
+ m->_st = PL_SHADE_NONE;
+
+ if (m->_ft == PL_FILL_SOLID) {
+ if (m->_st == PL_SHADE_NONE) _plGenerateSinglePalette(m);
+ else _plGeneratePhongPalette(m);
+ } else if (m->_ft == PL_FILL_TEXTURE) {
+ if (m->_st == PL_SHADE_NONE)
+ _plGenerateTexturePalette(m,m->Texture);
+ else _plGeneratePhongTexturePalette(m,m->Texture);
+ } else if (m->_ft == PL_FILL_ENVIRONMENT) {
+ if (m->_st == PL_SHADE_NONE)
+ _plGenerateTexturePalette(m,m->Environment);
+ else _plGeneratePhongTexturePalette(m,m->Environment);
+ } else if (m->_ft == (PL_FILL_ENVIRONMENT|PL_FILL_TEXTURE))
+ _plGenerateTextureEnvPalette(m);
+ else if (m->_ft == PL_FILL_TRANSPARENT) {
+ if (m->_st == PL_SHADE_NONE) _plGenerateTransparentPalette(m);
+ else _plGeneratePhongTransparentPalette(m);
+ }
+ _plSetMaterialPutFace(m);
+}
+
+static void _plMatSetupTransparent(pl_Mat *m, pl_uChar *pal) {
+ pl_uInt x, intensity;
+ if (m->Transparent)
+ {
+ if (m->_AddTable) free(m->_AddTable);
+ m->_AddTable = (pl_uInt16 *) malloc(256*sizeof(pl_uInt16));
+ for (x = 0; x < 256; x ++) {
+ intensity = *pal++;
+ intensity += *pal++;
+ intensity += *pal++;
+ m->_AddTable[x] = ((intensity*(m->_ColorsUsed-m->_tsfact))/768);
+ }
+ }
+}
+
+void plMatMapToPal(pl_Mat *m, pl_uChar *pal, pl_sInt pstart, pl_sInt pend) {
+ pl_sInt32 j, r, g, b, bestdiff, r2, g2, b2;
+ pl_sInt bestpos,k;
+ pl_uInt32 i;
+ pl_uChar *p;
+ if (!m->_RequestedColors) plMatInit(m);
+ if (!m->_RequestedColors) return;
+ if (m->_ReMapTable) free(m->_ReMapTable);
+ m->_ReMapTable = (pl_uChar *) malloc(m->_ColorsUsed);
+ for (i = 0; i < m->_ColorsUsed; i ++) {
+ bestdiff = 1000000000;
+ bestpos = pstart;
+ r = m->_RequestedColors[i*3];
+ g = m->_RequestedColors[i*3+1];
+ b = m->_RequestedColors[i*3+2];
+ p = pal + pstart*3;
+ for (k = pstart; k <= (pl_sInt)pend; k ++) {
+ r2 = p[0] - r;
+ g2 = p[1] - g;
+ b2 = p[2] - b;
+ p += 3;
+ j = r2*r2+g2*g2+b2*b2;
+ if (j < bestdiff) {
+ bestdiff = j;
+ bestpos = k;
+ }
+ }
+ m->_ReMapTable[i] = bestpos;
+ }
+ _plMatSetupTransparent(m,pal);
+}
+
+static void _plGenerateSinglePalette(pl_Mat *m) {
+ m->_ColorsUsed = 1;
+ if (m->_RequestedColors) free(m->_RequestedColors);
+ m->_RequestedColors = (pl_uChar *) malloc(3);
+ m->_RequestedColors[0] = plMin(plMax(m->Ambient[0],0),255);
+ m->_RequestedColors[1] = plMin(plMax(m->Ambient[1],0),255);
+ m->_RequestedColors[2] = plMin(plMax(m->Ambient[2],0),255);
+}
+
+static void _plGeneratePhongPalette(pl_Mat *m) {
+ pl_uInt i = m->NumGradients, x;
+ pl_sInt c;
+ pl_uChar *pal;
+ double a, da, ca, cb;
+ m->_ColorsUsed = m->NumGradients;
+ if (m->_RequestedColors) free(m->_RequestedColors);
+ pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
+ a = PL_PI/2.0;
+
+ if (m->NumGradients > 1) da = -PL_PI/((m->NumGradients-1)<<1);
+ else da=0.0;
+
+ do {
+ if (m->NumGradients == 1) ca = 1;
+ else {
+ ca = cos((double) a);
+ a += da;
+ }
+ cb = pow((double) ca, (double) m->Shininess);
+ for (x = 0; x < 3; x ++) {
+ c = (pl_sInt) ((cb*m->Specular[x])+(ca*m->Diffuse[x])+m->Ambient[x]);
+ *(pal++) = plMax(0,plMin(c,255));
+ }
+ } while (--i);
+}
+
+static void _plGenerateTextureEnvPalette(pl_Mat *m) {
+ pl_sInt c;
+ pl_uInt whichlevel,whichindex;
+ pl_uChar *texpal, *envpal, *pal;
+ m->_ColorsUsed = m->Texture->NumColors*m->Environment->NumColors;
+ if (m->_RequestedColors) free(m->_RequestedColors);
+ pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
+ envpal = m->Environment->PaletteData;
+ if (m->_AddTable) free(m->_AddTable);
+ m->_AddTable = (pl_uInt16 *) malloc(m->Environment->NumColors*sizeof(pl_uInt16));
+ for (whichlevel = 0; whichlevel < m->Environment->NumColors; whichlevel++) {
+ texpal = m->Texture->PaletteData;
+ switch (m->TexEnvMode)
+ {
+ case PL_TEXENV_MUL: // multiply
+ for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
+ *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[0])>>8);
+ *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[1])>>8);
+ *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[2])>>8);
+ }
+ break;
+ case PL_TEXENV_AVG: // average
+ for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
+ *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[0])>>1);
+ *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[1])>>1);
+ *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[2])>>1);
+ }
+ break;
+ case PL_TEXENV_TEXMINUSENV: // tex-env
+ for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
+ c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
+ c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
+ c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
+ }
+ break;
+ case PL_TEXENV_ENVMINUSTEX: // env-tex
+ for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
+ c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
+ c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
+ c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
+ }
+ break;
+ case PL_TEXENV_MIN:
+ for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
+ *pal++ = plMin(texpal[0],envpal[0]);
+ *pal++ = plMin(texpal[1],envpal[1]);
+ *pal++ = plMin(texpal[2],envpal[2]);
+ texpal+=3;
+ }
+ break;
+ case PL_TEXENV_MAX:
+ break;
+ for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
+ *pal++ = plMax(texpal[0],envpal[0]);
+ *pal++ = plMax(texpal[1],envpal[1]);
+ *pal++ = plMax(texpal[2],envpal[2]);
+ texpal+=3;
+ }
+ default: // add
+ for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
+ c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
+ c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
+ c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
+ }
+ break;
+ }
+ envpal += 3;
+ m->_AddTable[whichlevel] = whichlevel*m->Texture->NumColors;
+ }
+}
+
+static void _plGenerateTexturePalette(pl_Mat *m, pl_Texture *t) {
+ pl_uChar *ppal, *pal;
+ pl_sInt c, i, x;
+ m->_ColorsUsed = t->NumColors;
+ if (m->_RequestedColors) free(m->_RequestedColors);
+ pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
+ ppal = t->PaletteData;
+ i = t->NumColors;
+ do {
+ for (x = 0; x < 3; x ++) {
+ c = m->Ambient[x] + *ppal++;
+ *(pal++) = plMax(0,plMin(c,255));
+ }
+ } while (--i);
+}
+
+static void _plGeneratePhongTexturePalette(pl_Mat *m, pl_Texture *t) {
+ double a, ca, da, cb;
+ pl_uInt16 *addtable;
+ pl_uChar *ppal, *pal;
+ pl_sInt c, i, i2, x;
+ pl_uInt num_shades;
+
+ if (t->NumColors) num_shades = (m->NumGradients / t->NumColors);
+ else num_shades=1;
+
+ if (!num_shades) num_shades = 1;
+ m->_ColorsUsed = num_shades*t->NumColors;
+ if (m->_RequestedColors) free(m->_RequestedColors);
+ pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
+ a = PL_PI/2.0;
+ if (num_shades>1) da = (-PL_PI/2.0)/(num_shades-1);
+ else da=0.0;
+ i2 = num_shades;
+ do {
+ ppal = t->PaletteData;
+ ca = cos((double) a);
+ a += da;
+ cb = pow(ca, (double) m->Shininess);
+ i = t->NumColors;
+ do {
+ for (x = 0; x < 3; x ++) {
+ c = (pl_sInt) ((cb*m->Specular[x])+(ca*m->Diffuse[x])+m->Ambient[x] + *ppal++);
+ *(pal++) = plMax(0,plMin(c,255));
+ }
+ } while (--i);
+ } while (--i2);
+ ca = 0;
+ if (m->_AddTable) free(m->_AddTable);
+ m->_AddTable = (pl_uInt16 *) malloc(256*sizeof(pl_uInt16));
+ addtable = m->_AddTable;
+ i = 256;
+ do {
+ a = sin(ca) * num_shades;
+ ca += PL_PI/512.0;
+ *addtable++ = ((pl_sInt) a)*t->NumColors;
+ } while (--i);
+}
+
+static void _plGeneratePhongTransparentPalette(pl_Mat *m) {
+ m->_tsfact = (pl_sInt) (m->NumGradients*(1.0/(1+m->Transparent)));
+ _plGeneratePhongPalette(m);
+}
+
+static void _plGenerateTransparentPalette(pl_Mat *m) {
+ m->_tsfact = 0;
+ _plGeneratePhongPalette(m);
+}
+
+static void _plSetMaterialPutFace(pl_Mat *m) {
+ m->_PutFace = 0;
+ switch (m->_ft) {
+ case PL_FILL_TRANSPARENT: switch(m->_st) {
+ case PL_SHADE_NONE: case PL_SHADE_FLAT:
+ case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
+ m->_PutFace = plPF_TransF;
+ break;
+ case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
+ case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
+ m->_PutFace = plPF_TransG;
+ break;
+ }
+ break;
+ case PL_FILL_SOLID: switch(m->_st) {
+ case PL_SHADE_NONE: case PL_SHADE_FLAT:
+ case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
+ m->_PutFace = plPF_SolidF;
+ break;
+ case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
+ case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
+ m->_PutFace = plPF_SolidG;
+ break;
+ }
+ break;
+ case PL_FILL_ENVIRONMENT:
+ case PL_FILL_TEXTURE:
+ if (m->PerspectiveCorrect) switch (m->_st) {
+ case PL_SHADE_NONE: case PL_SHADE_FLAT:
+ case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
+ m->_PutFace = plPF_PTexF;
+ break;
+ case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
+ case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
+ m->_PutFace = plPF_PTexG;
+ break;
+ }
+ else switch (m->_st) {
+ case PL_SHADE_NONE: case PL_SHADE_FLAT:
+ case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
+ m->_PutFace = plPF_TexF;
+ break;
+ case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
+ case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
+ m->_PutFace = plPF_TexG;
+ break;
+ }
+ break;
+ case PL_FILL_TEXTURE|PL_FILL_ENVIRONMENT:
+ m->_PutFace = plPF_TexEnv;
+ break;
+ }
+}
+
+typedef struct __ct {
+ pl_uChar r,g,b;
+ pl_Bool visited;
+ struct __ct *next;
+} _ct;
+
+static int mdist(_ct *a, _ct *b) {
+ return ((a->r-b->r)*(a->r-b->r)+(a->g-b->g)*(a->g-b->g)+(a->b-b->b)*(a->b-b->b));
+}
+
+void plMatMakeOptPal(pl_uChar *p, pl_sInt pstart,
+ pl_sInt pend, pl_Mat **materials, pl_sInt nmats) {
+ pl_uChar *allColors = 0;
+ pl_sInt numColors = 0, nc, x;
+ pl_sInt len = pend + 1 - pstart;
+ pl_sInt32 current, newnext, bestdist, thisdist;
+ _ct *colorBlock, *best, *cp;
+
+ for (x = 0; x < nmats; x ++) {
+ if (materials[x]) {
+ if (!materials[x]->_RequestedColors) plMatInit(materials[x]);
+ if (materials[x]->_RequestedColors) numColors+=materials[x]->_ColorsUsed;
+ }
+ }
+ if (!numColors) return;
+
+ allColors=(pl_uChar*)malloc(numColors*3);
+ numColors=0;
+
+ for (x = 0; x < nmats; x ++) {
+ if (materials[x]) {
+ if (materials[x]->_RequestedColors)
+ memcpy(allColors + (numColors*3), materials[x]->_RequestedColors,
+ materials[x]->_ColorsUsed*3);
+ numColors += materials[x]->_ColorsUsed;
+ }
+ }
+
+ if (numColors <= len) {
+ memcpy(p+pstart*3,allColors,numColors*3);
+ free(allColors);
+ return;
+ }
+
+ colorBlock = (_ct *) malloc(sizeof(_ct)*numColors);
+ for (x = 0; x < numColors; x++) {
+ colorBlock[x].r = allColors[x*3];
+ colorBlock[x].g = allColors[x*3+1];
+ colorBlock[x].b = allColors[x*3+2];
+ colorBlock[x].visited = 0;
+ colorBlock[x].next = 0;
+ }
+ free(allColors);
+
+ /* Build a list, starting at color 0 */
+ current = 0;
+ nc = numColors;
+ do {
+ newnext = -1;
+ bestdist = 300000000;
+ colorBlock[current].visited = 1;
+ for (x = 0; x < nc; x ++) {
+ if (!colorBlock[x].visited) {
+ thisdist = mdist(colorBlock + x, colorBlock + current);
+ if (thisdist < 5) { colorBlock[x].visited = 1; numColors--; }
+ else if (thisdist < bestdist) { bestdist = thisdist; newnext = x; }
+ }
+ }
+ if (newnext != -1) {
+ colorBlock[current].next = colorBlock + newnext;
+ current = newnext;
+ }
+ } while (newnext != -1);
+ colorBlock[current].next = 0; /* terminate the list */
+
+ /* we now have a linked list starting at colorBlock, which is each one and
+ it's closest neighbor */
+
+ while (numColors > len) {
+ bestdist = mdist(colorBlock,colorBlock->next);
+ for (best = cp = colorBlock; cp->next; cp = cp->next) {
+ if (bestdist > (thisdist = mdist(cp,cp->next))) {
+ best = cp;
+ bestdist = thisdist;
+ }
+ }
+ best->r = ((int) best->r + (int) best->next->r)>>1;
+ best->g = ((int) best->g + (int) best->next->g)>>1;
+ best->b = ((int) best->b + (int) best->next->b)>>1;
+ best->next = best->next->next;
+ numColors--;
+ }
+ x = pstart*3;
+ for (cp = colorBlock; cp; cp = cp->next) {
+ p[x++] = cp->r;
+ p[x++] = cp->g;
+ p[x++] = cp->b;
+ }
+ free(colorBlock);
+}
diff --git a/Src/Winamp/plush/MATH.C b/Src/Winamp/plush/MATH.C
new file mode 100644
index 00000000..ef66ca89
--- /dev/null
+++ b/Src/Winamp/plush/MATH.C
@@ -0,0 +1,67 @@
+/******************************************************************************
+Plush Version 1.2
+math.c
+Math and Matrix Control
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+void plMatrixRotate(pl_Float matrix[], pl_uChar m, pl_Float Deg) {
+ pl_uChar m1, m2;
+ double c,s;
+ double d= Deg * PL_PI / 180.0;
+ memset(matrix,0,sizeof(pl_Float)*16);
+ matrix[((m-1)<<2)+m-1] = matrix[15] = 1.0;
+ m1 = (m % 3);
+ m2 = ((m1+1) % 3);
+ c = cos(d); s = sin(d);
+ matrix[(m1<<2)+m1]=(pl_Float)c; matrix[(m1<<2)+m2]=(pl_Float)s;
+ matrix[(m2<<2)+m2]=(pl_Float)c; matrix[(m2<<2)+m1]=(pl_Float)-s;
+}
+
+void plMatrixTranslate(pl_Float m[], pl_Float x, pl_Float y, pl_Float z) {
+ memset(m,0,sizeof(pl_Float)*16);
+ m[0] = m[4+1] = m[8+2] = m[12+3] = 1.0;
+ m[0+3] = x; m[4+3] = y; m[8+3] = z;
+}
+
+void plMatrixMultiply(pl_Float *dest, pl_Float src[]) {
+ pl_Float temp[16];
+ pl_uInt i;
+ memcpy(temp,dest,sizeof(pl_Float)*16);
+ for (i = 0; i < 16; i += 4) {
+ *dest++ = src[i+0]*temp[(0<<2)+0]+src[i+1]*temp[(1<<2)+0]+
+ src[i+2]*temp[(2<<2)+0]+src[i+3]*temp[(3<<2)+0];
+ *dest++ = src[i+0]*temp[(0<<2)+1]+src[i+1]*temp[(1<<2)+1]+
+ src[i+2]*temp[(2<<2)+1]+src[i+3]*temp[(3<<2)+1];
+ *dest++ = src[i+0]*temp[(0<<2)+2]+src[i+1]*temp[(1<<2)+2]+
+ src[i+2]*temp[(2<<2)+2]+src[i+3]*temp[(3<<2)+2];
+ *dest++ = src[i+0]*temp[(0<<2)+3]+src[i+1]*temp[(1<<2)+3]+
+ src[i+2]*temp[(2<<2)+3]+src[i+3]*temp[(3<<2)+3];
+ }
+}
+
+void plMatrixApply(pl_Float *m, pl_Float x, pl_Float y, pl_Float z,
+ pl_Float *outx, pl_Float *outy, pl_Float *outz) {
+ *outx = x*m[0] + y*m[1] + z*m[2] + m[3];
+ *outy = x*m[4] + y*m[5] + z*m[6] + m[7];
+ *outz = x*m[8] + y*m[9] + z*m[10] + m[11];
+}
+
+pl_Float plDotProduct(pl_Float x1, pl_Float y1, pl_Float z1,
+ pl_Float x2, pl_Float y2, pl_Float z2) {
+ return ((x1*x2)+(y1*y2)+(z1*z2));
+}
+
+void plNormalizeVector(pl_Float *x, pl_Float *y, pl_Float *z) {
+ double length;
+ length = (*x)*(*x)+(*y)*(*y)+(*z)*(*z);
+ if (length > 0.0000000001) {
+ pl_Float t = (pl_Float)sqrt(length);
+ *x /= t;
+ *y /= t;
+ *z /= t;
+ } else *x = *y = *z = 0.0;
+}
+
diff --git a/Src/Winamp/plush/OBJ.C b/Src/Winamp/plush/OBJ.C
new file mode 100644
index 00000000..79d9fce0
--- /dev/null
+++ b/Src/Winamp/plush/OBJ.C
@@ -0,0 +1,179 @@
+/******************************************************************************
+Plush Version 1.2
+obj.c
+Object control
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+pl_Obj *plObjScale(pl_Obj *o, pl_Float s) {
+ pl_uInt32 i = o->NumVertices;
+ pl_Vertex *v = o->Vertices;
+ while (i--) {
+ v->x *= s; v->y *= s; v->z *= s; v++;
+ }
+ for (i = 0; i < PL_MAX_CHILDREN; i ++)
+ if (o->Children[i]) plObjScale(o->Children[i],s);
+ return o;
+}
+
+pl_Obj *plObjStretch(pl_Obj *o, pl_Float x, pl_Float y, pl_Float z) {
+ pl_uInt32 i = o->NumVertices;
+ pl_Vertex *v = o->Vertices;
+ while (i--) {
+ v->x *= x; v->y *= y; v->z *= z; v++;
+ }
+ for (i = 0; i < PL_MAX_CHILDREN; i ++)
+ if (o->Children[i]) plObjStretch(o->Children[i],x,y,z);
+ return o;
+}
+
+pl_Obj *plObjTranslate(pl_Obj *o, pl_Float x, pl_Float y, pl_Float z) {
+ pl_uInt32 i = o->NumVertices;
+ pl_Vertex *v = o->Vertices;
+ while (i--) {
+ v->x += x; v->y += y; v->z += z; v++;
+ }
+ return o;
+}
+
+pl_Obj *plObjFlipNormals(pl_Obj *o) {
+ pl_uInt32 i = o->NumVertices;
+ pl_Vertex *v = o->Vertices;
+ pl_Face *f = o->Faces;
+ while (i--) {
+ v->nx = - v->nx; v->ny = - v->ny; v->nz = - v->nz; v++;
+ }
+ i = o->NumFaces;
+ while (i--) {
+ f->nx = - f->nx; f->ny = - f->ny; f->nz = - f->nz;
+ f++;
+ }
+ for (i = 0; i < PL_MAX_CHILDREN; i ++)
+ if (o->Children[i]) plObjFlipNormals(o->Children[i]);
+ return o;
+}
+
+void plObjDelete(pl_Obj *o) {
+ pl_uInt i;
+ if (o) {
+ for (i = 0; i < PL_MAX_CHILDREN; i ++)
+ if (o->Children[i]) plObjDelete(o->Children[i]);
+ if (o->Vertices) free(o->Vertices);
+ if (o->Faces) free(o->Faces);
+ free(o);
+ }
+}
+
+pl_Obj *plObjCreate(pl_uInt32 nv, pl_uInt32 nf) {
+ pl_Obj *o;
+ if (!(o = (pl_Obj *) malloc(sizeof(pl_Obj)))) return 0;
+ memset(o,0,sizeof(pl_Obj));
+ o->GenMatrix = 1;
+ o->BackfaceCull = 1;
+ o->NumVertices = nv;
+ o->NumFaces = nf;
+ if (nv && !(o->Vertices=(pl_Vertex *) malloc(sizeof(pl_Vertex)*nv))) {
+ free(o);
+ return 0;
+ }
+ if (nf && !(o->Faces = (pl_Face *) malloc(sizeof(pl_Face)*nf))) {
+ free(o->Vertices);
+ free(o);
+ return 0;
+ }
+ memset(o->Vertices,0,sizeof(pl_Vertex)*nv);
+ memset(o->Faces,0,sizeof(pl_Face)*nf);
+ return o;
+}
+
+pl_Obj *plObjClone(pl_Obj *o) {
+ pl_Face *iff, *of;
+ pl_uInt32 i;
+ pl_Obj *out;
+ if (!(out = plObjCreate(o->NumVertices,o->NumFaces))) return 0;
+ for (i = 0; i < PL_MAX_CHILDREN; i ++)
+ if (o->Children[i]) out->Children[i] = plObjClone(o->Children[i]);
+ out->Xa = o->Xa; out->Ya = o->Ya; out->Za = o->Za;
+ out->Xp = o->Xp; out->Yp = o->Yp; out->Zp = o->Zp;
+ out->BackfaceCull = o->BackfaceCull;
+ out->BackfaceIllumination = o->BackfaceIllumination;
+ out->GenMatrix = o->GenMatrix;
+ memcpy(out->Vertices, o->Vertices, sizeof(pl_Vertex) * o->NumVertices);
+ iff = o->Faces;
+ of = out->Faces;
+ i = out->NumFaces;
+ while (i--) {
+ of->Vertices[0] = (pl_Vertex *)
+ out->Vertices + (iff->Vertices[0] - o->Vertices);
+ of->Vertices[1] = (pl_Vertex *)
+ out->Vertices + (iff->Vertices[1] - o->Vertices);
+ of->Vertices[2] = (pl_Vertex *)
+ out->Vertices + (iff->Vertices[2] - o->Vertices);
+ of->MappingU[0] = iff->MappingU[0];
+ of->MappingV[0] = iff->MappingV[0];
+ of->MappingU[1] = iff->MappingU[1];
+ of->MappingV[1] = iff->MappingV[1];
+ of->MappingU[2] = iff->MappingU[2];
+ of->MappingV[2] = iff->MappingV[2];
+ of->nx = iff->nx;
+ of->ny = iff->ny;
+ of->nz = iff->nz;
+ of->Material = iff->Material;
+ of++;
+ iff++;
+ }
+ return out;
+}
+
+void plObjSetMat(pl_Obj *o, pl_Mat *m, pl_Bool th) {
+ pl_sInt32 i = o->NumFaces;
+ pl_Face *f = o->Faces;
+ while (i--) (f++)->Material = m;
+ if (th) for (i = 0; i < PL_MAX_CHILDREN; i++)
+ if (o->Children[i]) plObjSetMat(o->Children[i],m,th);
+}
+
+void plObjCalcNormals(pl_Obj *obj) {
+ pl_uInt32 i;
+ pl_Vertex *v = obj->Vertices;
+ pl_Face *f = obj->Faces;
+ double x1, x2, y1, y2, z1, z2;
+ i = obj->NumVertices;
+ while (i--) {
+ v->nx = 0.0; v->ny = 0.0; v->nz = 0.0;
+ v++;
+ }
+ i = obj->NumFaces;
+ while (i--) {
+ x1 = f->Vertices[0]->x-f->Vertices[1]->x;
+ x2 = f->Vertices[0]->x-f->Vertices[2]->x;
+ y1 = f->Vertices[0]->y-f->Vertices[1]->y;
+ y2 = f->Vertices[0]->y-f->Vertices[2]->y;
+ z1 = f->Vertices[0]->z-f->Vertices[1]->z;
+ z2 = f->Vertices[0]->z-f->Vertices[2]->z;
+ f->nx = (pl_Float) (y1*z2 - z1*y2);
+ f->ny = (pl_Float) (z1*x2 - x1*z2);
+ f->nz = (pl_Float) (x1*y2 - y1*x2);
+ plNormalizeVector(&f->nx, &f->ny, &f->nz);
+ f->Vertices[0]->nx += f->nx;
+ f->Vertices[0]->ny += f->ny;
+ f->Vertices[0]->nz += f->nz;
+ f->Vertices[1]->nx += f->nx;
+ f->Vertices[1]->ny += f->ny;
+ f->Vertices[1]->nz += f->nz;
+ f->Vertices[2]->nx += f->nx;
+ f->Vertices[2]->ny += f->ny;
+ f->Vertices[2]->nz += f->nz;
+ f++;
+ }
+ v = obj->Vertices;
+ i = obj->NumVertices;
+ do {
+ plNormalizeVector(&v->nx, &v->ny, &v->nz);
+ v++;
+ } while (--i);
+ for (i = 0; i < PL_MAX_CHILDREN; i ++)
+ if (obj->Children[i]) plObjCalcNormals(obj->Children[i]);
+}
diff --git a/Src/Winamp/plush/PF_PTEX.C b/Src/Winamp/plush/PF_PTEX.C
new file mode 100644
index 00000000..eb1d0381
--- /dev/null
+++ b/Src/Winamp/plush/PF_PTEX.C
@@ -0,0 +1,459 @@
+/******************************************************************************
+Plush Version 1.2
+pf_ptex.c
+Perspective Correct Texture Mapping Rasterizers
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+#include "putface.h"
+
+void plPF_PTexF(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_uChar *remap = TriFace->Material->_ReMapTable;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+ pl_Float MappingU1, MappingU2, MappingU3;
+ pl_Float MappingV1, MappingV2, MappingV3;
+ pl_sInt32 MappingU_AND, MappingV_AND;
+ pl_uChar *texture;
+ pl_uChar vshift;
+ pl_uInt16 bc;
+ pl_Texture *Texture;
+ pl_sInt32 iShade;
+
+ pl_uChar nm, nmb;
+ pl_sInt n;
+ pl_Float U1,V1,U2,V2,dU1=0,dU2=0,dV1=0,dV2=0,dUL=0,dVL=0,UL,VL;
+ pl_sInt32 iUL, iVL, idUL=0, idVL=0, iULnext, iVLnext;
+
+ pl_sInt32 scrwidth = cam->ScreenWidth;
+ pl_sInt32 X1, X2, dX1=0, dX2=0, XL1, Xlen;
+ pl_ZBuffer Z1, dZ1=0, dZ2=0, Z2, dZL=0, ZL, pZL, pdZL;
+ pl_sInt32 Y1, Y2, Y0, dY;
+ pl_uChar stat;
+
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+
+ if (TriFace->Material->Environment) Texture = TriFace->Material->Environment;
+ else Texture = TriFace->Material->Texture;
+
+ if (!Texture) return;
+ texture = Texture->Data;
+ iShade = (pl_sInt32)(TriFace->fShade*256.0);
+ if (iShade < 0) iShade=0;
+ if (iShade > 255) iShade=255;
+
+ if (!TriFace->Material->_AddTable) bc=0;
+ else bc = TriFace->Material->_AddTable[iShade];
+ nm = TriFace->Material->PerspectiveCorrect;
+ nmb = 0; while (nm) { nmb++; nm >>= 1; }
+ nmb = plMin(6,nmb);
+ nm = 1<<nmb;
+ MappingV_AND = ((1<<Texture->Height)-1)<<Texture->Width;
+ MappingU_AND = (1<<Texture->Width)-1;
+ vshift = 16 - Texture->Width;
+
+ if (TriFace->Material->Environment) {
+ PUTFACE_SORT_ENV();
+ } else {
+ PUTFACE_SORT_TEX();
+ }
+
+ MappingU1 *= TriFace->Scrz[i0]/65536.0f;
+ MappingV1 *= TriFace->Scrz[i0]/65536.0f;
+ MappingU2 *= TriFace->Scrz[i1]/65536.0f;
+ MappingV2 *= TriFace->Scrz[i1]/65536.0f;
+ MappingU3 *= TriFace->Scrz[i2]/65536.0f;
+ MappingV3 *= TriFace->Scrz[i2]/65536.0f;
+
+ U1 = U2 = MappingU1;
+ V1 = V2 = MappingV1;
+ X2 = X1 = TriFace->Scrx[i0];
+ Z2 = Z1 = TriFace->Scrz[i0];
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2-Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dZ2 = (TriFace->Scrz[i2] - Z1) / dY;
+ dU2 = (MappingU3 - U1) / dY;
+ dV2 = (MappingV3 - V1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dZ1 = (TriFace->Scrz[i1] - Z1) / dY;
+ dU1 = (MappingU2 - U1) / dY;
+ dV1 = (MappingV2 - V1) / dY;
+ if (dX2 < dX1) {
+ XL1 = dX2; dX2 = dX1; dX1 = XL1;
+ dUL = dU1; dU1 = dU2; dU2 = dUL;
+ dVL = dV1; dV1 = dV2; dV2 = dVL;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ Z2 = TriFace->Scrz[i1];
+ U2 = MappingU2;
+ V2 = MappingV2;
+ stat = 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ Z1 = TriFace->Scrz[i1];
+ U1 = MappingU2;
+ V1 = MappingV2;
+ stat = 1|8;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+
+ XL1 = ((dX1-dX2)*dY+(1<<19))>>20;
+ if (XL1) {
+ dUL = ((dU1-dU2)*dY)/XL1;
+ dVL = ((dV1-dV2)*dY)/XL1;
+ dZL = ((dZ1-dZ2)*dY)/XL1;
+ } else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) {
+ dUL = (U2-U1)/XL1;
+ dVL = (V2-V1)/XL1;
+ dZL = (Z2-Z1)/XL1;
+ }
+ }
+
+ pdZL = dZL * nm;
+ dUL *= nm;
+ dVL *= nm;
+
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2-((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (TriFace->Scrz[i2]-Z1)/dY;
+ dV1 = (MappingV3 - V1) / dY;
+ dU1 = (MappingU3 - U1) / dY;
+ }
+ }
+ XL1 = (X1+(1<<19))>>20;
+ Xlen = ((X2+(1<<19))>>20) - XL1;
+ if (Xlen > 0) {
+ register pl_Float t;
+ pZL = ZL = Z1;
+ UL = U1;
+ VL = V1;
+ gmem += XL1;
+ zbuf += XL1;
+ XL1 += Xlen-scrwidth;
+ t = 65536.0f/ZL;
+ iUL = iULnext = ((pl_sInt32) (UL*t));
+ iVL = iVLnext = ((pl_sInt32) (VL*t));
+ do {
+ UL += dUL;
+ VL += dVL;
+ iUL = iULnext;
+ iVL = iVLnext;
+ pZL += pdZL;
+ t = 65536.0f/pZL;
+ iULnext = ((pl_sInt32) (UL*t));
+ iVLnext = ((pl_sInt32) (VL*t));
+ idUL = (iULnext - iUL)>>nmb;
+ idVL = (iVLnext - iVL)>>nmb;
+ n = nm;
+ Xlen -= n;
+ if (Xlen < 0) n += Xlen;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ *zbuf = ZL;
+ *gmem = remap[bc + texture[((iUL>>16)&MappingU_AND) +
+ ((iVL>>vshift)&MappingV_AND)]];
+ }
+ zbuf++;
+ gmem++;
+ ZL += dZL;
+ iUL += idUL;
+ iVL += idVL;
+ } while (--n);
+ else do {
+ *gmem++ = remap[bc + texture[((iUL>>16)&MappingU_AND) +
+ ((iVL>>vshift)&MappingV_AND)]];
+ iUL += idUL;
+ iVL += idVL;
+ } while (--n);
+ } while (Xlen > 0);
+ gmem -= XL1;
+ zbuf -= XL1;
+ } else {
+ zbuf += cam->ScreenWidth;
+ gmem += cam->ScreenWidth;
+ }
+ Z1 += dZ1;
+ U1 += dU1;
+ V1 += dV1;
+ X1 += dX1;
+ X2 += dX2;
+ Y0++;
+ }
+}
+
+void plPF_PTexG(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_Float MappingU1, MappingU2, MappingU3;
+ pl_Float MappingV1, MappingV2, MappingV3;
+
+ pl_Texture *Texture;
+ pl_Bool zb = (cam->zBuffer&&TriFace->Material->zBufferable) ? 1 : 0;
+
+ pl_uChar nm, nmb;
+ pl_uInt n;
+ pl_sInt32 MappingU_AND, MappingV_AND;
+ pl_uChar vshift;
+ pl_uChar *texture;
+ pl_uInt16 *addtable;
+ pl_uChar *remap = TriFace->Material->_ReMapTable;
+ pl_sInt32 iUL, iVL, idUL, idVL, iULnext, iVLnext;
+ pl_Float U2,V2,dU2=0,dV2=0,dUL=0,dVL=0,UL,VL;
+ pl_sInt32 XL1, Xlen;
+ pl_sInt32 C2, dC2=0, CL, dCL=0;
+ pl_Float ZL, Z2, dZ2=0, dZL=0, pdZL, pZL;
+
+ pl_sInt32 Y2, dY;
+ pl_uChar stat;
+
+ /* Cache line */
+ pl_sInt32 Y0,Y1;
+ pl_sInt32 C1, dC1=0, X2, dX2=0, X1, dX1=0;
+
+ /* Cache line */
+ pl_Float dU1=0, U1, dZ1=0, Z1, V1, dV1=0;
+ pl_sInt32 scrwidth = cam->ScreenWidth;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+
+ if (TriFace->Material->Environment) Texture = TriFace->Material->Environment;
+ else Texture = TriFace->Material->Texture;
+
+ if (!Texture) return;
+ texture = Texture->Data;
+ addtable = TriFace->Material->_AddTable;
+ if (!addtable) return;
+
+ nm = TriFace->Material->PerspectiveCorrect;
+ nmb = 0; while (nm) { nmb++; nm >>= 1; }
+ nmb = plMin(6,nmb);
+ nm = 1<<nmb;
+ MappingV_AND = ((1<<Texture->Height)-1)<<Texture->Width;
+ MappingU_AND = (1<<Texture->Width)-1;
+ vshift = 16 - Texture->Width;
+
+ if (TriFace->Material->Environment) {
+ PUTFACE_SORT_ENV();
+ } else {
+ PUTFACE_SORT_TEX();
+ }
+
+ MappingU1 *= TriFace->Scrz[i0]/65536.0f;
+ MappingV1 *= TriFace->Scrz[i0]/65536.0f;
+ MappingU2 *= TriFace->Scrz[i1]/65536.0f;
+ MappingV2 *= TriFace->Scrz[i1]/65536.0f;
+ MappingU3 *= TriFace->Scrz[i2]/65536.0f;
+ MappingV3 *= TriFace->Scrz[i2]/65536.0f;
+ TriFace->Shades[0] *= 65536.0f;
+ TriFace->Shades[1] *= 65536.0f;
+ TriFace->Shades[2] *= 65536.0f;
+
+ C1 = C2 = (pl_sInt32) TriFace->Shades[i0];
+ U1 = U2 = MappingU1;
+ V1 = V2 = MappingV1;
+ X2 = X1 = TriFace->Scrx[i0];
+ Z2 = Z1 = TriFace->Scrz[i0];
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2-Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dZ2 = (TriFace->Scrz[i2] - Z1) / dY;
+ dC2 = (pl_sInt32) ((TriFace->Shades[i2] - C1) / dY);
+ dU2 = (MappingU3 - U1) / dY;
+ dV2 = (MappingV3 - V1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dZ1 = (TriFace->Scrz[i1] - Z1) / dY;
+ dC1 = (pl_sInt32) ((TriFace->Shades[i1] - C1) / dY);
+ dU1 = (MappingU2 - U1) / dY;
+ dV1 = (MappingV2 - V1) / dY;
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dUL = dU1; dU1 = dU2; dU2 = dUL;
+ dVL = dV1; dV1 = dV2; dV2 = dVL;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ dCL = dC1; dC1 = dC2; dC2 = dCL;
+ stat = 2;
+ } else stat = 1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ Z2 = TriFace->Scrz[i1];
+ C2 = (pl_sInt32)TriFace->Shades[i1];
+ U2 = MappingU2;
+ V2 = MappingV2;
+ stat = 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ Z1 = TriFace->Scrz[i1];
+ C1 = (pl_sInt32)TriFace->Shades[i1];
+ U1 = MappingU2;
+ V1 = MappingV2;
+ stat = 1|8;
+ }
+ }
+
+ gmem += (Y0 * scrwidth);
+ zbuf += (Y0 * scrwidth);
+
+ XL1 = (((dX1-dX2)*dY+(1<<19))>>20);
+ if (XL1) {
+ dUL = ((dU1-dU2)*dY)/XL1;
+ dVL = ((dV1-dV2)*dY)/XL1;
+ dZL = ((dZ1-dZ2)*dY)/XL1;
+ dCL = ((dC1-dC2)*dY)/XL1;
+ } else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) {
+ dUL = (U2-U1)/XL1;
+ dVL = (V2-V1)/XL1;
+ dZL = (Z2-Z1)/XL1;
+ dCL = (C2-C1)/XL1;
+ }
+ }
+
+ pdZL = dZL * nm;
+ dUL *= nm;
+ dVL *= nm;
+ Y1 -= Y0;
+ Y0 = Y2-Y0;
+ while (Y0--) {
+ if (!Y1--) {
+ dY = Y2-((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (TriFace->Scrz[i2]-Z1)/dY;
+ dC1 = (pl_sInt32)((TriFace->Shades[i2]-C1)/dY);
+ dV1 = (MappingV3 - V1) / dY;
+ dU1 = (MappingU3 - U1) / dY;
+ }
+ }
+ XL1 = (X1+(1<<19))>>20;
+ Xlen = ((X2+(1<<19))>>20) - XL1;
+ if (Xlen > 0) {
+ register pl_Float t;
+ CL = C1;
+ pZL = ZL = Z1;
+ UL = U1;
+ VL = V1;
+ gmem += XL1;
+ zbuf += XL1;
+ XL1 += Xlen-scrwidth;
+ t = 65536.0f / ZL;
+ iUL = iULnext = ((pl_sInt32) (UL*t));
+ iVL = iVLnext = ((pl_sInt32) (VL*t));
+ do {
+ UL += dUL;
+ VL += dVL;
+ iUL = iULnext;
+ iVL = iVLnext;
+ pZL += pdZL;
+ t = 65536.0f/pZL;
+ iULnext = ((pl_sInt32) (UL*t));
+ iVLnext = ((pl_sInt32) (VL*t));
+ idUL = (iULnext - iUL)>>nmb;
+ idVL = (iVLnext - iVL)>>nmb;
+ n = nm;
+ Xlen -= n;
+ if (Xlen < 0) n += Xlen;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ int av;
+ if (CL < 0) av=addtable[0];
+ else if (CL > (255<<8)) av=addtable[255];
+ else av=addtable[CL>>8];
+ *zbuf = ZL;
+ *gmem = remap[av +
+ texture[((iUL>>16)&MappingU_AND) +
+ ((iVL>>vshift)&MappingV_AND)]];
+ }
+ zbuf++;
+ gmem++;
+ ZL += dZL;
+ CL += dCL;
+ iUL += idUL;
+ iVL += idVL;
+ } while (--n);
+ else do {
+ int av;
+ if (CL < 0) av=addtable[0];
+ else if (CL > (255<<8)) av=addtable[255];
+ else av=addtable[CL>>8];
+ *gmem++ = remap[av +
+ texture[((iUL>>16)&MappingU_AND) +
+ ((iVL>>vshift)&MappingV_AND)]];
+ CL += dCL;
+ iUL += idUL;
+ iVL += idVL;
+ } while (--n);
+ } while (Xlen > 0);
+ gmem -= XL1;
+ zbuf -= XL1;
+ } else {
+ zbuf += scrwidth;
+ gmem += scrwidth;
+ }
+ Z1 += dZ1;
+ U1 += dU1;
+ V1 += dV1;
+ X1 += dX1;
+ X2 += dX2;
+ C1 += dC1;
+ }
+}
diff --git a/Src/Winamp/plush/PF_SOLID.C b/Src/Winamp/plush/PF_SOLID.C
new file mode 100644
index 00000000..f306b177
--- /dev/null
+++ b/Src/Winamp/plush/PF_SOLID.C
@@ -0,0 +1,271 @@
+/******************************************************************************
+Plush Version 1.2
+pf_solid.c
+Solid Rasterizers
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+#include "putface.h"
+
+void plPF_SolidF(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+
+ pl_sInt32 X1, X2, dX1=0, dX2=0, XL1, XL2;
+ pl_ZBuffer dZL=0, dZ1=0, dZ2=0, Z1, ZL, Z2, Z3;
+ pl_sInt32 Y1, Y2, Y0, dY;
+ pl_uChar stat;
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+ pl_uChar bc;
+ pl_sInt32 shade;
+
+ PUTFACE_SORT();
+
+ shade=(pl_sInt32) (TriFace->fShade*(TriFace->Material->_ColorsUsed-1));
+ if (shade < 0) shade=0;
+ if (shade > (pl_sInt32) TriFace->Material->_ColorsUsed-1) shade=TriFace->Material->_ColorsUsed-1;
+ bc=TriFace->Material->_ReMapTable[shade];
+
+ X2 = X1 = TriFace->Scrx[i0];
+ Z1 = TriFace->Scrz[i0];
+ Z2 = TriFace->Scrz[i1];
+ Z3 = TriFace->Scrz[i2];
+ Y0 = (TriFace->Scry[i0]+(1<<19)) >> 20;
+ Y1 = (TriFace->Scry[i1]+(1<<19)) >> 20;
+ Y2 = (TriFace->Scry[i2]+(1<<19)) >> 20;
+
+ dY = Y2-Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dZ2 = (Z3 - Z1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dZ1 = (Z2 - Z1) / dY;
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ Z2 = Z1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ stat = 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ ZL = Z1; Z1 = Z2; Z2 = ZL;
+ stat = 1|8;
+ }
+ }
+
+ if (zb) {
+ XL1 = ((dX1-dX2)*dY+(1<<19))>>20;
+ if (XL1) dZL = ((dZ1-dZ2)*dY)/XL1;
+ else {
+ XL1 = (X2-X1+(1<<19))>>20;
+ if (zb && XL1) dZL = (Z2-Z1)/XL1;
+ else dZL = 0.0;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2 - ((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (Z3-Z1)/dY;
+ }
+ }
+ XL1 = (X1+(1<<19))>>20;
+ XL2 = (X2+(1<<19))>>20;
+ ZL = Z1;
+ XL2 -= XL1;
+ if (XL2 > 0) {
+ zbuf += XL1;
+ gmem += XL1;
+ XL1 += XL2;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ *zbuf = ZL;
+ *gmem = bc;
+ }
+ gmem++;
+ zbuf++;
+ ZL += dZL;
+ } while (--XL2);
+ else do *gmem++ = bc; while (--XL2);
+ gmem -= XL1;
+ zbuf -= XL1;
+ }
+ gmem += cam->ScreenWidth;
+ zbuf += cam->ScreenWidth;
+ Z1 += dZ1;
+ X1 += dX1;
+ X2 += dX2;
+ Y0++;
+ }
+}
+
+void plPF_SolidG(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_uChar *remap = TriFace->Material->_ReMapTable;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+ pl_ZBuffer dZL=0, dZ1=0, dZ2=0, Z1, Z2, ZL, Z3;
+ pl_sInt32 dX1=0, dX2=0, X1, X2, XL1, XL2;
+ pl_sInt32 C1, C2, dC1=0, dC2=0, dCL=0, CL, C3;
+ pl_sInt32 Y1, Y2, Y0, dY;
+ pl_uChar stat;
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+
+ pl_Float nc = (TriFace->Material->_ColorsUsed-1)*65536.0f;
+ pl_sInt32 maxColor=((TriFace->Material->_ColorsUsed-1)<<16);
+ pl_sInt32 maxColorNonShift=TriFace->Material->_ColorsUsed-1;
+
+ PUTFACE_SORT();
+
+
+ C1 = (pl_sInt32) (TriFace->Shades[i0]*nc);
+ C2 = (pl_sInt32) (TriFace->Shades[i1]*nc);
+ C3 = (pl_sInt32) (TriFace->Shades[i2]*nc);
+ X2 = X1 = TriFace->Scrx[i0];
+ Z1 = TriFace->Scrz[i0];
+ Z2 = TriFace->Scrz[i1];
+ Z3 = TriFace->Scrz[i2];
+
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2 - Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dC2 = (C3 - C1) / dY;
+ dZ2 = (Z3 - Z1) / dY;
+ }
+ dY = Y1 - Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dC1 = (C2 - C1) / dY;
+ dZ1 = (Z2 - Z1) / dY;
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dC2 ^= dC1; dC1 ^= dC2; dC2 ^= dC1;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ Z2 = Z1;
+ C2 = C1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ stat = 2|4;
+ } else {
+ X1 = C1; C1 = C2; C2 = X1;
+ ZL = Z1; Z1 = Z2; Z2 = ZL;
+ X1 = TriFace->Scrx[i1];
+ stat = 1|8;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+
+ XL1 = (((dX1-dX2)*dY+(1<<19))>>20);
+ if (XL1) {
+ dCL = ((dC1-dC2)*dY)/XL1;
+ dZL = ((dZ1-dZ2)*dY)/XL1;
+ } else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) {
+ dCL = (C2-C1)/XL1;
+ dZL = (Z2-Z1)/XL1;
+ }
+ }
+
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2 - ((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ dZ1 = (Z3-Z1)/dY;
+ dC1 = (C3-C1) / dY;
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ }
+ }
+ CL = C1;
+ XL1 = (X1+(1<<19))>>20;
+ XL2 = (X2+(1<<19))>>20;
+ ZL = Z1;
+ XL2 -= XL1;
+ if (XL2 > 0) {
+ gmem += XL1;
+ zbuf += XL1;
+ XL1 += XL2;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ *zbuf = ZL;
+ if (CL >= maxColor) *gmem=remap[maxColorNonShift];
+ else if (CL > 0) *gmem = remap[CL>>16];
+ else *gmem = remap[0];
+ }
+ gmem++;
+ zbuf++;
+ ZL += dZL;
+ CL += dCL;
+ } while (--XL2);
+ else do {
+ if (CL >= maxColor) *gmem++=remap[maxColorNonShift];
+ else if (CL > 0) *gmem++ = remap[CL>>16];
+ else *gmem++ = remap[0];
+ CL += dCL;
+ } while (--XL2);
+ gmem -= XL1;
+ zbuf -= XL1;
+ }
+ gmem += cam->ScreenWidth;
+ zbuf += cam->ScreenWidth;
+ X1 += dX1;
+ X2 += dX2;
+ C1 += dC1;
+ Z1 += dZ1;
+ Y0++;
+ }
+}
diff --git a/Src/Winamp/plush/PF_TEX.C b/Src/Winamp/plush/PF_TEX.C
new file mode 100644
index 00000000..b9879169
--- /dev/null
+++ b/Src/Winamp/plush/PF_TEX.C
@@ -0,0 +1,584 @@
+/******************************************************************************
+Plush Version 1.2
+pf_tex.c
+Affine Texture Mapping Rasterizers
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+#include "putface.h"
+
+
+void plPF_TexEnv(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_uChar *remap;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+
+ pl_sInt32 MappingU1, MappingU2, MappingU3;
+ pl_sInt32 MappingV1, MappingV2, MappingV3;
+ pl_sInt32 MappingU_AND, MappingV_AND;
+ pl_sInt32 eMappingU1, eMappingU2, eMappingU3;
+ pl_sInt32 eMappingV1, eMappingV2, eMappingV3;
+ pl_sInt32 eMappingU_AND, eMappingV_AND;
+
+ pl_uChar *texture, *environment;
+ pl_uChar vshift;
+ pl_uChar evshift;
+ pl_uInt16 *addtable;
+ pl_Texture *Texture, *Environment;
+ pl_uChar stat;
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+
+ pl_sInt32 U1, V1, U2, V2, dU1=0, dU2=0, dV1=0, dV2=0, dUL=0, dVL=0, UL, VL;
+ pl_sInt32 eU1, eV1, eU2, eV2, edU1=0, edU2=0, edV1=0,
+ edV2=0, edUL=0, edVL=0, eUL, eVL;
+ pl_sInt32 X1, X2, dX1=0, dX2=0, XL1, XL2;
+ pl_Float Z1, ZL, dZ1=0, dZ2=0, dZL=0, Z2;
+ pl_sInt32 Y1, Y2, Y0, dY;
+
+ Environment = TriFace->Material->Environment;
+ Texture = TriFace->Material->Texture;
+
+ if (!Texture || !Environment) return;
+ texture = Texture->Data;
+ environment = Environment->Data;
+ addtable = TriFace->Material->_AddTable;
+ remap = TriFace->Material->_ReMapTable;
+
+ MappingV_AND = ((1<<Texture->Height)-1)<<Texture->Width;
+ MappingU_AND = (1<<Texture->Width)-1;
+ vshift = 16 - Texture->Width;
+ eMappingV_AND = ((1<<Environment->Height)-1)<<Environment->Width;
+ eMappingU_AND = (1<<Environment->Width)-1;
+ evshift = 16 - Environment->Width;
+
+ PUTFACE_SORT_TEX();
+
+ eMappingU1=(pl_sInt32) (TriFace->eMappingU[i0]*Environment->uScale*TriFace->Material->EnvScaling);
+ eMappingV1=(pl_sInt32) (TriFace->eMappingV[i0]*Environment->vScale*TriFace->Material->EnvScaling);
+ eMappingU2=(pl_sInt32) (TriFace->eMappingU[i1]*Environment->uScale*TriFace->Material->EnvScaling);
+ eMappingV2=(pl_sInt32) (TriFace->eMappingV[i1]*Environment->vScale*TriFace->Material->EnvScaling);
+ eMappingU3=(pl_sInt32) (TriFace->eMappingU[i2]*Environment->uScale*TriFace->Material->EnvScaling);
+ eMappingV3=(pl_sInt32) (TriFace->eMappingV[i2]*Environment->vScale*TriFace->Material->EnvScaling);
+
+ U1 = U2 = MappingU1;
+ V1 = V2 = MappingV1;
+ eU1 = eU2 = eMappingU1;
+ eV1 = eV2 = eMappingV1;
+ X2 = X1 = TriFace->Scrx[i0];
+ Z2 = Z1 = TriFace->Scrz[i0];
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2 - Y0;
+ if (dY) {
+ dU2 = (MappingU3 - U1) / dY;
+ dV2 = (MappingV3 - V1) / dY;
+ edU2 = (eMappingU3 - eU1) / dY;
+ edV2 = (eMappingV3 - eV1) / dY;
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dZ2 = (TriFace->Scrz[i2] - Z1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dU1 = (MappingU2 - U1) / dY;
+ dV1 = (MappingV2 - V1) / dY;
+ edU1 = (eMappingU2 - eU1) / dY;
+ edV1 = (eMappingV2 - eV1) / dY;
+ dZ1 = (TriFace->Scrz[i1] - Z1) / dY;
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dU2 ^= dU1; dU1 ^= dU2; dU2 ^= dU1;
+ dV2 ^= dV1; dV1 ^= dV2; dV2 ^= dV1;
+ edU2 ^= edU1; edU1 ^= edU2; edU2 ^= edU1;
+ edV2 ^= edV1; edV1 ^= edV2; edV2 ^= edV1;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ Z2 = TriFace->Scrz[i1];
+ U2 = MappingU2;
+ V2 = MappingV2;
+ eU2 = eMappingU2;
+ eV2 = eMappingV2;
+ stat = 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ Z1 = TriFace->Scrz[i1];
+ U1 = MappingU2;
+ V1 = MappingV2;
+ eU1 = eMappingU2;
+ eV1 = eMappingV2;
+ stat = 1|8;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+
+ XL1 = (((dX1-dX2)*dY+(1<<19))>>20);
+ if (XL1) {
+ dUL = ((dU1-dU2)*dY)/XL1;
+ dVL = ((dV1-dV2)*dY)/XL1;
+ edUL = ((edU1-edU2)*dY)/XL1;
+ edVL = ((edV1-edV2)*dY)/XL1;
+ dZL = ((dZ1-dZ2)*dY)/XL1;
+ } else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) {
+ edUL = (eU2-eU1)/XL1;
+ edVL = (eV2-eV1)/XL1;
+ dUL = (U2-U1)/XL1;
+ dVL = (V2-V1)/XL1;
+ dZL = (Z2-Z1)/XL1;
+ }
+ }
+
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2 - ((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (TriFace->Scrz[i2]-Z1)/dY;
+ dV1 = (MappingV3 - V1) / dY;
+ dU1 = (MappingU3 - U1) / dY;
+ edV1 = (eMappingV3 - eV1) / dY;
+ edU1 = (eMappingU3 - eU1) / dY;
+ }
+ }
+ XL1 = (X1+(1<<19))>>20;
+ XL2 = (X2+(1<<19))>>20;
+ ZL = Z1;
+ UL = U1;
+ VL = V1;
+ eUL = eU1;
+ eVL = eV1;
+ if ((XL2-XL1) > 0) {
+ XL2 -= XL1;
+ gmem += XL1;
+ zbuf += XL1;
+ XL1 += XL2;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ *zbuf = ZL;
+ *gmem = remap[addtable[environment[
+ ((eUL>>16)&eMappingU_AND)+((eVL>>evshift)&eMappingV_AND)]] +
+ texture[((UL>>16)&MappingU_AND) +
+ ((VL>>vshift)&MappingV_AND)]];
+ }
+ zbuf++;
+ gmem++;
+ ZL += dZL;
+ UL += dUL;
+ VL += dVL;
+ eUL += edUL;
+ eVL += edVL;
+ } while (--XL2);
+ else do {
+ *gmem++ = remap[addtable[environment[
+ ((eUL>>16)&eMappingU_AND)+((eVL>>evshift)&eMappingV_AND)]] +
+ texture[((UL>>16)&MappingU_AND) +
+ ((VL>>vshift)&MappingV_AND)]];
+ UL += dUL;
+ VL += dVL;
+ eUL += edUL;
+ eVL += edVL;
+ } while (--XL2);
+ gmem -= XL1;
+ zbuf -= XL1;
+ }
+ zbuf += cam->ScreenWidth;
+ gmem += cam->ScreenWidth;
+ Z1 += dZ1;
+ X1 += dX1;
+ X2 += dX2;
+ U1 += dU1;
+ V1 += dV1;
+ eU1 += edU1;
+ eV1 += edV1;
+ Y0++;
+ }
+}
+
+void plPF_TexF(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+ pl_sInt32 MappingU1, MappingU2, MappingU3;
+ pl_sInt32 MappingV1, MappingV2, MappingV3;
+ pl_sInt32 MappingU_AND, MappingV_AND;
+ pl_uChar *texture;
+ pl_uChar vshift;
+ pl_uInt bc;
+ pl_uChar *remap;
+ pl_Texture *Texture;
+ pl_uChar stat;
+
+ pl_ZBuffer Z1, ZL, dZ1=0, dZL=0, Z2, dZ2=0;
+ pl_sInt32 dU1=0, dV1=0, dU2=0, dV2=0, U1, V1, U2, V2;
+ pl_sInt32 dUL=0, dVL=0, UL, VL;
+ pl_sInt32 X1, X2, dX1=0, dX2=0, XL1, XL2;
+ pl_sInt32 Y1, Y2, Y0, dY;
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+ pl_sInt shade;
+
+ if (TriFace->Material->Environment) Texture = TriFace->Material->Environment;
+ else Texture = TriFace->Material->Texture;
+
+ if (!Texture) return;
+ remap = TriFace->Material->_ReMapTable;
+ if (TriFace->Material->_AddTable)
+ {
+ shade=(pl_sInt)(TriFace->fShade*255.0f);
+ if (shade < 0) shade=0;
+ if (shade > 255) shade=255;
+ bc = TriFace->Material->_AddTable[shade];
+ }
+ else bc=0;
+ texture = Texture->Data;
+ vshift = 16 - Texture->Width;
+ MappingV_AND = ((1<<Texture->Height)-1)<<Texture->Width;
+ MappingU_AND = (1<<Texture->Width)-1;
+
+ if (TriFace->Material->Environment) {
+ PUTFACE_SORT_ENV();
+ } else {
+ PUTFACE_SORT_TEX();
+ }
+
+ U1 = U2 = MappingU1;
+ V1 = V2 = MappingV1;
+ X2 = X1 = TriFace->Scrx[i0];
+ Z2 = Z1 = TriFace->Scrz[i0];
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2 - Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dV2 = (MappingV3 - V1) / dY;
+ dU2 = (MappingU3 - U1) / dY;
+ dZ2 = (TriFace->Scrz[i2] - Z1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dZ1 = (TriFace->Scrz[i1] - Z1) / dY;
+ dU1 = (MappingU2 - U1) / dY;
+ dV1 = (MappingV2 - V1) / dY;
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dU2 ^= dU1; dU1 ^= dU2; dU2 ^= dU1;
+ dV2 ^= dV1; dV1 ^= dV2; dV2 ^= dV1;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ Z2 = TriFace->Scrz[i1];
+ U2 = MappingU2;
+ V2 = MappingV2;
+ stat = 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ Z1 = TriFace->Scrz[i1];
+ U1 = MappingU2;
+ V1 = MappingV2;
+ stat = 1|8;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+
+ XL1 = (((dX1-dX2)*dY+(1<<19))>>20);
+ if (XL1) {
+ dUL = ((dU1-dU2)*dY)/XL1;
+ dVL = ((dV1-dV2)*dY)/XL1;
+ dZL = ((dZ1-dZ2)*dY)/XL1;
+ } else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) {
+ dUL = (U2-U1)/XL1;
+ dVL = (V2-V1)/XL1;
+ dZL = (Z2-Z1)/XL1;
+ }
+ }
+
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2 - ((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (TriFace->Scrz[i2]-Z1) / dY;
+ dV1 = (MappingV3 - V1) / dY;
+ dU1 = (MappingU3 - U1) / dY;
+ }
+ }
+ XL1 = (X1+(1<<19))>>20;
+ XL2 = (X2+(1<<19))>>20;
+ ZL = Z1;
+ UL = U1;
+ VL = V1;
+ if ((XL2-XL1) > 0) {
+ XL2 -= XL1;
+ gmem += XL1;
+ zbuf += XL1;
+ XL1 += XL2;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ *zbuf = ZL;
+ *gmem = remap[bc + texture[((UL >> 16)&MappingU_AND) +
+ ((VL>>vshift)&MappingV_AND)]];
+ }
+ zbuf++;
+ gmem++;
+ ZL += dZL;
+ UL += dUL;
+ VL += dVL;
+ } while (--XL2);
+ else do {
+ *gmem++ = remap[bc + texture[((UL >> 16)&MappingU_AND) +
+ ((VL>>vshift)&MappingV_AND)]];
+ UL += dUL;
+ VL += dVL;
+ } while (--XL2);
+ gmem -= XL1;
+ zbuf -= XL1;
+ }
+ zbuf += cam->ScreenWidth;
+ gmem += cam->ScreenWidth;
+ X1 += dX1;
+ X2 += dX2;
+ U1 += dU1;
+ V1 += dV1;
+ Z1 += dZ1;
+ Y0++;
+ }
+}
+
+void plPF_TexG(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+ pl_sInt32 MappingU1, MappingU2, MappingU3;
+ pl_sInt32 MappingV1, MappingV2, MappingV3;
+ pl_sInt32 MappingU_AND, MappingV_AND;
+ pl_uChar *texture;
+ pl_uChar *remap;
+ pl_uChar vshift;
+ pl_uInt16 *addtable;
+ pl_Texture *Texture;
+
+ pl_sInt32 U1, V1, U2, V2, dU1=0, dU2=0, dV1=0, dV2=0, dUL=0, dVL=0, UL, VL;
+ pl_sInt32 X1, X2, dX1=0, dX2=0, XL1, XL2;
+ pl_sInt32 C1, C2, dC1=0, dC2=0, CL, dCL=0;
+ pl_ZBuffer Z1, ZL, dZ1=0, dZ2=0, dZL=0, Z2;
+ pl_sInt32 Y1, Y2, Y0, dY;
+ pl_uChar stat;
+
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+
+ if (TriFace->Material->Environment) Texture = TriFace->Material->Environment;
+ else Texture = TriFace->Material->Texture;
+
+ if (!Texture) return;
+ remap = TriFace->Material->_ReMapTable;
+ texture = Texture->Data;
+ addtable = TriFace->Material->_AddTable;
+ vshift = 16 - Texture->Width;
+ MappingV_AND = ((1<<Texture->Height)-1)<<Texture->Width;
+ MappingU_AND = (1<<Texture->Width)-1;
+
+ if (TriFace->Material->Environment) {
+ PUTFACE_SORT_ENV();
+ } else {
+ PUTFACE_SORT_TEX();
+ }
+
+ C1 = C2 = TriFace->Shades[i0]*65535.0f;
+ U1 = U2 = MappingU1;
+ V1 = V2 = MappingV1;
+ X2 = X1 = TriFace->Scrx[i0];
+ Z2 = Z1 = TriFace->Scrz[i0];
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2 - Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dZ2 = (TriFace->Scrz[i2] - Z1) / dY;
+ dC2 = (TriFace->Shades[i2]*65535.0f - C1) / dY;
+ dU2 = (MappingU3 - U1) / dY;
+ dV2 = (MappingV3 - V1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dZ1 = (TriFace->Scrz[i1] - Z1) / dY;
+ dC1 = (TriFace->Shades[i1]*65535.0f - C1) / dY;
+ dU1 = (MappingU2 - U1) / dY;
+ dV1 = (MappingV2 - V1) / dY;
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dU2 ^= dU1; dU1 ^= dU2; dU2 ^= dU1;
+ dV2 ^= dV1; dV1 ^= dV2; dV2 ^= dV1;
+ dC2 ^= dC1; dC1 ^= dC2; dC2 ^= dC1;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ Z2 = TriFace->Scrz[i1];
+ C2 = TriFace->Shades[i1]*65535.0f;
+ U2 = MappingU2;
+ V2 = MappingV2;
+ stat = 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ Z1 = TriFace->Scrz[i1];
+ C1 = TriFace->Shades[i1]*65535.0f;
+ U1 = MappingU2;
+ V1 = MappingV2;
+ stat = 1|8;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+
+ XL1 = (((dX1-dX2)*dY+(1<<19))>>20);
+ if (XL1) {
+ dUL = ((dU1-dU2)*dY)/XL1;
+ dVL = ((dV1-dV2)*dY)/XL1;
+ if (zb) dZL = ((dZ1-dZ2)*dY)/XL1;
+ dCL = ((dC1-dC2)*dY)/XL1;
+ } else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) {
+ dUL = (U2-U1)/XL1;
+ dVL = (V2-V1)/XL1;
+ if (zb) dZL = (Z2-Z1)/XL1;
+ dCL = (C2-C1)/(XL1);
+ }
+ }
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2 - ((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (TriFace->Scrz[i2]-Z1)/dY;
+ dV1 = (MappingV3 - V1) / dY;
+ dU1 = (MappingU3 - U1) / dY;
+ dC1 = (TriFace->Shades[i2]*65535.0f-C1)/dY;
+ }
+ }
+ XL1 = (X1+(1<<19))>>20;
+ XL2 = (X2+(1<<19))>>20;
+ CL = C1;
+ ZL = Z1;
+ UL = U1;
+ VL = V1;
+ if ((XL2-XL1) > 0) {
+ XL2 -= XL1;
+ gmem += XL1;
+ zbuf += XL1;
+ XL1 += XL2;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ int av;
+ if (CL < 0) av=addtable[0];
+ else if (CL > (255<<8)) av=addtable[255];
+ else av=addtable[CL>>8];
+ *zbuf = ZL;
+ *gmem = remap[av +
+ texture[((UL>>16)&MappingU_AND) +
+ ((VL>>vshift)&MappingV_AND)]];
+ }
+ zbuf++;
+ gmem++;
+ ZL += dZL;
+ CL += dCL;
+ UL += dUL;
+ VL += dVL;
+ } while (--XL2);
+ else do {
+ int av;
+ if (CL < 0) av=addtable[0];
+ else if (CL > (255<<8)) av=addtable[255];
+ else av=addtable[CL>>8];
+ *gmem++ = remap[av +
+ texture[((UL>>16)&MappingU_AND) +
+ ((VL>>vshift)&MappingV_AND)]];
+ CL += dCL;
+ UL += dUL;
+ VL += dVL;
+ } while (--XL2);
+ gmem -= XL1;
+ zbuf -= XL1;
+ }
+ zbuf += cam->ScreenWidth;
+ gmem += cam->ScreenWidth;
+ Z1 += dZ1;
+ X1 += dX1;
+ X2 += dX2;
+ C1 += dC1;
+ U1 += dU1;
+ V1 += dV1;
+ Y0++;
+ }
+}
diff --git a/Src/Winamp/plush/PF_TRANS.C b/Src/Winamp/plush/PF_TRANS.C
new file mode 100644
index 00000000..d82365ee
--- /dev/null
+++ b/Src/Winamp/plush/PF_TRANS.C
@@ -0,0 +1,263 @@
+/******************************************************************************
+Plush Version 1.2
+pf_trans.c
+Solid Translucent Rasterizers
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+#include "putface.h"
+
+void plPF_TransF(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_uChar *remap = TriFace->Material->_ReMapTable;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+ pl_sInt32 X1, X2, dX1=0, dX2=0, XL1, XL2;
+ pl_ZBuffer Z1, ZL, dZ1=0, dZL=0, dZ2=0, Z2;
+ pl_sInt32 Y1, Y2, Y0, dY;
+ pl_uInt16 *lookuptable = TriFace->Material->_AddTable;
+ pl_uChar stat;
+ pl_sInt32 bc = (pl_sInt32) TriFace->fShade*TriFace->Material->_tsfact;
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+
+ PUTFACE_SORT();
+
+ if (bc < 0) bc=0;
+ if (bc > (pl_sInt32) TriFace->Material->_tsfact-1) bc=TriFace->Material->_tsfact-1;
+ remap+=bc;
+
+ X2 = X1 = TriFace->Scrx[i0];
+ Z2 = Z1 = TriFace->Scrz[i0];
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2 - Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dZ2 = (TriFace->Scrz[i2] - Z1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dZ1 = (TriFace->Scrz[i1] - Z1) / dY;
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ Z2 = TriFace->Scrz[i1];
+ stat= 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ Z1 = TriFace->Scrz[i1];
+ stat= 1|8;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+ if (zb) {
+ XL1 = (((dX1-dX2)*dY+(1<<19))>>20);
+ if (XL1) dZL = ((dZ1-dZ2)*dY)/XL1;
+ else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) dZL = (Z2-Z1)/XL1;
+ }
+ }
+
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2 - ((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (TriFace->Scrz[i2]- Z1)/dY;
+ }
+ }
+ XL1 = (X1+(1<<19))>>20;
+ XL2 = (X2+(1<<19))>>20;
+ ZL = Z1;
+ if ((XL2-XL1) > 0) {
+ XL2 -= XL1;
+ zbuf += XL1;
+ gmem += XL1;
+ XL1 += XL2;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ *zbuf = ZL;
+ *gmem = remap[lookuptable[*gmem]];
+ }
+ gmem++;
+ zbuf++;
+ ZL += dZL;
+ } while (--XL2);
+ else do *gmem++ = remap[lookuptable[*gmem]]; while (--XL2);
+ gmem -= XL1;
+ zbuf -= XL1;
+ }
+ gmem += cam->ScreenWidth;
+ zbuf += cam->ScreenWidth;
+ Z1 += dZ1;
+ X1 += dX1;
+ X2 += dX2;
+ Y0 ++;
+ }
+}
+
+void plPF_TransG(pl_Cam *cam, pl_Face *TriFace) {
+ pl_uChar i0, i1, i2;
+ pl_uChar *gmem = cam->frameBuffer;
+ pl_uChar *remap = TriFace->Material->_ReMapTable;
+ pl_ZBuffer *zbuf = cam->zBuffer;
+ pl_sInt32 X1, X2, dX1=0, dX2=0, XL1, XL2;
+ pl_ZBuffer Z1, ZL, dZ1=0, dZL=0, dZ2=0, Z2;
+ pl_sInt32 dC1=0, dCL=0, CL, C1, C2, dC2=0;
+ pl_sInt32 Y1, Y2, Y0, dY;
+ pl_Float nc = (TriFace->Material->_tsfact*65536.0f);
+ pl_uInt16 *lookuptable = TriFace->Material->_AddTable;
+ pl_Bool zb = (zbuf&&TriFace->Material->zBufferable) ? 1 : 0;
+ pl_uChar stat;
+
+ pl_sInt32 maxColor=((TriFace->Material->_tsfact-1)<<16);
+ pl_sInt32 maxColorNonShift=TriFace->Material->_tsfact-1;
+
+ PUTFACE_SORT();
+
+ C1 = C2 = (pl_sInt32) (TriFace->Shades[i0]*nc);
+ X2 = X1 = TriFace->Scrx[i0];
+ Z2 = Z1 = TriFace->Scrz[i0];
+ Y0 = (TriFace->Scry[i0]+(1<<19))>>20;
+ Y1 = (TriFace->Scry[i1]+(1<<19))>>20;
+ Y2 = (TriFace->Scry[i2]+(1<<19))>>20;
+
+ dY = Y2 - Y0;
+ if (dY) {
+ dX2 = (TriFace->Scrx[i2] - X1) / dY;
+ dC2 = (pl_sInt32) ((TriFace->Shades[i2]*nc - C1) / dY);
+ dZ2 = (TriFace->Scrz[i2] - Z1) / dY;
+ }
+ dY = Y1-Y0;
+ if (dY) {
+ dX1 = (TriFace->Scrx[i1] - X1) / dY;
+ dZ1 = (TriFace->Scrz[i1] - Z1) / dY;
+ dC1 = (pl_sInt32) ((TriFace->Shades[i1]*nc - C1) / dY);
+ if (dX2 < dX1) {
+ dX2 ^= dX1; dX1 ^= dX2; dX2 ^= dX1;
+ dC2 ^= dC1; dC1 ^= dC2; dC2 ^= dC1;
+ dZL = dZ1; dZ1 = dZ2; dZ2 = dZL;
+ stat = 2;
+ } else stat = 1;
+ } else {
+ if (TriFace->Scrx[i1] > X1) {
+ X2 = TriFace->Scrx[i1];
+ Z2 = TriFace->Scrz[i1];
+ C2 = (pl_sInt32) (TriFace->Shades[i1]*nc);
+ stat = 2|4;
+ } else {
+ X1 = TriFace->Scrx[i1];
+ Z1 = TriFace->Scrz[i1];
+ C1 = (pl_sInt32) (TriFace->Shades[i1]*nc);
+ stat = 1|8;
+ }
+ }
+
+ gmem += (Y0 * cam->ScreenWidth);
+ zbuf += (Y0 * cam->ScreenWidth);
+ XL1 = (((dX1-dX2)*dY+(1<<19))>>20);
+ if (XL1) {
+ dCL = ((dC1-dC2)*dY)/XL1;
+ dZL = ((dZ1-dZ2)*dY)/XL1;
+ } else {
+ XL1 = ((X2-X1+(1<<19))>>20);
+ if (XL1) {
+ dCL = (C2-C1)/XL1;
+ dZL = (Z2-Z1)/XL1;
+ }
+ }
+
+ while (Y0 < Y2) {
+ if (Y0 == Y1) {
+ dY = Y2 - ((TriFace->Scry[i1]+(1<<19))>>20);
+ if (dY) {
+ if (stat & 1) {
+ X1 = TriFace->Scrx[i1];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 2) {
+ X2 = TriFace->Scrx[i1];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i1])/dY;
+ }
+ if (stat & 4) {
+ X1 = TriFace->Scrx[i0];
+ dX1 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ if (stat & 8) {
+ X2 = TriFace->Scrx[i0];
+ dX2 = (TriFace->Scrx[i2]-TriFace->Scrx[i0])/dY;
+ }
+ dZ1 = (TriFace->Scrz[i2]-Z1)/dY;
+ dC1 = (pl_sInt32) ((TriFace->Shades[i2]*nc - C1) / dY);
+ }
+ }
+ CL = C1;
+ XL1 = (X1+(1<<19))>>20;
+ XL2 = (X2+(1<<19))>>20;
+ ZL = Z1;
+ if ((XL2-XL1) > 0) {
+ XL2 -= XL1;
+ zbuf += XL1;
+ gmem += XL1;
+ XL1 += XL2;
+ if (zb) do {
+ if (*zbuf < ZL) {
+ int av;
+ if (CL >= maxColor) av=maxColorNonShift;
+ else if (CL > 0) av=CL>>16;
+ else av=0;
+ *zbuf = ZL;
+ *gmem = remap[av + lookuptable[*gmem]];
+ }
+ gmem++;
+ CL += dCL;
+ zbuf++;
+ ZL += dZL;
+ } while (--XL2);
+ else do {
+ int av;
+ if (CL >= maxColor) av=maxColorNonShift;
+ else if (CL > 0) av=CL>>16;
+ else av=0;
+ *gmem++ = remap[av + lookuptable[*gmem]];
+ CL += dCL;
+ } while (--XL2);
+ gmem -= XL1;
+ zbuf -= XL1;
+ }
+ gmem += cam->ScreenWidth;
+ zbuf += cam->ScreenWidth;
+ Z1 += dZ1;
+ X1 += dX1;
+ X2 += dX2;
+ C1 += dC1;
+ Y0++;
+ }
+}
diff --git a/Src/Winamp/plush/PLUSH.C b/Src/Winamp/plush/PLUSH.C
new file mode 100644
index 00000000..173fb389
--- /dev/null
+++ b/Src/Winamp/plush/PLUSH.C
@@ -0,0 +1,286 @@
+/******************************************************************************
+Plush Version 1.2
+plush.c
+Misc code and data
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+pl_uChar plText_DefaultFont[256*16] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 60, 66, 129, 231, 165, 153, 129, 153, 66, 60, 0, 0, 0, 0,
+ 0, 0, 60, 126, 255, 153, 219, 231, 255, 231, 126, 60, 0, 0, 0, 0,
+ 0, 0, 0, 0, 102, 255, 255, 255, 255, 126, 60, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 60, 126, 255, 126, 60, 24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 24, 60, 60, 90, 255, 255, 90, 24, 60, 0, 0, 0, 0,
+ 0, 0, 0, 24, 60, 126, 255, 255, 255, 90, 24, 60, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 24, 60, 60, 24, 0, 0, 0, 0, 0, 0,
+ 255,255,255, 255, 255, 255, 231, 195, 195, 231, 255, 255, 255, 255, 255, 255,
+ 0, 0, 0, 0, 0, 60, 102, 66, 66, 102, 60, 0, 0, 0, 0, 0,
+ 255,255,255, 255, 255, 195, 153, 189, 189, 153, 195, 255, 255, 255, 255, 255,
+ 0, 0, 15, 7, 13, 24, 62, 99, 195, 195, 198, 124, 0, 0, 0, 0,
+ 0, 0, 126, 195, 195, 195, 126, 24, 24, 30, 120, 24, 0, 0, 0, 0,
+ 0, 0, 8, 12, 14, 11, 8, 8, 8, 120, 248, 112, 0, 0, 0, 0,
+ 0, 16, 24, 28, 22, 26, 22, 18, 114, 242, 98, 14, 30, 12, 0, 0,
+ 0, 0, 24, 24, 219, 126, 60, 255, 60, 126, 219, 24, 24, 0, 0, 0,
+ 0, 0, 96, 112, 120, 124, 126, 126, 124, 120, 112, 96, 0, 0, 0, 0,
+ 0, 0, 6, 14, 30, 62, 126, 126, 62, 30, 14, 6, 0, 0, 0, 0,
+ 0, 0, 16, 56, 124, 254, 56, 56, 56, 56, 254, 124, 56, 16, 0, 0,
+ 0, 0, 102, 102, 102, 102, 102, 102, 102, 0, 102, 102, 0, 0, 0, 0,
+ 0, 0, 63, 123, 219, 219, 219, 127, 59, 27, 27, 27, 0, 0, 0, 0,
+ 0, 31, 48, 120, 220, 206, 231, 115, 59, 30, 12, 24, 48, 224, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 126, 126, 126, 126, 0, 0, 0, 0,
+ 0, 0, 16, 56, 124, 254, 56, 56, 56, 254, 124, 56, 16, 0, 254, 0,
+ 0, 0, 16, 56, 124, 254, 56, 56, 56, 56, 56, 56, 56, 56, 0, 0,
+ 0, 0, 56, 56, 56, 56, 56, 56, 56, 56, 254, 124, 56, 16, 0, 0,
+ 0, 0, 0, 0, 0, 8, 12, 254, 255, 254, 12, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 16, 48, 127, 255, 127, 48, 16, 0, 0, 0, 0,
+ 0, 0, 204, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 36, 102, 255, 255, 102, 36, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 60, 60, 126, 126, 255, 255, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 255, 255, 126, 126, 60, 60, 24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 24, 24, 24, 24, 24, 24, 24, 0, 24, 24, 0, 0, 0, 0,
+ 0, 0, 51, 102, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 51, 51, 255, 102, 102, 102, 102, 255, 204, 204, 0, 0, 0, 0,
+ 0, 24, 126, 219, 216, 120, 28, 30, 27, 219, 219, 126, 24, 0, 0, 0,
+ 0, 0, 96, 209, 179, 102, 12, 24, 54, 109, 203, 6, 0, 0, 0, 0,
+ 0, 0, 28, 54, 102, 60, 56, 108, 199, 198, 110, 59, 0, 0, 0, 0,
+ 0, 0, 12, 24, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 12, 24, 48, 48, 96, 96, 96, 96, 48, 48, 24, 12, 0, 0, 0,
+ 0, 48, 24, 12, 12, 6, 6, 6, 6, 12, 12, 24, 48, 0, 0, 0,
+ 0, 0, 102, 60, 255, 60, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 24, 24, 126, 24, 24, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 24, 48, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 0,
+ 0, 0, 6, 4, 12, 8, 24, 16, 48, 32, 96, 64, 192, 0, 0, 0,
+ 0, 0, 62, 99, 195, 195, 195, 207, 219, 243, 198, 124, 0, 0, 0, 0,
+ 0, 0, 12, 28, 60, 108, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0,
+ 0, 0, 62, 99, 195, 3, 6, 12, 24, 48, 99, 255, 0, 0, 0, 0,
+ 0, 0, 255, 198, 12, 24, 62, 3, 3, 195, 198, 124, 0, 0, 0, 0,
+ 0, 0, 6, 14, 30, 54, 102, 199, 222, 246, 6, 6, 0, 0, 0, 0,
+ 0, 0, 31, 240, 192, 220, 246, 3, 3, 195, 198, 124, 0, 0, 0, 0,
+ 0, 0, 60, 102, 198, 192, 220, 246, 198, 198, 204, 120, 0, 0, 0, 0,
+ 0, 0, 255, 195, 6, 12, 12, 24, 24, 48, 48, 48, 0, 0, 0, 0,
+ 0, 0, 60, 102, 198, 108, 62, 99, 195, 195, 198, 124, 0, 0, 0, 0,
+ 0, 0, 60, 102, 198, 198, 222, 118, 6, 198, 204, 120, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 24, 0, 0, 0, 24, 24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 24, 0, 0, 0, 24, 24, 48, 0, 0, 0, 0,
+ 0, 0, 6, 12, 24, 48, 96, 96, 48, 24, 12, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 255, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 96, 48, 24, 12, 6, 6, 12, 24, 48, 96, 0, 0, 0, 0,
+ 0, 0, 62, 99, 198, 12, 24, 48, 48, 0, 48, 48, 0, 0, 0, 0,
+ 0, 0, 30, 51, 111, 219, 219, 219, 222, 216, 198, 220, 112, 0, 0, 0,
+ 0, 0, 24, 24, 60, 36, 102, 110, 122, 227, 195, 195, 0, 0, 0, 0,
+ 0, 0, 30, 51, 227, 198, 220, 247, 195, 198, 220, 240, 0, 0, 0, 0,
+ 0, 0, 30, 51, 96, 192, 192, 192, 192, 192, 99, 62, 0, 0, 0, 0,
+ 0, 0, 252, 198, 195, 195, 195, 195, 195, 198, 220, 240, 0, 0, 0, 0,
+ 0, 0, 30, 240, 192, 192, 220, 240, 192, 192, 222, 240, 0, 0, 0, 0,
+ 0, 0, 30, 240, 192, 192, 220, 240, 192, 192, 192, 192, 0, 0, 0, 0,
+ 0, 0, 62, 99, 192, 192, 192, 207, 195, 195, 102, 60, 0, 0, 0, 0,
+ 0, 0, 195, 195, 195, 195, 207, 251, 195, 195, 195, 195, 0, 0, 0, 0,
+ 0, 0, 28, 56, 24, 24, 24, 24, 24, 24, 28, 56, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 3, 3, 3, 195, 195, 99, 62, 0, 0, 0, 0,
+ 0, 0, 195, 198, 220, 240, 224, 240, 216, 204, 198, 195, 0, 0, 0, 0,
+ 0, 0, 192, 192, 192, 192, 192, 192, 192, 192, 222, 240, 0, 0, 0, 0,
+ 0, 0, 195, 195, 231, 239, 251, 211, 195, 195, 195, 195, 0, 0, 0, 0,
+ 0, 0, 195, 195, 227, 243, 211, 219, 207, 199, 195, 195, 0, 0, 0, 0,
+ 0, 0, 62, 99, 195, 195, 195, 195, 195, 195, 198, 124, 0, 0, 0, 0,
+ 0, 0, 30, 51, 227, 195, 198, 220, 240, 192, 192, 192, 0, 0, 0, 0,
+ 0, 0, 62, 99, 195, 195, 195, 195, 243, 222, 204, 124, 6, 3, 0, 0,
+ 0, 0, 30, 51, 227, 195, 198, 252, 216, 204, 198, 195, 0, 0, 0, 0,
+ 0, 0, 126, 195, 192, 112, 28, 6, 3, 195, 195, 126, 0, 0, 0, 0,
+ 0, 0, 15, 248, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 0, 0, 195, 195, 195, 195, 195, 195, 198, 198, 204, 120, 0, 0, 0, 0,
+ 0, 0, 195, 195, 195, 195, 102, 102, 124, 56, 48, 48, 0, 0, 0, 0,
+ 0, 0, 195, 195, 195, 195, 219, 219, 219, 255, 231, 195, 0, 0, 0, 0,
+ 0, 0, 195, 195, 102, 102, 60, 60, 102, 102, 195, 195, 0, 0, 0, 0,
+ 0, 0, 195, 195, 102, 102, 60, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 0, 0, 31, 246, 4, 12, 24, 16, 48, 32, 111, 248, 0, 0, 0, 0,
+ 0, 62, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 62, 0, 0, 0,
+ 0, 0, 192, 64, 96, 32, 48, 16, 24, 8, 12, 4, 6, 0, 0, 0,
+ 0, 124, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 124, 0, 0, 0,
+ 0, 24, 60, 102, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0,
+ 0, 0, 48, 24, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 62, 99, 31, 115, 195, 207, 123, 0, 0, 0, 0,
+ 0, 0, 192, 192, 192, 220, 246, 195, 195, 198, 220, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 30, 51, 96, 192, 192, 195, 126, 0, 0, 0, 0,
+ 0, 0, 3, 3, 3, 31, 115, 195, 199, 207, 219, 115, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 62, 99, 206, 248, 192, 195, 126, 0, 0, 0, 0,
+ 0, 0, 30, 51, 48, 48, 60, 240, 48, 48, 48, 48, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 63, 99, 195, 199, 207, 219, 115, 3, 195, 126, 0,
+ 0, 0, 192, 192, 192, 206, 219, 243, 227, 195, 195, 195, 0, 0, 0, 0,
+ 0, 0, 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 0, 0, 12, 12, 0, 12, 12, 12, 12, 12, 12, 12, 204, 204, 120, 0,
+ 0, 0, 192, 192, 192, 198, 204, 216, 248, 236, 198, 195, 0, 0, 0, 0,
+ 0, 0, 56, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 230, 219, 219, 219, 195, 195, 195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 206, 219, 243, 227, 195, 195, 195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 62, 99, 195, 195, 195, 198, 124, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 206, 219, 243, 227, 195, 198, 252, 192, 192, 192, 0,
+ 0, 0, 0, 0, 0, 115, 219, 207, 199, 195, 99, 63, 3, 3, 3, 0,
+ 0, 0, 0, 0, 0, 206, 219, 243, 224, 192, 192, 192, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 126, 195, 112, 30, 3, 195, 126, 0, 0, 0, 0,
+ 0, 0, 16, 48, 48, 60, 240, 48, 48, 54, 60, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 195, 195, 195, 199, 207, 219, 115, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 195, 195, 195, 102, 108, 56, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 195, 195, 195, 219, 219, 255, 195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 195, 102, 60, 24, 60, 102, 195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 195, 195, 195, 195, 195, 102, 62, 12, 216, 112, 0,
+ 0, 0, 0, 0, 0, 255, 6, 12, 24, 48, 96, 255, 0, 0, 0, 0,
+ 0, 14, 24, 24, 24, 24, 112, 112, 24, 24, 24, 24, 14, 0, 0, 0,
+ 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0,
+ 0, 112, 24, 24, 24, 24, 14, 14, 24, 24, 24, 24, 112, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 118, 220, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 16, 56, 108, 198, 198, 198, 254, 0, 0, 0, 0, 0,
+ 0, 0, 30, 51, 96, 192, 192, 192, 192, 192, 99, 62, 12, 24, 240, 0,
+ 0, 0, 102, 102, 0, 195, 195, 195, 199, 207, 219, 115, 0, 0, 0, 0,
+ 0, 6, 12, 24, 0, 62, 99, 206, 248, 192, 195, 126, 0, 0, 0, 0,
+ 12, 30, 51, 96, 0, 62, 99, 31, 115, 195, 207, 123, 0, 0, 0, 0,
+ 0, 0, 54, 54, 0, 62, 99, 31, 115, 195, 207, 123, 0, 0, 0, 0,
+ 0, 48, 24, 12, 0, 62, 99, 31, 115, 195, 207, 123, 0, 0, 0, 0,
+ 28, 54, 54, 28, 0, 62, 99, 31, 115, 195, 207, 123, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 30, 51, 96, 192, 192, 195, 126, 12, 24, 240, 0,
+ 24, 60, 102, 192, 0, 62, 99, 206, 248, 192, 195, 126, 0, 0, 0, 0,
+ 0, 0, 102, 102, 0, 62, 99, 206, 248, 192, 195, 126, 0, 0, 0, 0,
+ 0, 96, 48, 24, 0, 62, 99, 206, 248, 192, 195, 126, 0, 0, 0, 0,
+ 0, 0, 102, 102, 0, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 24, 60, 102, 192, 0, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 0, 96, 48, 24, 0, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 102, 102, 24, 24, 60, 36, 102, 102, 126, 195, 195, 195, 0, 0, 0, 0,
+ 24, 36, 36, 24, 60, 36, 102, 102, 126, 195, 195, 195, 0, 0, 0, 0,
+ 24, 48, 96, 30, 240, 192, 222, 240, 192, 192, 222, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 126, 219, 59, 126, 220, 219, 110, 0, 0, 0, 0,
+ 0, 0, 63, 62, 60, 108, 111, 110, 124, 204, 207, 206, 0, 0, 0, 0,
+ 24, 60, 102, 192, 0, 62, 99, 195, 195, 195, 198, 124, 0, 0, 0, 0,
+ 0, 0, 102, 102, 0, 62, 99, 195, 195, 195, 198, 124, 0, 0, 0, 0,
+ 0, 96, 48, 24, 0, 62, 99, 195, 195, 195, 198, 124, 0, 0, 0, 0,
+ 24, 60, 102, 192, 0, 195, 195, 195, 199, 207, 219, 115, 0, 0, 0, 0,
+ 0, 96, 48, 24, 0, 195, 195, 195, 199, 207, 219, 115, 0, 0, 0, 0,
+ 0, 0, 102, 102, 0, 195, 195, 195, 195, 195, 102, 62, 12, 216, 112, 0,
+ 102, 0, 62, 99, 195, 195, 195, 195, 195, 195, 198, 124, 0, 0, 0, 0,
+ 102, 0, 195, 195, 195, 195, 195, 195, 198, 198, 204, 120, 0, 0, 0, 0,
+ 0, 0, 0, 8, 8, 30, 59, 104, 200, 200, 203, 126, 8, 8, 0, 0,
+ 0, 0, 60, 102, 96, 248, 96, 248, 96, 96, 99, 126, 0, 0, 0, 0,
+ 0, 0, 195, 195, 102, 102, 60, 24, 126, 24, 126, 24, 24, 0, 0, 0,
+ 0, 0, 30, 51, 227, 195, 198, 220, 248, 204, 222, 204, 15, 14, 4, 0,
+ 0, 0, 30, 51, 48, 48, 60, 240, 48, 48, 48, 48, 224, 0, 0, 0,
+ 0, 6, 12, 24, 0, 62, 99, 31, 115, 195, 207, 123, 0, 0, 0, 0,
+ 0, 6, 12, 24, 0, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 0, 6, 12, 24, 0, 62, 99, 195, 195, 195, 198, 124, 0, 0, 0, 0,
+ 0, 12, 24, 48, 0, 195, 195, 195, 199, 207, 219, 115, 0, 0, 0, 0,
+ 0, 3, 118, 220, 0, 206, 219, 243, 227, 195, 195, 195, 0, 0, 0, 0,
+ 3, 118, 220, 0, 195, 227, 243, 211, 219, 207, 199, 195, 0, 0, 0, 0,
+ 0, 0, 62, 99, 31, 115, 195, 207, 123, 0, 0, 255, 0, 0, 0, 0,
+ 0, 0, 62, 99, 195, 195, 195, 198, 124, 0, 0, 255, 0, 0, 0, 0,
+ 0, 0, 12, 12, 0, 12, 12, 24, 48, 99, 198, 124, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 254, 192, 192, 192, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 254, 6, 6, 6, 0, 0, 0, 0, 0, 0,
+ 0, 96, 225, 99, 102, 108, 24, 48, 96, 206, 155, 6, 13, 31, 0, 0,
+ 0, 96, 225, 99, 102, 108, 24, 48, 102, 206, 151, 62, 6, 6, 0, 0,
+ 0, 0, 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 54, 108, 216, 216, 108, 54, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 108, 54, 27, 27, 54, 108, 192, 0, 0, 0, 0,
+ 130, 16, 130, 16, 130, 16, 130, 16, 130, 16, 130, 16, 130, 16, 130, 16,
+ 0, 149, 0, 169, 0, 149, 0, 169, 0, 149, 0, 169, 0, 149, 0, 169,
+ 146, 73, 146, 73, 146, 73, 146, 73, 146, 73, 146, 73, 146, 73, 146, 73,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 248, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 248, 248, 248, 24, 24, 24, 24, 24, 24, 24,
+ 60, 60, 60, 60, 60, 60, 60, 60, 252, 60, 60, 60, 60, 60, 60, 60,
+ 0, 0, 0, 0, 0, 0, 0, 0, 252, 60, 60, 60, 60, 60, 60, 60,
+ 0, 0, 0, 0, 0, 0, 248, 248, 248, 24, 24, 24, 24, 24, 24, 24,
+ 60, 60, 60, 60, 60, 60, 252, 252, 252, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 0, 0, 0, 0, 0, 0, 252, 252, 252, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 252, 252, 252, 0, 0, 0, 0, 0, 0, 0,
+ 60, 60, 60, 60, 60, 60, 60, 60, 252, 0, 0, 0, 0, 0, 0, 0,
+ 24, 24, 24, 24, 24, 24, 248, 248, 248, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 248, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 31, 0, 0, 0, 0, 0, 0, 0,
+ 24, 24, 24, 24, 24, 24, 24, 24, 255, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 255, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 31, 24, 24, 24, 24, 24, 24, 24,
+ 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0,
+ 24, 24, 24, 24, 24, 24, 24, 24, 255, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 31, 31, 31, 24, 24, 24, 24, 24, 24, 24,
+ 60, 60, 60, 60, 60, 60, 60, 60, 63, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 63, 63, 63, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 63, 63, 63, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 255, 255, 255, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 63, 63, 63, 60, 60, 60, 60, 60, 60, 60,
+ 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
+ 60, 60, 60, 60, 60, 60, 255, 255, 255, 60, 60, 60, 60, 60, 60, 60,
+ 24, 24, 24, 24, 24, 24, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
+ 60, 60, 60, 60, 60, 60, 60, 60, 255, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 255, 255, 255, 24, 24, 24, 24, 24, 24, 24,
+ 0, 0, 0, 0, 0, 0, 0, 0, 255, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 63, 0, 0, 0, 0, 0, 0, 0,
+ 24, 24, 24, 24, 24, 24, 31, 31, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 31, 31, 31, 24, 24, 24, 24, 24, 24, 24,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 255, 60, 60, 60, 60, 60, 60, 60,
+ 24, 24, 24, 24, 24, 24, 255, 255, 255, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 248, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 31, 24, 24, 24, 24, 24, 24, 24,
+ 255, 255, 255,255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
+ 240, 240, 240, 240,240,240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 3, 118, 204, 204, 204, 222, 115, 0, 0, 0, 0,
+ 0, 0, 30, 51, 227, 194, 204, 194, 195, 195, 206, 216, 192, 192, 0, 0,
+ 0, 0, 31, 243, 195, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 126, 230, 102, 102, 102, 102, 68, 0, 0, 0, 0,
+ 0, 0, 31, 240, 96, 48, 24, 48, 96, 192, 223, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 127, 240, 216, 216, 216, 216, 112, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 99, 99, 99, 99, 103, 111, 123, 96, 96, 192, 0,
+ 0, 0, 0, 0, 111, 184, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0,
+ 0, 0, 24, 24, 126, 219, 219, 219, 219, 126, 24, 24, 0, 0, 0, 0,
+ 0, 0, 0, 60, 102, 195, 195, 255, 195, 195, 102, 60, 0, 0, 0, 0,
+ 0, 0, 60, 102, 195, 195, 195, 195, 102, 36, 165, 231, 0, 0, 0, 0,
+ 0, 7, 28, 48, 24, 12, 62, 102, 198, 198, 204, 120, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 110, 219, 219, 219, 118, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 4, 124, 206, 214, 230, 124, 64, 128, 0, 0, 0, 0,
+ 0, 0, 30, 48, 96, 96, 126, 96, 96, 96, 48, 30, 0, 0, 0, 0,
+ 0, 0, 0, 126, 195, 195, 195, 195, 195, 195, 195, 195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 24, 126, 24, 24, 0, 0, 126, 0, 0, 0, 0,
+ 0, 0, 0, 48, 24, 12, 6, 12, 24, 48, 0, 126, 0, 0, 0, 0,
+ 0, 0, 0, 12, 24, 48, 96, 48, 24, 12, 0, 126, 0, 0, 0, 0,
+ 0, 0, 0, 14, 27, 27, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 216, 216, 112, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 24, 0, 255, 0, 24, 24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 118, 220, 0, 118, 220, 0, 0, 0, 0, 0, 0,
+ 0, 0, 60, 102, 102, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 2, 6, 4, 12, 8, 216, 80, 112, 32, 0, 0, 0, 0,
+ 0, 0, 220, 246, 230, 198, 198, 198, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 120, 204, 24, 48, 100, 252, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 126, 126, 126, 126, 126, 126, 126, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Can't find another place to put this... */
+void plTexDelete(pl_Texture *t) {
+ if (t != NULL)
+ {
+ if (t->Data != NULL)
+ {
+ free(t->Data);
+ t->Data = NULL;
+ }
+ if (t->PaletteData != NULL)
+ {
+ free(t->PaletteData);
+ t->PaletteData = NULL;
+ }
+ free(t);
+ t = NULL;
+ }
+}
diff --git a/Src/Winamp/plush/PLUSH.H b/Src/Winamp/plush/PLUSH.H
new file mode 100644
index 00000000..6d68e8c0
--- /dev/null
+++ b/Src/Winamp/plush/PLUSH.H
@@ -0,0 +1,720 @@
+/******************************************************************************
+ plush.h
+ PLUSH 3D VERSION 1.2 MAIN HEADER
+ Copyright (c) 1996-2000 Justin Frankel
+ Copyright (c) 1998-2000 Nullsoft, Inc.
+
+ For more information on Plush and the latest updates, please visit
+ http://www.nullsoft.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Justin Frankel
+ justin@nullsoft.com
+
+******************************************************************************/
+
+#ifndef _PLUSH_H_
+#define _PLUSH_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "pl_conf.h"
+#include "pl_defs.h"
+#include "pl_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern pl_uChar plText_DefaultFont[256*16]; /* Default 8x16 font for plText* */
+extern pl_uInt32 plRender_TriStats[4]; /* Three different triangle counts from
+ the last plRender() block:
+ 0: initial tris
+ 1: tris after culling
+ 2: final polys after real clipping
+ 3: final tris after tesselation
+ */
+
+/******************************************************************************
+** Material Functions (mat.c)
+******************************************************************************/
+
+/*
+ plMatCreate() creates a material.
+ Parameters:
+ none
+ Returns:
+ a pointer to the material on success, 0 on failure
+*/
+pl_Mat *plMatCreate();
+
+/*
+ plMatDelete() deletes a material that was created with plMatCreate().
+ Parameters:
+ m: a pointer to the material to be deleted
+ Returns:
+ nothing
+*/
+void plMatDelete(pl_Mat *m);
+
+/*
+ plMatInit() initializes a material that was created with plMatCreate().
+ Parameters:
+ m: a pointer to the material to be intialized
+ Returns:
+ nothing
+ Notes:
+ you *must* do this before calling plMatMapToPal() or plMatMakeOptPal().
+*/
+void plMatInit(pl_Mat *m);
+
+/*
+ plMatMapToPal() maps a material that was created with plMatCreate() and
+ initialized with plMatInit() to a palette.
+ Parameters:
+ mat: material to map
+ pal: a 768 byte array of unsigned chars, each 3 being a rgb triplet
+ (0-255, *not* the cheesy vga 0-63)
+ pstart: starting offset to use colors of, usually 0
+ pend: ending offset to use colors of, usually 255
+ Returns:
+ nothing
+ Notes:
+ Mapping a material with > 2000 colors can take up to a second or two.
+ Be careful, and go easy on plMat.NumGradients ;)
+*/
+void plMatMapToPal(pl_Mat *m, pl_uChar *pal, pl_sInt pstart, pl_sInt pend);
+
+
+/*
+ plMatMakeOptPal() makes an almost optimal palette from materials
+ created with plMatCreate() and initialized with plMatInit().
+ Paramters:
+ p: palette to create
+ pstart: first color entry to use
+ pend: last color entry to use
+ materials: an array of pointers to materials to generate the palette from
+ nmats: number of materials
+ Returns:
+ nothing
+*/
+void plMatMakeOptPal(pl_uChar *p, pl_sInt pstart,
+ pl_sInt pend, pl_Mat **materials, pl_sInt nmats);
+
+
+/******************************************************************************
+** Object Functions (obj.c)
+******************************************************************************/
+
+/*
+ plObjCreate() allocates an object
+ Paramters:
+ np: Number of vertices in object
+ nf: Number of faces in object
+ Returns:
+ a pointer to the object on success, 0 on failure
+*/
+pl_Obj *plObjCreate(pl_uInt32 np, pl_uInt32 nf);
+
+/*
+ plObjDelete() frees an object and all of it's subobjects
+ that was allocated with plObjCreate();
+ Paramters:
+ o: object to delete
+ Returns:
+ nothing
+*/
+void plObjDelete(pl_Obj *o);
+
+/*
+ plObjClone() creates an exact but independent duplicate of an object and
+ all of it's subobjects
+ Paramters:
+ o: the object to clone
+ Returns:
+ a pointer to the new object on success, 0 on failure
+*/
+pl_Obj *plObjClone(pl_Obj *o);
+
+/*
+ plObjScale() scales an object, and all of it's subobjects.
+ Paramters:
+ o: a pointer to the object to scale
+ s: the scaling factor
+ Returns:
+ a pointer to o.
+ Notes: This scales it slowly, by going through each vertex and scaling it's
+ position. Avoid doing this in realtime.
+*/
+pl_Obj *plObjScale(pl_Obj *o, pl_Float s);
+
+/*
+ plObjStretch() stretches an object, and all of it's subobjects
+ Parameters:
+ o: a pointer to the object to stretch
+ x,y,z: the x y and z stretch factors
+ Returns:
+ a pointer to o.
+ Notes: same as plObjScale(). Note that the normals are preserved.
+*/
+pl_Obj *plObjStretch(pl_Obj *o, pl_Float x, pl_Float y, pl_Float z);
+
+/*
+ plObjTranslate() translates an object
+ Parameters:
+ o: a pointer to the object to translate
+ x,y,z: translation in object space
+ Returns:
+ a pointer to o
+ Notes: same has plObjScale().
+*/
+pl_Obj *plObjTranslate(pl_Obj *o, pl_Float x, pl_Float y, pl_Float z);
+
+/*
+ plObjFlipNormals() flips all vertex and face normals of and object
+ and allo of it's subobjects.
+ Parameters:
+ o: a pointer to the object to flip normals of
+ Returns:
+ a pointer to o
+ Notes:
+ Not especially fast.
+ A call to plObjFlipNormals() or plObjCalcNormals() will restore the normals
+*/
+pl_Obj *plObjFlipNormals(pl_Obj *o);
+
+/*
+ plObjSetMat() sets the material of all faces in an object.
+ Paramters:
+ o: the object to set the material of
+ m: the material to set it to
+ th: "transcend hierarchy". If set, it will set the
+ material of all subobjects too.
+ Returns:
+ nothing
+*/
+void plObjSetMat(pl_Obj *o, pl_Mat *m, pl_Bool th);
+
+/*
+ plObjCalcNormals() calculates all face and vertex normals for an object
+ and all subobjects.
+ Paramters:
+ obj: the object
+ Returns:
+ nothing
+*/
+void plObjCalcNormals(pl_Obj *obj);
+
+/******************************************************************************
+** Frustum Clipping Functions (clip.c)
+******************************************************************************/
+
+/*
+ plClipSetFrustum() sets up the clipping frustum.
+ Parameters:
+ cam: a camera allocated with plCamCreate().
+ Returns:
+ nothing
+ Notes:
+ Sets up the internal structures.
+ DO NOT CALL THIS ROUTINE FROM WITHIN A plRender*() block.
+*/
+void plClipSetFrustum(pl_Cam *cam);
+
+/*
+ plClipRenderFace() renders a face and clips it to the frustum initialized
+ with plClipSetFrustum().
+ Parameters:
+ face: the face to render
+ Returns:
+ nothing
+ Notes: this is used internally by plRender*(), so be careful. Kinda slow too.
+*/
+void plClipRenderFace(pl_Face *face);
+
+/*
+ plClipNeeded() decides whether the face is in the frustum, intersecting
+ the frustum, or completely out of the frustum craeted with
+ plClipSetFrustum().
+ Parameters:
+ face: the face to check
+ Returns:
+ 0: the face is out of the frustum, no drawing necessary
+ 1: the face is intersecting the frustum, splitting and drawing necessary
+ Notes: this is used internally by plRender*(), so be careful. Kinda slow too.
+*/
+pl_sInt plClipNeeded(pl_Face *face);
+
+/******************************************************************************
+** Light Handling Routines (light.c)
+******************************************************************************/
+
+/*
+ plLightCreate() creates a new light
+ Parameters:
+ none
+ Returns:
+ a pointer to the light
+*/
+pl_Light *plLightCreate();
+
+/*
+ plLightSet() sets up a light allocated with plLightCreate()
+ Parameters:
+ light: the light to set up
+ mode: the mode of the light (PL_LIGHT_*)
+ x,y,z: either the position of the light (PL_LIGHT_POINT*) or the angle
+ in degrees of the light (PL_LIGHT_VECTOR)
+ intensity: the intensity of the light (0.0-1.0)
+ halfDist: the distance at which PL_LIGHT_POINT_DISTANCE is 1/2 intensity
+ Returns:
+ a pointer to light.
+*/
+pl_Light *plLightSet(pl_Light *light, pl_uChar mode, pl_Float x, pl_Float y,
+ pl_Float z, pl_Float intensity, pl_Float halfDist);
+
+/*
+ plLightDelete() frees a light allocated with plLightCreate().
+ Paramters:
+ l: light to delete
+ Returns:
+ nothing
+*/
+void plLightDelete(pl_Light *l);
+
+/* PUT ME SOMEWHERE */
+/*
+** plTexDelete() frees all memory associated with "t"
+*/
+void plTexDelete(pl_Texture *t);
+
+
+/******************************************************************************
+** Camera Handling Routines (cam.c)
+******************************************************************************/
+
+/*
+ plCamCreate() allocates a new camera
+ Parameters:
+ sw: screen width
+ sh: screen height
+ ar: aspect ratio (usually 1.0)
+ fov: field of view (usually 45-120)
+ fb: pointer to framebuffer
+ zb: pointer to Z buffer (or NULL)
+ Returns:
+ a pointer to the newly allocated camera
+*/
+pl_Cam *plCamCreate(pl_uInt sw, pl_uInt sh, pl_Float ar, pl_Float fov,
+ pl_uChar *fb, pl_ZBuffer *zb);
+
+/*
+ plCamSetTarget() sets the target of a camera allocated with plCamCreate().
+ Parameters:
+ c: the camera to set the target of
+ x,y,z: the worldspace coordinate of the target
+ Returns:
+ nothing
+ Notes:
+ Sets the pitch and pan of the camera. Does not touch the roll.
+*/
+void plCamSetTarget(pl_Cam *c, pl_Float x, pl_Float y, pl_Float z);
+
+/*
+ plCamDelete() frees all memory associated with a camera excluding
+ framebuffers and Z buffers
+ Paramters:
+ c: camera to free
+ Returns:
+ nothing
+*/
+void plCamDelete(pl_Cam *c);
+
+/******************************************************************************
+** Easy Rendering Interface (render.c)
+******************************************************************************/
+
+/*
+ plRenderBegin() begins the rendering process.
+ Parameters:
+ Camera: camera to use for rendering
+ Returns:
+ nothing
+ Notes:
+ Only one rendering process can occur at a time.
+ Uses plClip*(), so don't use them within or around a plRender() block.
+*/
+void plRenderBegin(pl_Cam *Camera);
+
+/*
+ plRenderLight() adds a light to the scene.
+ Parameters:
+ light: light to add to scene
+ Returns:
+ nothing
+ Notes: Any objects rendered before will be unaffected by this.
+*/
+void plRenderLight(pl_Light *light);
+
+/*
+ plRenderObj() adds an object and all of it's subobjects to the scene.
+ Parameters:
+ obj: object to render
+ Returns:
+ nothing
+ Notes: if Camera->Sort is zero, objects are rendered in the order that
+ they are added to the scene.
+*/
+void plRenderObj(pl_Obj *obj);
+
+/*
+ plRenderEnd() actually does the rendering, and closes the rendering process
+ Paramters:
+ none
+ Returns:
+ nothing
+*/
+void plRenderEnd();
+
+/******************************************************************************
+** Object Primitives Code (make.c)
+******************************************************************************/
+
+/*
+ plMakePlane() makes a plane centered at the origin facing up the y axis.
+ Parameters:
+ w: width of the plane (along the x axis)
+ d: depth of the plane (along the z axis)
+ res: resolution of plane, i.e. subdivisions
+ m: material to use
+ Returns:
+ pointer to object created.
+*/
+pl_Obj *plMakePlane(pl_Float w, pl_Float d, pl_uInt res, pl_Mat *m);
+
+/*
+ plMakeBox() makes a box centered at the origin
+ Parameters:
+ w: width of the box (x axis)
+ d: depth of the box (z axis)
+ h: height of the box (y axis)
+ Returns:
+ pointer to object created.
+*/
+pl_Obj *plMakeBox(pl_Float w, pl_Float d, pl_Float h, pl_Mat *m);
+
+/*
+ plMakeCone() makes a cone centered at the origin
+ Parameters:
+ r: radius of the cone (x-z axis)
+ h: height of the cone (y axis)
+ div: division of cone (>=3)
+ cap: close the big end?
+ m: material to use
+ Returns:
+ pointer to object created.
+*/
+pl_Obj *plMakeCone(pl_Float r, pl_Float h, pl_uInt div, pl_Bool cap, pl_Mat *m);
+
+/*
+ plMakeCylinder() makes a cylinder centered at the origin
+ Parameters:
+ r: radius of the cylinder (x-z axis)
+ h: height of the cylinder (y axis)
+ divr: division of of cylinder (around the circle) (>=3)
+ captop: close the top
+ capbottom: close the bottom
+ m: material to use
+ Returns:
+ pointer to object created.
+*/
+pl_Obj *plMakeCylinder(pl_Float r, pl_Float h, pl_uInt divr, pl_Bool captop,
+ pl_Bool capbottom, pl_Mat *m);
+
+/*
+ plMakeSphere() makes a sphere centered at the origin.
+ Parameters:
+ r: radius of the sphere
+ divr: division of the sphere (around the y axis) (>=3)
+ divh: division of the sphere (around the x,z axis) (>=3)
+ m: material to use
+ Returns:
+ pointer to object created.
+*/
+pl_Obj *plMakeSphere(pl_Float r, pl_uInt divr, pl_uInt divh, pl_Mat *m);
+
+/*
+ plMakeTorus() makes a torus centered at the origin
+ Parameters:
+ r1: inner radius of the torus
+ r2: outer radius of the torus
+ divrot: division of the torus (around the y axis) (>=3)
+ divrad: division of the radius of the torus (x>=3)
+ m: material to use
+ Returns:
+ pointer to object created.
+*/
+pl_Obj *plMakeTorus(pl_Float r1, pl_Float r2, pl_uInt divrot,
+ pl_uInt divrad, pl_Mat *m);
+
+/******************************************************************************
+** File Readers (read_*.c)
+******************************************************************************/
+
+/*
+ plRead3DSObj() reads a 3DS object
+ Parameters:
+ fn: filename of object to read
+ m: material to assign it
+ Returns:
+ pointer to object
+ Notes:
+ This reader organizes multiple objects like so:
+ 1) the first object is returned
+ 2) the second object is the first's first child
+ 3) the third object is the second's first child
+ 4) etc
+*/
+pl_Obj *plRead3DSObj(char *fn, pl_Mat *m);
+
+/*
+ plReadCOBObj() reads an ascii .COB object
+ Parameters:
+ fn: filename of object to read
+ mat: material to assign it
+ Returns:
+ pointer to object
+ Notes:
+ This is Caligari's ASCII object format.
+ This reader doesn't handle multiple objects. It just reads the first one.
+ Polygons with lots of sides are not always tesselated correctly. Just
+ use the "Tesselate" button from within truespace to improve the results.
+*/
+pl_Obj *plReadCOBObj(char *fn, pl_Mat *mat);
+
+/*
+ plReadJAWObj() reads a .JAW object.
+ Parameters:
+ fn: filename of object to read
+ m: material to assign it
+ Returns:
+ pointer to object
+ Notes:
+ For information on the .JAW format, please see the jaw3D homepage,
+ http://www.tc.umn.edu/nlhome/g346/kari0022/jaw3d/
+*/
+pl_Obj *plReadJAWObj(char *fn, pl_Mat *m);
+
+/*
+ plReadPCXTex() reads a 8bpp PCX texture
+ Parameters:
+ fn: filename of texture to read
+ rescale: will rescale image if not whole log2 dimensions (USE THIS)
+ optimize: will optimize colors (USE THIS TOO)
+ Returns:
+ pointer to texture
+ Notes:
+ The PCX must be a 8bpp zSoft version 5 PCX. The texture's palette will
+ be optimized, and the texture might be scaled up so that it's dimensions
+ will be a nice power of two.
+*/
+pl_Texture *plReadPCXTex(char *fn, pl_Bool rescale, pl_Bool optimize);
+
+/******************************************************************************
+** Math Code (math.c)
+******************************************************************************/
+
+/*
+ plMatrixRotate() generates a rotation matrix
+ Parameters:
+ matrix: an array of 16 pl_Floats that is a 4x4 matrix
+ m: the axis to rotate around, 1=X, 2=Y, 3=Z.
+ Deg: the angle in degrees to rotate
+ Returns:
+ nothing
+*/
+void plMatrixRotate(pl_Float matrix[], pl_uChar m, pl_Float Deg);
+
+/*
+ plMatrixTranslate() generates a translation matrix
+ Parameters:
+ m: the matrix (see plMatrixRotate for more info)
+ x,y,z: the translation coordinates
+ Returns:
+ nothing
+*/
+void plMatrixTranslate(pl_Float m[], pl_Float x, pl_Float y, pl_Float z);
+
+/*
+ plMatrixMultiply() multiplies two matrices
+ Parameters:
+ dest: destination matrix will be multipled by src
+ src: source matrix
+ Returns:
+ nothing
+ Notes:
+ this is the same as dest = dest*src (since the order *does* matter);
+*/
+void plMatrixMultiply(pl_Float *dest, pl_Float src[]);
+
+/*
+ plMatrixApply() applies a matrix.
+ Parameters:
+ m: matrix to apply
+ x,y,z: input coordinate
+ outx,outy,outz: pointers to output coords.
+ Returns:
+ nothing
+ Notes:
+ applies the matrix to the 3d point to produce the transformed 3d point
+*/
+void plMatrixApply(pl_Float *m, pl_Float x, pl_Float y, pl_Float z,
+ pl_Float *outx, pl_Float *outy, pl_Float *outz);
+
+/*
+ plNormalizeVector() makes a vector a unit vector
+ Parameters:
+ x,y,z: pointers to the vector
+ Returns:
+ nothing
+*/
+void plNormalizeVector(pl_Float *x, pl_Float *y, pl_Float *z);
+
+/*
+ plDotProduct() returns the dot product of two vectors
+ Parameters:
+ x1,y1,z1: the first vector
+ x2,y2,z2: the second vector
+ Returns:
+ the dot product of the two vectors
+*/
+pl_Float plDotProduct(pl_Float x1, pl_Float y1, pl_Float z1,
+ pl_Float x2, pl_Float y2, pl_Float z2);
+
+/******************************************************************************
+** Spline Interpolation (spline.c)
+******************************************************************************/
+
+/*
+ plSplineInit() initializes a spline
+ Parameters:
+ s: the spline
+ Returns:
+ nothing
+ Notes:
+ Intializes the spline. Do this once, or when you change any of the settings
+*/
+void plSplineInit(pl_Spline *s);
+
+/*
+ plSplineGetPoint() gets a point on the spline
+ Parameters:
+ s: spline
+ frame: time into spline. 0.0 is start, 1.0 is second key point, etc.
+ out: a pointer to an array of s->keyWidth floats that will be filled in.
+ Returns:
+ nothing
+*/
+void plSplineGetPoint(pl_Spline *s, pl_Float frame, pl_Float *out);
+
+/******************************************************************************
+** 8xX Bitmapped Text
+******************************************************************************/
+/*
+ plTextSetFont() sets the font to be used by the plText*() functions.
+ Parameters:
+ font: a pointer to a 8xX bitmapped font
+ height: the height of the font (X)
+ Returns:
+ nothing
+*/
+
+void plTextSetFont(pl_uChar *font, pl_uChar height);
+
+/*
+ plTextPutChar() puts a character to a camera
+ Parameters:
+ cam: The camera. If the camera has a zBuffer, it will be used.
+ x: the x screen position of the left of the text
+ y: the y screen position of the top of the text
+ z: the depth of the text (used when cam->zBuffer is set)
+ color: the color to make the text
+ c: the character to put. Special characters such as '\n' aren't handled.
+ Returns:
+ nothing
+*/
+
+void plTextPutChar(pl_Cam *cam, pl_sInt x, pl_sInt y, pl_Float z,
+ pl_uChar color, pl_uChar c);
+
+/*
+ plTextPutString() puts an array of characters to a camera
+ Parameters:
+ cam: The camera. If the camera has a zBuffer, it will be used.
+ x: the x screen position of the left of the text
+ y: the y screen position of the top of the text
+ z: the depth of the text (used when cam->zBuffer is set)
+ color: the color to make the text
+ string:
+ the characters to put. '\n' and '\t' are handled as one would expect
+ Returns:
+ nothing
+*/
+void plTextPutStr(pl_Cam *cam, pl_sInt x, pl_sInt y, pl_Float z,
+ pl_uChar color, pl_sChar *string);
+
+/*
+ plTextPrintf() is printf() for graphics
+ Parameters:
+ cam: The camera. If the camera has a zBuffer, it will be used.
+ x: the x screen position of the left of the text
+ y: the y screen position of the top of the text
+ z: the depth of the text (used when cam->zBuffer is set)
+ color: the color to make the text
+ format:
+ the characters to put, with printf() formatting codes.
+ '\n' and '\t' are handled as one would expect
+ ...: any additional parameters specified by format
+ Returns:
+ nothing
+*/
+void plTextPrintf(pl_Cam *cam, pl_sInt x, pl_sInt y, pl_Float z,
+ pl_uChar color, pl_sChar *format, ...);
+
+/******************************************************************************
+** Built-in Rasterizers
+******************************************************************************/
+
+void plPF_SolidF(pl_Cam *, pl_Face *);
+void plPF_SolidG(pl_Cam *, pl_Face *);
+void plPF_TexF(pl_Cam *, pl_Face *);
+void plPF_TexG(pl_Cam *, pl_Face *);
+void plPF_TexEnv(pl_Cam *, pl_Face *);
+void plPF_PTexF(pl_Cam *, pl_Face *);
+void plPF_PTexG(pl_Cam *, pl_Face *);
+void plPF_TransF(pl_Cam *, pl_Face *);
+void plPF_TransG(pl_Cam *, pl_Face *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_PLUSH_H_ */
diff --git a/Src/Winamp/plush/PL_CONF.H b/Src/Winamp/plush/PL_CONF.H
new file mode 100644
index 00000000..e5be4287
--- /dev/null
+++ b/Src/Winamp/plush/PL_CONF.H
@@ -0,0 +1,45 @@
+/******************************************************************************
+ pl_conf.h
+ PLUSH 3D VERSION 1.2 CONFIGURATION HEADER
+ Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#ifndef _PL_CONF_H_
+#define _PL_CONF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Maximum children per object */
+#define PL_MAX_CHILDREN (16)
+
+/* Maximum lights per scene -- if you exceed this, they will be ignored */
+#define PL_MAX_LIGHTS (32)
+
+/* Maximum number of triangles per scene -- if you exceed this, entire
+objects will be ignored. You can increase this if you need it. It takes
+approximately 8*PL_MAX_TRIANGLES bytes of memory. i.e. the default of
+16384 consumes 128kbytes of memory. not really a big deal,
+*/
+
+#define PL_MAX_TRIANGLES (16384)
+
+typedef float pl_ZBuffer; /* z-buffer type (must be float) */
+typedef float pl_Float; /* General floating point */
+typedef float pl_IEEEFloat32; /* IEEE 32 bit floating point */
+typedef signed long int pl_sInt32; /* signed 32 bit integer */
+typedef unsigned long int pl_uInt32; /* unsigned 32 bit integer */
+typedef signed short int pl_sInt16; /* signed 16 bit integer */
+typedef unsigned short int pl_uInt16; /* unsigned 16 bit integer */
+typedef signed int pl_sInt; /* signed optimal integer */
+typedef unsigned int pl_uInt; /* unsigned optimal integer */
+typedef int pl_Bool; /* boolean */
+typedef unsigned char pl_uChar; /* unsigned 8 bit integer */
+typedef signed char pl_sChar; /* signed 8 bit integer */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_PL_CONF_H_ */
diff --git a/Src/Winamp/plush/PL_DEFS.H b/Src/Winamp/plush/PL_DEFS.H
new file mode 100644
index 00000000..f101810f
--- /dev/null
+++ b/Src/Winamp/plush/PL_DEFS.H
@@ -0,0 +1,62 @@
+/******************************************************************************
+ pl_defs.h
+ PLUSH 3D VERSION 1.2 CONSTANTS DEFINITION HEADER
+ Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#ifndef _PL_DEFS_H_
+#define _PL_DEFS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* pi! */
+#define PL_PI 3.14159265359
+
+/* Utility min() and max() functions */
+#define plMin(x,y) (( ( x ) > ( y ) ? ( y ) : ( x )))
+#define plMax(x,y) (( ( x ) < ( y ) ? ( y ) : ( x )))
+
+/*
+** Shade modes. Used with plMat.ShadeType
+** Note that (PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE) and
+** (PL_SHADE_FLAT|PL_SHADE_FLAT_DISTANCE) are valid shading modes.
+*/
+#define PL_SHADE_NONE (1)
+#define PL_SHADE_FLAT (2)
+#define PL_SHADE_FLAT_DISTANCE (4)
+#define PL_SHADE_GOURAUD (8)
+#define PL_SHADE_GOURAUD_DISTANCE (16)
+
+/*
+** Light modes. Used with plLight.Type or plLightSet().
+** Note that PL_LIGHT_POINT_ANGLE assumes no falloff and uses the angle between
+** the light and the point, PL_LIGHT_POINT_DISTANCE has falloff with proportion
+** to distance**2 (see plLightSet() for setting it), PL_LIGHT_POINT does both.
+*/
+#define PL_LIGHT_NONE (0x0)
+#define PL_LIGHT_VECTOR (0x1)
+#define PL_LIGHT_POINT (0x2|0x4)
+#define PL_LIGHT_POINT_DISTANCE (0x2)
+#define PL_LIGHT_POINT_ANGLE (0x4)
+
+/* Used internally; PL_FILL_* are stored in plMat._st. */
+#define PL_FILL_SOLID (0x0)
+#define PL_FILL_TEXTURE (0x1)
+#define PL_FILL_ENVIRONMENT (0x2)
+#define PL_FILL_TRANSPARENT (0x4)
+
+#define PL_TEXENV_ADD (0)
+#define PL_TEXENV_MUL (1)
+#define PL_TEXENV_AVG (2)
+#define PL_TEXENV_TEXMINUSENV (3)
+#define PL_TEXENV_ENVMINUSTEX (4)
+#define PL_TEXENV_MIN (5)
+#define PL_TEXENV_MAX (6)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_PL_DEFS_H_ */
diff --git a/Src/Winamp/plush/PL_TYPES.H b/Src/Winamp/plush/PL_TYPES.H
new file mode 100644
index 00000000..f6cb7c48
--- /dev/null
+++ b/Src/Winamp/plush/PL_TYPES.H
@@ -0,0 +1,162 @@
+/******************************************************************************
+ pl_types.h
+ PLUSH 3D VERSION 1.2 TYPES DEFINITION HEADER
+ Copyright (c) 1996-2000 Justin Frankel
+******************************************************************************/
+
+#ifndef _PL_TYPES_H_
+#define _PL_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Texture type. Read textures with plReadPCXTex(), and assign them to
+** plMat.Environment or plMat.Texture.
+*/
+typedef struct _pl_Texture {
+ pl_uChar *Data; /* Texture data */
+ pl_uChar *PaletteData; /* Palette data (NumColors bytes) */
+ pl_uChar Width, Height; /* Log2 of dimensions */
+ pl_uInt iWidth, iHeight; /* Integer dimensions */
+ pl_Float uScale, vScale; /* Scaling (usually 2**Width, 2**Height) */
+ pl_uInt NumColors; /* Number of colors used in texture */
+} pl_Texture;
+
+/*
+** Material type. Create materials with plMatCreate().
+*/
+typedef struct _pl_Mat {
+ pl_sInt Ambient[3]; /* RGB of surface (0-255 is a good range) */
+ pl_sInt Diffuse[3]; /* RGB of diffuse (0-255 is a good range) */
+ pl_sInt Specular[3]; /* RGB of "specular" highlights (0-255) */
+ pl_uInt Shininess; /* Shininess of material. 1 is dullest */
+ pl_Float FadeDist; /* For distance fading, distance at
+ which intensity is 0 */
+ pl_uChar ShadeType; /* Shade type: PL_SHADE_* */
+ pl_uChar Transparent; /* Transparency index (0 = none), 4 = alot
+ Note: transparencies disable textures */
+ pl_uChar PerspectiveCorrect; /* Correct textures every n pixels */
+ pl_Texture *Texture; /* Texture map (see pl_Texture) above */
+ pl_Texture *Environment; /* Environment map (ditto) */
+ pl_Float TexScaling; /* Texture map scaling */
+ pl_Float EnvScaling; /* Environment map scaling */
+ pl_uChar TexEnvMode; /* TexEnv combining mode (PL_TEXENV_*) */
+ pl_Bool zBufferable; /* Can this material be zbuffered? */
+ pl_uInt NumGradients; /* Desired number of gradients to be used */
+ /* The following are used mostly internally */
+ pl_uInt _ColorsUsed; /* Number of colors actually used */
+ pl_uChar _st, _ft; /* The shadetype and filltype */
+ pl_uInt _tsfact; /* Translucent shading factor */
+ pl_uInt16 *_AddTable; /* Shading/Translucent/etc table */
+ pl_uChar *_ReMapTable; /* Table to remap colors to palette */
+ pl_uChar *_RequestedColors; /* _ColorsUsed colors, desired colors */
+ void (*_PutFace)(); /* Function that renders the triangle with this
+ material */
+} pl_Mat;
+
+/*
+** Vertex, used within pl_Obj
+*/
+typedef struct _pl_Vertex {
+ pl_Float x, y, z; /* Vertex coordinate (objectspace) */
+ pl_Float xformedx, xformedy, xformedz;
+ /* Transformed vertex
+ coordinate (cameraspace) */
+ pl_Float nx, ny, nz; /* Unit vertex normal (objectspace) */
+ pl_Float xformednx, xformedny, xformednz;
+ /* Transformed unit vertex normal
+ (cameraspace) */
+} pl_Vertex;
+
+/*
+** Face
+*/
+typedef struct _pl_Face {
+ pl_Vertex *Vertices[3]; /* Vertices of triangle */
+ pl_Float nx, ny, nz; /* Normal of triangle (object space) */
+ pl_Mat *Material; /* Material of triangle */
+ pl_sInt32 Scrx[3], Scry[3]; /* Projected screen coordinates
+ (12.20 fixed point) */
+ pl_Float Scrz[3]; /* Projected 1/Z coordinates */
+ pl_sInt32 MappingU[3], MappingV[3];
+ /* 16.16 Texture mapping coordinates */
+ pl_sInt32 eMappingU[3], eMappingV[3];
+ /* 16.16 Environment map coordinates */
+ pl_Float fShade; /* Flat intensity */
+ pl_Float sLighting; /* Face static lighting. Should usually be 0.0 */
+ pl_Float Shades[3]; /* Vertex intensity */
+ pl_Float vsLighting[3]; /* Vertex static lighting. Should be 0.0 */
+} pl_Face;
+
+/*
+** Object
+*/
+typedef struct _pl_Obj {
+ pl_uInt32 NumVertices; /* Number of vertices */
+ pl_uInt32 NumFaces; /* Number of faces */
+ pl_Vertex *Vertices; /* Array of vertices */
+ pl_Face *Faces; /* Array of faces */
+ struct _pl_Obj *Children[PL_MAX_CHILDREN];
+ /* Children */
+ pl_Bool BackfaceCull; /* Are backfacing polys drawn? */
+ pl_Bool BackfaceIllumination; /* Illuminated by lights behind them? */
+ pl_Bool GenMatrix; /* Generate Matrix from the following
+ if set */
+ pl_Float Xp, Yp, Zp, Xa, Ya, Za; /* Position and rotation of object:
+ Note: rotations are around
+ X then Y then Z. Measured in degrees */
+ pl_Float Matrix[16]; /* Transformation matrix */
+ pl_Float RotMatrix[16]; /* Rotation only matrix (for normals) */
+} pl_Obj;
+
+/*
+** Spline type. See plSpline*().
+*/
+typedef struct _pl_Spline {
+ pl_Float *keys; /* Key data, keyWidth*numKeys */
+ pl_sInt keyWidth; /* Number of floats per key */
+ pl_sInt numKeys; /* Number of keys */
+ pl_Float cont; /* Continuity. Should be -1.0 -> 1.0 */
+ pl_Float bias; /* Bias. -1.0 -> 1.0 */
+ pl_Float tens; /* Tension. -1.0 -> 1.0 */
+} pl_Spline;
+
+/*
+** Light type. See plLight*().
+*/
+typedef struct _pl_Light {
+ pl_uChar Type; /* Type of light: PL_LIGHT_* */
+ pl_Float Xp, Yp, Zp; /* If Type=PL_LIGHT_POINT*,
+ this is Position (PL_LIGHT_POINT_*),
+ otherwise if PL_LIGHT_VECTOR,
+ Unit vector */
+ pl_Float Intensity; /* Intensity. 0.0 is off, 1.0 is full */
+ pl_Float HalfDistSquared; /* Distance squared at which
+ PL_LIGHT_POINT_DISTANCE is 50% */
+} pl_Light;
+
+/*
+** Camera Type.
+*/
+typedef struct _pl_Cam {
+ pl_Float Fov; /* FOV in degrees valid range is 1-179 */
+ pl_Float AspectRatio; /* Aspect ratio (usually 1.0) */
+ pl_sChar Sort; /* Sort polygons, -1 f-t-b, 1 b-t-f, 0 no */
+ pl_Float ClipBack; /* Far clipping ( < 0.0 is none) */
+ pl_sInt ClipTop, ClipLeft; /* Screen Clipping */
+ pl_sInt ClipBottom, ClipRight;
+ pl_uInt ScreenWidth, ScreenHeight; /* Screen dimensions */
+ pl_sInt CenterX, CenterY; /* Center of screen */
+ pl_Float X, Y, Z; /* Camera position in worldspace */
+ pl_Float Pitch, Pan, Roll; /* Camera angle in degrees in worldspace */
+ pl_uChar *frameBuffer; /* Framebuffer (ScreenWidth*ScreenHeight) */
+ pl_ZBuffer *zBuffer; /* Z Buffer (NULL if none) */
+} pl_Cam;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_PL_TYPES_H_ */
diff --git a/Src/Winamp/plush/PUTFACE.H b/Src/Winamp/plush/PUTFACE.H
new file mode 100644
index 00000000..c79e789b
--- /dev/null
+++ b/Src/Winamp/plush/PUTFACE.H
@@ -0,0 +1,54 @@
+/******************************************************************************
+Plush Version 1.2
+putface.h
+Triangle Vertex Sorting Code for pf_*.c
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#ifndef _PUTFACE_H_
+#define _PUTFACE_H_
+
+#define PUTFACE_SORT() \
+ i0 = 0; i1 = 1; i2 = 2; \
+ if (TriFace->Scry[0] > TriFace->Scry[1]) { \
+ i0 = 1; i1 = 0; \
+ } \
+ if (TriFace->Scry[i0] > TriFace->Scry[2]) { \
+ i2 ^= i0; i0 ^= i2; i2 ^= i0; \
+ } \
+ if (TriFace->Scry[i1] > TriFace->Scry[i2]) { \
+ i2 ^= i1; i1 ^= i2; i2 ^= i1; \
+ }
+
+
+#define PUTFACE_SORT_ENV() \
+ PUTFACE_SORT(); \
+ MappingU1=TriFace->eMappingU[i0]*Texture->uScale*\
+ TriFace->Material->EnvScaling;\
+ MappingV1=TriFace->eMappingV[i0]*Texture->vScale*\
+ TriFace->Material->EnvScaling;\
+ MappingU2=TriFace->eMappingU[i1]*Texture->uScale*\
+ TriFace->Material->EnvScaling;\
+ MappingV2=TriFace->eMappingV[i1]*Texture->vScale*\
+ TriFace->Material->EnvScaling;\
+ MappingU3=TriFace->eMappingU[i2]*Texture->uScale*\
+ TriFace->Material->EnvScaling;\
+ MappingV3=TriFace->eMappingV[i2]*Texture->vScale*\
+ TriFace->Material->EnvScaling;
+
+#define PUTFACE_SORT_TEX() \
+ PUTFACE_SORT(); \
+ MappingU1=TriFace->MappingU[i0]*Texture->uScale*\
+ TriFace->Material->TexScaling;\
+ MappingV1=TriFace->MappingV[i0]*Texture->vScale*\
+ TriFace->Material->TexScaling;\
+ MappingU2=TriFace->MappingU[i1]*Texture->uScale*\
+ TriFace->Material->TexScaling;\
+ MappingV2=TriFace->MappingV[i1]*Texture->vScale*\
+ TriFace->Material->TexScaling;\
+ MappingU3=TriFace->MappingU[i2]*Texture->uScale*\
+ TriFace->Material->TexScaling;\
+ MappingV3=TriFace->MappingV[i2]*Texture->vScale*\
+ TriFace->Material->TexScaling;
+
+#endif /* !_PUTFACE_H_ */
diff --git a/Src/Winamp/plush/READ_3DS.C b/Src/Winamp/plush/READ_3DS.C
new file mode 100644
index 00000000..90db94e9
--- /dev/null
+++ b/Src/Winamp/plush/READ_3DS.C
@@ -0,0 +1,244 @@
+/******************************************************************************
+Plush Version 1.2
+read_3ds.c
+3DS Object Reader
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+typedef struct {
+ pl_uInt16 id;
+ void (*func)(FILE *f, pl_uInt32 p);
+} _pl_3DSChunk;
+
+static pl_Obj *obj;
+static pl_Obj *bobj;
+static pl_Obj *lobj;
+static pl_sInt16 currentobj;
+static pl_Mat *_m;
+
+static pl_Float _pl3DSReadFloat(FILE *f);
+static pl_uInt32 _pl3DSReadDWord(FILE *f);
+static pl_uInt16 _pl3DSReadWord(FILE *f);
+static void _pl3DSChunkReader(FILE *f, pl_uInt32 p);
+static void _pl3DSRGBFReader(FILE *f, pl_uInt32 p);
+static void _pl3DSRGBBReader(FILE *f, pl_uInt32 p);
+static void _pl3DSASCIIZReader(FILE *f, pl_uInt32 p, char *as);
+static void _pl3DSObjBlockReader(FILE *f, pl_uInt32 p);
+static void _pl3DSTriMeshReader(FILE *f, pl_uInt32 p);
+static void _pl3DSVertListReader(FILE *f, pl_uInt32 p);
+static void _pl3DSFaceListReader(FILE *f, pl_uInt32 p);
+static void _pl3DSFaceMatReader(FILE *f, pl_uInt32 p);
+static void MapListReader(FILE *f, pl_uInt32 p);
+static pl_sInt16 _pl3DSFindChunk(pl_uInt16 id);
+
+static _pl_3DSChunk _pl3DSChunkNames[] = {
+ {0x4D4D,NULL}, /* Main */
+ {0x3D3D,NULL}, /* Object Mesh */
+ {0x4000,_pl3DSObjBlockReader},
+ {0x4100,_pl3DSTriMeshReader},
+ {0x4110,_pl3DSVertListReader},
+ {0x4120,_pl3DSFaceListReader},
+ {0x4130,_pl3DSFaceMatReader},
+ {0x4140,MapListReader},
+ {0xAFFF,NULL}, /* Material */
+ {0xA010,NULL}, /* Ambient */
+ {0xA020,NULL}, /* Diff */
+ {0xA030,NULL}, /* Specular */
+ {0xA200,NULL}, /* Texture */
+ {0x0010,_pl3DSRGBFReader},
+ {0x0011,_pl3DSRGBBReader},
+};
+
+pl_Obj *plRead3DSObj(char *fn, pl_Mat *m) {
+ FILE *f;
+ pl_uInt32 p;
+ _m = m;
+ obj = bobj = lobj = 0;
+ currentobj = 0;
+ f = fopen(fn, "rb");
+ if (!f) return 0;
+ fseek(f, 0, 2);
+ p = ftell(f);
+ rewind(f);
+ _pl3DSChunkReader(f, p);
+ fclose(f);
+ return bobj;
+}
+
+static pl_Float _pl3DSReadFloat(FILE *f) {
+ pl_uInt32 *i;
+ pl_IEEEFloat32 c;
+ i = (pl_uInt32 *) &c;
+ *i = _pl3DSReadDWord(f);
+ return ((pl_Float) c);
+}
+
+static pl_uInt32 _pl3DSReadDWord(FILE *f) {
+ pl_uInt32 r;
+ r = fgetc(f);
+ r |= fgetc(f)<<8;
+ r |= fgetc(f)<<16;
+ r |= fgetc(f)<<24;
+ return r;
+}
+
+static pl_uInt16 _pl3DSReadWord(FILE *f) {
+ pl_uInt16 r;
+ r = fgetc(f);
+ r |= fgetc(f)<<8;
+ return r;
+}
+
+static void _pl3DSRGBFReader(FILE *f, pl_uInt32 p) {
+ pl_Float c[3];
+ c[0] = _pl3DSReadFloat(f);
+ c[1] = _pl3DSReadFloat(f);
+ c[2] = _pl3DSReadFloat(f);
+}
+
+static void _pl3DSRGBBReader(FILE *f, pl_uInt32 p) {
+ unsigned char c[3];
+ if (fread(&c, sizeof(c), 1, f) != 1) return;
+}
+
+static void _pl3DSASCIIZReader(FILE *f, pl_uInt32 p, char *as) {
+ char c;
+ if (!as) while ((c = fgetc(f)) != EOF && c != '\0');
+ else {
+ while ((c = fgetc(f)) != EOF && c != '\0') *as++ = c;
+ *as = 0;
+ }
+}
+
+static void _pl3DSObjBlockReader(FILE *f, pl_uInt32 p) {
+ _pl3DSASCIIZReader(f,p,0);
+ _pl3DSChunkReader(f, p);
+}
+
+static void _pl3DSTriMeshReader(FILE *f, pl_uInt32 p) {
+ pl_uInt32 i;
+ pl_Face *face;
+ obj = plObjCreate(0,0);
+ _pl3DSChunkReader(f, p);
+ i = obj->NumFaces;
+ face = obj->Faces;
+ while (i--) {
+ face->Vertices[0] = obj->Vertices + (pl_uInt32) face->Vertices[0];
+ face->Vertices[1] = obj->Vertices + (pl_uInt32) face->Vertices[1];
+ face->Vertices[2] = obj->Vertices + (pl_uInt32) face->Vertices[2];
+ face->MappingU[0] = face->Vertices[0]->xformedx;
+ face->MappingV[0] = face->Vertices[0]->xformedy;
+ face->MappingU[1] = face->Vertices[1]->xformedx;
+ face->MappingV[1] = face->Vertices[1]->xformedy;
+ face->MappingU[2] = face->Vertices[2]->xformedx;
+ face->MappingV[2] = face->Vertices[2]->xformedy;
+ face++;
+ }
+ plObjCalcNormals(obj);
+ if (currentobj == 0) {
+ currentobj = 1;
+ lobj = bobj = obj;
+ } else {
+ lobj->Children[0] = obj;
+ lobj = obj;
+ }
+}
+
+static void _pl3DSVertListReader(FILE *f, pl_uInt32 p) {
+ pl_uInt16 nv;
+ pl_Vertex *v;
+ nv = _pl3DSReadWord(f);
+ obj->NumVertices = nv;
+ v = obj->Vertices = (pl_Vertex *) calloc(sizeof(pl_Vertex)*nv,1);
+ while (nv--) {
+ v->x = _pl3DSReadFloat(f);
+ v->y = _pl3DSReadFloat(f);
+ v->z = _pl3DSReadFloat(f);
+ if (feof(f)) return;
+ v++;
+ }
+}
+
+static void _pl3DSFaceListReader(FILE *f, pl_uInt32 p) {
+ pl_uInt16 nv;
+ pl_uInt16 c[3];
+ pl_uInt16 flags;
+ pl_Face *face;
+
+ nv = _pl3DSReadWord(f);
+ obj->NumFaces = nv;
+ face = obj->Faces = (pl_Face *) calloc(sizeof(pl_Face)*nv,1);
+ while (nv--) {
+ c[0] = _pl3DSReadWord(f);
+ c[1] = _pl3DSReadWord(f);
+ c[2] = _pl3DSReadWord(f);
+ flags = _pl3DSReadWord(f);
+ if (feof(f)) return;
+ face->Vertices[0] = (pl_Vertex *) (c[0]&0x0000FFFF);
+ face->Vertices[1] = (pl_Vertex *) (c[1]&0x0000FFFF);
+ face->Vertices[2] = (pl_Vertex *) (c[2]&0x0000FFFF);
+ face->Material = _m;
+ face++;
+ }
+ _pl3DSChunkReader(f, p);
+}
+
+static void _pl3DSFaceMatReader(FILE *f, pl_uInt32 p) {
+ pl_uInt16 n, nf;
+
+ _pl3DSASCIIZReader(f, p,0);
+
+ n = _pl3DSReadWord(f);
+ while (n--) {
+ nf = _pl3DSReadWord(f);
+ }
+}
+
+static void MapListReader(FILE *f, pl_uInt32 p) {
+ pl_uInt16 nv;
+ pl_Float c[2];
+ pl_Vertex *v;
+ nv = _pl3DSReadWord(f);
+ v = obj->Vertices;
+ if (nv == obj->NumVertices) while (nv--) {
+ c[0] = _pl3DSReadFloat(f);
+ c[1] = _pl3DSReadFloat(f);
+ if (feof(f)) return;
+ v->xformedx = (pl_sInt32) (c[0]*65536.0);
+ v->xformedy = (pl_sInt32) (c[1]*65536.0);
+ v++;
+ }
+}
+
+static pl_sInt16 _pl3DSFindChunk(pl_uInt16 id) {
+ pl_sInt16 i;
+ for (i = 0; i < sizeof(_pl3DSChunkNames)/sizeof(_pl3DSChunkNames[0]); i++)
+ if (id == _pl3DSChunkNames[i].id) return i;
+ return -1;
+}
+
+static void _pl3DSChunkReader(FILE *f, pl_uInt32 p) {
+ pl_uInt32 hlen;
+ pl_uInt16 hid;
+ pl_sInt16 n;
+ pl_uInt32 pc;
+
+ while (ftell(f) < (int)p) {
+ pc = ftell(f);
+ hid = _pl3DSReadWord(f); if (feof(f)) return;
+ hlen = _pl3DSReadDWord(f); if (feof(f)) return;
+ if (hlen == 0) return;
+ n = _pl3DSFindChunk(hid);
+ if (n < 0) fseek(f, pc + hlen, 0);
+ else {
+ pc += hlen;
+ if (_pl3DSChunkNames[n].func != NULL) _pl3DSChunkNames[n].func(f, pc);
+ else _pl3DSChunkReader(f, pc);
+ fseek(f, pc, 0);
+ }
+ if (ferror(f)) break;
+ }
+}
+
diff --git a/Src/Winamp/plush/READ_COB.C b/Src/Winamp/plush/READ_COB.C
new file mode 100644
index 00000000..20233d20
--- /dev/null
+++ b/Src/Winamp/plush/READ_COB.C
@@ -0,0 +1,182 @@
+/******************************************************************************
+Plush Version 1.2
+read_cob.c
+ASCII COB Object Reader
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+#define PL_COB_MAX_LINELENGTH 1024
+
+pl_Obj *plReadCOBObj(char *fn, pl_Mat *mat) {
+ FILE *fp = fopen(fn,"rt");
+ long int p1,m1,p2,m2,p3,m3;
+ char temp_string[PL_COB_MAX_LINELENGTH];
+ float TransMatrix[4][4];
+ pl_Obj *obj;
+ pl_sInt32 x,i2;
+ long int numVertices, numMappingVertices, numFaces, i;
+ pl_sInt32 *MappingVertices = 0;
+ if (!fp) return 0;
+
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ if (memcmp("Caligari",temp_string,8)) { fclose(fp); return 0; }
+
+ do {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ } while (!feof(fp) && memcmp("Transform",temp_string,9));
+ if (feof(fp)) { fclose(fp); return 0; }
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ sscanf(temp_string,"%f %f %f %f",
+ &TransMatrix[0][0],&TransMatrix[0][1],&TransMatrix[0][2],&TransMatrix[0][3]);
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ sscanf(temp_string,"%f %f %f %f",
+ &TransMatrix[1][0],&TransMatrix[1][1],&TransMatrix[1][2],&TransMatrix[1][3]);
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ sscanf(temp_string,"%f %f %f %f",
+ &TransMatrix[2][0],&TransMatrix[2][1],&TransMatrix[2][2],&TransMatrix[2][3]);
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ sscanf(temp_string,"%f %f %f %f",
+ &TransMatrix[3][0],&TransMatrix[3][1],&TransMatrix[3][2],&TransMatrix[3][3]);
+
+ do {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ } while (!feof(fp) && memcmp("World Vertices",temp_string,12));
+ if (feof(fp) || sscanf(temp_string,"World Vertices %ld",&numVertices) != 1)
+ { fclose(fp); return 0; }
+
+ rewind(fp);
+ do {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ } while (!feof(fp) && memcmp("Texture Vertices",temp_string,16));
+ if (feof(fp) ||
+ sscanf(temp_string,"Texture Vertices %ld",&numMappingVertices) != 1) {
+ fclose(fp); return 0;
+ }
+
+ rewind(fp);
+ do {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ } while (!feof(fp) && memcmp("Faces",temp_string,5));
+ if (feof(fp) || sscanf(temp_string,"Faces %ld",&numFaces) != 1) {
+ fclose(fp); return 0;
+ }
+ for (x = numFaces; x; x--) {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ if (feof(fp) || sscanf(temp_string+4," verts %ld",&i) != 1 || i < 3) {
+ fclose(fp);
+ return 0;
+ }
+ numFaces += i-3;
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ }
+ obj = plObjCreate(numVertices,numFaces);
+ if (!obj) { fclose(fp); return 0; }
+ rewind(fp);
+ do {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ } while (!feof(fp) && memcmp("World Vertices",temp_string,12));
+ if (feof(fp)) { plObjDelete(obj); fclose(fp); return 0; }
+ for (x = 0; x < numVertices; x ++) {
+ float xp, yp, zp;
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ if (feof(fp) ||
+ sscanf(temp_string,"%f %f %f", &xp, &yp, &zp) != 3) {
+ plObjDelete(obj); fclose(fp); return 0;
+ }
+ obj->Vertices[x].x = (TransMatrix[0][0]*xp+TransMatrix[0][1]*yp+
+ TransMatrix[0][2]*zp+TransMatrix[0][3]);
+ obj->Vertices[x].y = (TransMatrix[1][0]*xp+TransMatrix[1][1]*yp+
+ TransMatrix[1][2]*zp+TransMatrix[1][3]);
+ obj->Vertices[x].z = (TransMatrix[2][0]*xp+TransMatrix[2][1]*yp+
+ TransMatrix[2][2]*zp+TransMatrix[2][3]);
+ }
+ rewind(fp);
+ do {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ } while (!feof(fp) && memcmp("Texture Vertices",temp_string,16));
+ if (!feof(fp)) {
+ MappingVertices = (pl_sInt32 *)
+ malloc(sizeof(pl_sInt32) * numMappingVertices * 2);
+ if (MappingVertices) {
+ for (x = 0; x < numMappingVertices; x ++) {
+ float p1, p2;
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ if (feof(fp) || sscanf(temp_string,"%f %f", &p1, &p2) != 2) {
+ free(MappingVertices); plObjDelete(obj); fclose(fp); return 0;
+ }
+ MappingVertices[x*2] = (pl_sInt32) (p1*65536.0);
+ MappingVertices[x*2+1] = (pl_sInt32) (p2*65536.0);
+ }
+ }
+ }
+ rewind(fp);
+ do {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ } while (!feof(fp) && memcmp("Faces",temp_string,5));
+ if (feof(fp)) {
+ if (MappingVertices) free(MappingVertices);
+ plObjDelete(obj); fclose(fp); return 0;
+ }
+ for (x = 0; x < numFaces; x ++) {
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ sscanf(temp_string+4," verts %ld",&i);
+ fgets(temp_string,PL_COB_MAX_LINELENGTH,fp);
+ if (i == 3) {
+ if (feof(fp) || sscanf(temp_string,"<%ld,%ld> <%ld,%ld> <%ld,%ld>",
+ &p3,&m3,&p2,&m2,&p1,&m1) != 6) {
+ if (MappingVertices) free(MappingVertices);
+ plObjDelete(obj); fclose(fp); return 0;
+ }
+ obj->Faces[x].Vertices[0] = obj->Vertices + p1;
+ obj->Faces[x].Vertices[1] = obj->Vertices + p2;
+ obj->Faces[x].Vertices[2] = obj->Vertices + p3;
+ if (MappingVertices) {
+ obj->Faces[x].MappingU[0] = MappingVertices[m1*2];
+ obj->Faces[x].MappingV[0] = MappingVertices[m1*2+1];
+ obj->Faces[x].MappingU[1] = MappingVertices[m2*2];
+ obj->Faces[x].MappingV[1] = MappingVertices[m2*2+1];
+ obj->Faces[x].MappingU[2] = MappingVertices[m3*2];
+ obj->Faces[x].MappingV[2] = MappingVertices[m3*2+1];
+ }
+ obj->Faces[x].Material = mat;
+ } else {
+ long int p[16],m[16];
+ if (feof(fp)) {
+ if (MappingVertices) free(MappingVertices);
+ plObjDelete(obj); fclose(fp); return 0;
+ }
+ sscanf(temp_string,
+ "<%ld,%ld> <%ld,%ld> <%ld,%ld> <%ld,%ld> "
+ "<%ld,%ld> <%ld,%ld> <%ld,%ld> <%ld,%ld> "
+ "<%ld,%ld> <%ld,%ld> <%ld,%ld> <%ld,%ld> "
+ "<%ld,%ld> <%ld,%ld> <%ld,%ld> <%ld,%ld> ",
+ p+0,m+0,p+1,m+1,p+2,m+2,p+3,m+3,
+ p+4,m+4,p+5,m+5,p+6,m+6,p+7,m+7,
+ p+8,m+8,p+9,m+9,p+10,m+10,p+11,m+11,
+ p+12,m+12,p+13,m+13,p+14,m+14,p+15,m+15);
+ for (i2 = 1; i2 < (i-1); i2 ++) {
+ obj->Faces[x].Vertices[0] = obj->Vertices + p[0];
+ obj->Faces[x].Vertices[1] = obj->Vertices + p[i2+1];
+ obj->Faces[x].Vertices[2] = obj->Vertices + p[i2];
+ if (MappingVertices) {
+ obj->Faces[x].MappingU[0] = MappingVertices[m[0]*2];
+ obj->Faces[x].MappingV[0] = MappingVertices[m[0]*2+1];
+ obj->Faces[x].MappingU[1] = MappingVertices[m[i2+1]*2];
+ obj->Faces[x].MappingV[1] = MappingVertices[m[i2+1]*2+1];
+ obj->Faces[x].MappingU[2] = MappingVertices[m[i2]*2];
+ obj->Faces[x].MappingV[2] = MappingVertices[m[i2]*2+1];
+ }
+ obj->Faces[x].Material = mat;
+ x++;
+ }
+ x--;
+ }
+ }
+ obj->BackfaceCull = 1;
+ if (MappingVertices) free(MappingVertices);
+ plObjCalcNormals(obj);
+ fclose(fp);
+ return obj;
+}
diff --git a/Src/Winamp/plush/READ_JAW.C b/Src/Winamp/plush/READ_JAW.C
new file mode 100644
index 00000000..18ed1ce2
--- /dev/null
+++ b/Src/Winamp/plush/READ_JAW.C
@@ -0,0 +1,69 @@
+/******************************************************************************
+Plush Version 1.2
+read_jaw.c
+Jaw3D Object Reader
+Copyright (c) 1996-2000, Justin Frankel
+*******************************************************************************
+ Notes on .JAW files:
+ This is a file format created by Jawed Karim for Jaw3D
+ (http://jaw3d.home.ml.org).
+ -- updated 11/6/00 - www.jawed.com
+ It is very simple, and lets one easily create ones own models using only
+ a text editor. The format is pretty simple:
+ The first line must be "Light: (x,y,z)" where x,y, and z are the x y and
+ z components of the lightsource vector (I think ;)
+ A series of lines, numbered 0 to n, in the format of
+ "i: x y z", where i is the vertex number (which should be listed in
+ order, and x y and z are the coordinates of that vertex.
+ A series of lines, having the format "tri a, b, c" where a b and c are
+ the vertices that the face uses. It is unclear at this time which
+ way the vertices are listed (ccw or cw), so just make em consistent
+ and you can always use plFlipObjectNormals() on the loaded object.
+ That is it! (I told ya it was simple).
+******************************************************************************/
+
+#include "plush.h"
+
+pl_Obj *plReadJAWObj(char *filename, pl_Mat *m) {
+ FILE *jawfile;
+ pl_Obj *obj;
+ pl_uInt32 i;
+ pl_sInt crap;
+ char line[256];
+ pl_uInt32 total_points = 0, total_polys = 0;
+ if ((jawfile = fopen(filename, "r")) == NULL) return 0;
+ fgets(line, 256, jawfile); /* Ignores lightsource info */
+ while (fgets(line, 256, jawfile) != NULL)
+ if (strstr(line, ":") != NULL) total_points++;
+
+ rewind(jawfile); fgets(line, 256, jawfile);
+ while (fgets(line, 256, jawfile) != NULL)
+ if (strstr(line, "tri") != NULL) total_polys++;
+
+ rewind(jawfile); fgets(line, 256, jawfile);
+ obj = plObjCreate(total_points,total_polys);
+
+ i = 0;
+ while (fgets(line, 256, jawfile) != NULL) if (strstr(line, ":") != NULL) {
+ float x, y, z;
+ sscanf(line, "%d: %f %f %f",&crap,&x,&y,&z);
+ obj->Vertices[i].x = (pl_Float) x;
+ obj->Vertices[i].y = (pl_Float) y;
+ obj->Vertices[i].z = (pl_Float) z;
+ i++;
+ }
+ rewind(jawfile); fgets(line, 256, jawfile);
+ i = 0;
+ while (fgets(line, 256, jawfile) != NULL) if (strstr(line, "tri") != NULL) {
+ pl_uInt32 a,b,c;
+ sscanf(line, "tri %ld, %ld, %ld", &a, &b, &c);
+ obj->Faces[i].Vertices[0] = obj->Vertices + a;
+ obj->Faces[i].Vertices[1] = obj->Vertices + c;
+ obj->Faces[i].Vertices[2] = obj->Vertices + b;
+ obj->Faces[i].Material = m;
+ i++;
+ }
+ fclose(jawfile);
+ plObjCalcNormals(obj);
+ return obj;
+}
diff --git a/Src/Winamp/plush/READ_PCX.C b/Src/Winamp/plush/READ_PCX.C
new file mode 100644
index 00000000..e1de3825
--- /dev/null
+++ b/Src/Winamp/plush/READ_PCX.C
@@ -0,0 +1,162 @@
+/******************************************************************************
+Plush Version 1.2
+read_pcx.c
+PCX Texture Reader
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+static pl_uInt _plHiBit(pl_uInt16);
+static pl_uInt _plOptimizeImage(pl_uChar *, pl_uChar *, pl_uInt32);
+static pl_sInt _plReadPCX(char *filename, pl_uInt16 *width, pl_uInt16 *height,
+ pl_uChar **pal, pl_uChar **data);
+static void _plRescaleImage(pl_uChar *in, pl_uChar *out, pl_uInt inx,
+ pl_uInt iny, pl_uInt outx, pl_uInt outy);
+
+pl_Texture *plReadPCXTex(char *fn, pl_Bool rescale, pl_Bool optimize) {
+ pl_uChar *data, *pal;
+ pl_uInt16 x, y;
+ pl_Texture *t;
+ if (_plReadPCX(fn,&x,&y,&pal,&data) < 0) return 0;
+ t = (pl_Texture *) malloc(sizeof(pl_Texture));
+ if (!t) return 0;
+ t->Width = _plHiBit(x);
+ t->Height = _plHiBit(y);
+ if (rescale && (1 << t->Width != x || 1 << t->Height != y)) {
+ pl_uChar nx, ny, *newdata;
+ nx = t->Width;
+ if ((1 << t->Width) != x) nx++;
+ ny = t->Height;
+ if ((1 << t->Height) != y) ny++;
+ newdata = (pl_uChar *) malloc((1<<nx)*(1<<ny));
+ if (!newdata) {
+ free(t);
+ free(data);
+ free(pal);
+ return 0;
+ }
+ _plRescaleImage(data,newdata,x,y,1<<nx,1<<ny);
+ free(data);
+ data = newdata;
+ t->Width = nx;
+ t->Height = ny;
+ x = 1<<nx; y = 1<<ny;
+ }
+ t->iWidth = x;
+ t->iHeight = y;
+ t->uScale = (pl_Float) (1<<t->Width);
+ t->vScale = (pl_Float) (1<<t->Height);
+ if (optimize) t->NumColors = _plOptimizeImage(pal, data,x*y);
+ else t->NumColors = 256;
+ t->Data = data;
+ t->PaletteData = pal;
+ return t;
+}
+
+
+static pl_uInt _plHiBit(pl_uInt16 x) {
+ pl_uInt i = 16, mask = 1<<15;
+ while (mask) {
+ if (x & mask) return i;
+ mask >>= 1; i--;
+ }
+ return 0;
+}
+
+static pl_uInt _plOptimizeImage(pl_uChar *pal, pl_uChar *data, pl_uInt32 len) {
+ pl_uChar colors[256], *dd = data;
+ pl_uChar remap[256];
+ pl_sInt32 lastused, firstunused;
+ pl_uInt32 x;
+ memset(colors,0,256);
+ for (x = 0; x < len; x ++) colors[(pl_uInt) *dd++] = 1;
+ lastused = -1;
+ for (x = 0; x < 256; x ++) remap[x] = (pl_uChar)x;
+ lastused = 255;
+ firstunused = 0;
+ for (;;) {
+ while (firstunused < 256 && colors[firstunused]) firstunused++;
+ if (firstunused > 255) break;
+ while (lastused >= 0 && !colors[lastused]) lastused--;
+ if (lastused < 0) break;
+ if (lastused <= firstunused) break;
+ pal[firstunused*3] = pal[lastused*3];
+ pal[firstunused*3+1] = pal[lastused*3+1];
+ pal[firstunused*3+2] = pal[lastused*3+2];
+ colors[lastused] = 0;
+ colors[firstunused] = 1;
+ remap[lastused] = (pl_uChar) firstunused;
+ }
+ x = len;
+ while (x--) *data++ = remap[(pl_uInt) *data];
+ return (lastused+1);
+}
+
+static pl_sInt _plReadPCX(char *filename, pl_uInt16 *width, pl_uInt16 *height,
+ pl_uChar **pal, pl_uChar **data) {
+ pl_uInt16 sx, sy, ex, ey;
+ FILE *fp = fopen(filename,"rb");
+ pl_uChar *data2;
+ if (!fp) return -1;
+ fgetc(fp);
+ if (fgetc(fp) != 5) { fclose(fp); return -2; }
+ if (fgetc(fp) != 1) { fclose(fp); return -2; }
+ if (fgetc(fp) != 8) { fclose(fp); return -3; }
+ sx = fgetc(fp); sx |= fgetc(fp)<<8;
+ sy = fgetc(fp); sy |= fgetc(fp)<<8;
+ ex = fgetc(fp); ex |= fgetc(fp)<<8;
+ ey = fgetc(fp); ey |= fgetc(fp)<<8;
+ *width = ex - sx + 1;
+ *height = ey - sy + 1;
+ fseek(fp,128,SEEK_SET);
+ if (feof(fp)) { fclose(fp); return -4; }
+ *data = (pl_uChar *) malloc((*width) * (*height));
+ if (!*data) { fclose(fp); return -128; }
+ sx = *height;
+ data2 = *data;
+ do {
+ int xpos = 0;
+ do {
+ char c = fgetc(fp);
+ if ((c & 192) == 192) {
+ char oc = fgetc(fp);
+ c &= ~192;
+ do {
+ *(data2++) = oc;
+ xpos++;
+ } while (--c && xpos < *width);
+ } else {
+ *(data2++) = c;
+ xpos++;
+ }
+ } while (xpos < *width);
+ } while (--sx);
+ if (feof(fp)) { fclose(fp); free(*data); return -5; }
+ fseek(fp,-769,SEEK_END);
+ if (fgetc(fp) != 12) { fclose(fp); free(*data); return -6; }
+ *pal = (pl_uChar *) malloc(768);
+ if (!*pal) { fclose(fp); free(*data); return -7; }
+ fread(*pal,3,256,fp);
+ fclose(fp);
+ return 0;
+}
+
+static void _plRescaleImage(pl_uChar *in, pl_uChar *out, pl_uInt inx,
+ pl_uInt iny, pl_uInt outx, pl_uInt outy) {
+ pl_uInt x;
+ pl_uInt32 X, dX, dY, Y;
+ dX = (inx<<16) / outx;
+ dY = (iny<<16) / outy;
+ Y = 0;
+ do {
+ pl_uChar *ptr = in + inx*(Y>>16);
+ X = 0;
+ Y += dY;
+ x = outx;
+ do {
+ *out++ = ptr[X>>16];
+ X += dX;
+ } while (--x);
+ } while (--outy);
+}
diff --git a/Src/Winamp/plush/RENDER.C b/Src/Winamp/plush/RENDER.C
new file mode 100644
index 00000000..665e96fa
--- /dev/null
+++ b/Src/Winamp/plush/RENDER.C
@@ -0,0 +1,301 @@
+/******************************************************************************
+Plush Version 1.2
+render.c
+Rendering code: this includes transformation, lighting, etc
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+typedef struct {
+ pl_Float zd;
+ pl_Face *face;
+} _faceInfo;
+
+typedef struct {
+ pl_Light *light;
+ pl_Float l[3];
+} _lightInfo;
+
+#define MACRO_plMatrixApply(m,x,y,z,outx,outy,outz) \
+ ( outx ) = ( x )*( m )[0] + ( y )*( m )[1] + ( z )*( m )[2] + ( m )[3];\
+ ( outy ) = ( x )*( m )[4] + ( y )*( m )[5] + ( z )*( m )[6] + ( m )[7];\
+ ( outz ) = ( x )*( m )[8] + ( y )*( m )[9] + ( z )*( m )[10] + ( m )[11]
+
+#define MACRO_plDotProduct(x1,y1,z1,x2,y2,z2) \
+ ((( x1 )*( x2 ))+(( y1 )*( y2 ))+(( z1 )*( z2 )))
+
+#define MACRO_plNormalizeVector(x,y,z) { \
+ register double length; \
+ length = ( x )*( x )+( y )*( y )+( z )*( z ); \
+ if (length > 0.0000000001) { \
+ pl_Float l = (pl_Float) sqrt(length); \
+ ( x ) /= l; \
+ ( y ) /= l; \
+ ( z ) /= l; \
+ } \
+}
+
+pl_uInt32 plRender_TriStats[4];
+
+static pl_uInt32 _numfaces;
+static _faceInfo _faces[PL_MAX_TRIANGLES];
+
+static pl_Float _cMatrix[16];
+static pl_uInt32 _numlights;
+static _lightInfo _lights[PL_MAX_LIGHTS];
+static pl_Cam *_cam;
+static void _RenderObj(pl_Obj *, pl_Float *, pl_Float *);
+static void _sift_down(int L, int U, int dir);
+static void _hsort(_faceInfo *base, int nel, int dir);
+
+void plRenderBegin(pl_Cam *Camera) {
+ pl_Float tempMatrix[16];
+ memset(plRender_TriStats,0,sizeof(plRender_TriStats));
+ _cam = Camera;
+ _numlights = 0;
+ _numfaces = 0;
+ plMatrixRotate(_cMatrix,2,-Camera->Pan);
+ plMatrixRotate(tempMatrix,1,-Camera->Pitch);
+ plMatrixMultiply(_cMatrix,tempMatrix);
+ plMatrixRotate(tempMatrix,3,-Camera->Roll);
+ plMatrixMultiply(_cMatrix,tempMatrix);
+ plClipSetFrustum(_cam);
+}
+
+void plRenderLight(pl_Light *light) {
+ pl_Float *pl, xp, yp, zp;
+ if (light->Type == PL_LIGHT_NONE || _numlights >= PL_MAX_LIGHTS) return;
+ pl = _lights[_numlights].l;
+ if (light->Type == PL_LIGHT_VECTOR) {
+ xp = light->Xp;
+ yp = light->Yp;
+ zp = light->Zp;
+ MACRO_plMatrixApply(_cMatrix,xp,yp,zp,pl[0],pl[1],pl[2]);
+ } else if (light->Type & PL_LIGHT_POINT) {
+ xp = light->Xp-_cam->X;
+ yp = light->Yp-_cam->Y;
+ zp = light->Zp-_cam->Z;
+ MACRO_plMatrixApply(_cMatrix,xp,yp,zp,pl[0],pl[1],pl[2]);
+ }
+ _lights[_numlights++].light = light;
+}
+
+static void _RenderObj(pl_Obj *obj, pl_Float *bmatrix, pl_Float *bnmatrix) {
+ pl_uInt32 i, x, facepos;
+ pl_Float nx = 0.0, ny = 0.0, nz = 0.0;
+ double tmp, tmp2;
+ pl_Float oMatrix[16], nMatrix[16], tempMatrix[16];
+
+ pl_Vertex *vertex;
+ pl_Face *face;
+ pl_Light *light;
+
+ if (obj->GenMatrix) {
+ plMatrixRotate(nMatrix,1,obj->Xa);
+ plMatrixRotate(tempMatrix,2,obj->Ya);
+ plMatrixMultiply(nMatrix,tempMatrix);
+ plMatrixRotate(tempMatrix,3,obj->Za);
+ plMatrixMultiply(nMatrix,tempMatrix);
+ memcpy(oMatrix,nMatrix,sizeof(pl_Float)*16);
+ } else memcpy(nMatrix,obj->RotMatrix,sizeof(pl_Float)*16);
+
+ if (bnmatrix) plMatrixMultiply(nMatrix,bnmatrix);
+
+ if (obj->GenMatrix) {
+ plMatrixTranslate(tempMatrix, obj->Xp, obj->Yp, obj->Zp);
+ plMatrixMultiply(oMatrix,tempMatrix);
+ } else memcpy(oMatrix,obj->Matrix,sizeof(pl_Float)*16);
+ if (bmatrix) plMatrixMultiply(oMatrix,bmatrix);
+
+ for (i = 0; i < PL_MAX_CHILDREN; i ++)
+ if (obj->Children[i]) _RenderObj(obj->Children[i],oMatrix,nMatrix);
+ if (!obj->NumFaces || !obj->NumVertices) return;
+
+ plMatrixTranslate(tempMatrix, -_cam->X, -_cam->Y, -_cam->Z);
+ plMatrixMultiply(oMatrix,tempMatrix);
+ plMatrixMultiply(oMatrix,_cMatrix);
+ plMatrixMultiply(nMatrix,_cMatrix);
+
+ x = obj->NumVertices;
+ vertex = obj->Vertices;
+
+ do {
+ MACRO_plMatrixApply(oMatrix,vertex->x,vertex->y,vertex->z,
+ vertex->xformedx, vertex->xformedy, vertex->xformedz);
+ MACRO_plMatrixApply(nMatrix,vertex->nx,vertex->ny,vertex->nz,
+ vertex->xformednx,vertex->xformedny,vertex->xformednz);
+ vertex++;
+ } while (--x);
+
+ face = obj->Faces;
+ facepos = _numfaces;
+
+ if (_numfaces + obj->NumFaces >= PL_MAX_TRIANGLES) // exceeded maximum face coutn
+ {
+ return;
+ }
+
+ plRender_TriStats[0] += obj->NumFaces;
+ _numfaces += obj->NumFaces;
+ x = obj->NumFaces;
+
+ do {
+ if (obj->BackfaceCull || face->Material->_st & PL_SHADE_FLAT)
+ {
+ MACRO_plMatrixApply(nMatrix,face->nx,face->ny,face->nz,nx,ny,nz);
+ }
+ if (!obj->BackfaceCull || (MACRO_plDotProduct(nx,ny,nz,
+ face->Vertices[0]->xformedx, face->Vertices[0]->xformedy,
+ face->Vertices[0]->xformedz) < 0.0000001)) {
+ if (plClipNeeded(face)) {
+ if (face->Material->_st & (PL_SHADE_FLAT|PL_SHADE_FLAT_DISTANCE)) {
+ tmp = face->sLighting;
+ if (face->Material->_st & PL_SHADE_FLAT) {
+ for (i = 0; i < _numlights; i ++) {
+ tmp2 = 0.0;
+ light = _lights[i].light;
+ if (light->Type & PL_LIGHT_POINT_ANGLE) {
+ double nx2 = _lights[i].l[0] - face->Vertices[0]->xformedx;
+ double ny2 = _lights[i].l[1] - face->Vertices[0]->xformedy;
+ double nz2 = _lights[i].l[2] - face->Vertices[0]->xformedz;
+ MACRO_plNormalizeVector(nx2,ny2,nz2);
+ tmp2 = MACRO_plDotProduct(nx,ny,nz,nx2,ny2,nz2)*light->Intensity;
+ }
+ if (light->Type & PL_LIGHT_POINT_DISTANCE) {
+ double nx2 = _lights[i].l[0] - face->Vertices[0]->xformedx;
+ double ny2 = _lights[i].l[1] - face->Vertices[0]->xformedy;
+ double nz2 = _lights[i].l[2] - face->Vertices[0]->xformedz;
+ if (light->Type & PL_LIGHT_POINT_ANGLE) {
+ nx2 = (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/
+ light->HalfDistSquared));
+ tmp2 *= plMax(0,plMin(1.0,nx2))*light->Intensity;
+ } else {
+ tmp2 = (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/
+ light->HalfDistSquared));
+ tmp2 = plMax(0,plMin(1.0,tmp2))*light->Intensity;
+ }
+ }
+ if (light->Type == PL_LIGHT_VECTOR)
+ tmp2 = MACRO_plDotProduct(nx,ny,nz,_lights[i].l[0],_lights[i].l[1],_lights[i].l[2])
+ * light->Intensity;
+ if (tmp2 > 0.0) tmp += tmp2;
+ else if (obj->BackfaceIllumination) tmp -= tmp2;
+ } /* End of light loop */
+ } /* End of flat shading if */
+ if (face->Material->_st & PL_SHADE_FLAT_DISTANCE)
+ tmp += 1.0-(face->Vertices[0]->xformedz+face->Vertices[1]->xformedz+
+ face->Vertices[2]->xformedz) /
+ (face->Material->FadeDist*3.0);
+ face->fShade = (pl_Float) tmp;
+ } else face->fShade = 0.0; /* End of flatmask lighting if */
+ if (face->Material->_ft & PL_FILL_ENVIRONMENT) {
+ face->eMappingU[0] = 32768 + (pl_sInt32) (face->Vertices[0]->xformednx*32768.0);
+ face->eMappingV[0] = 32768 - (pl_sInt32) (face->Vertices[0]->xformedny*32768.0);
+ face->eMappingU[1] = 32768 + (pl_sInt32) (face->Vertices[1]->xformednx*32768.0);
+ face->eMappingV[1] = 32768 - (pl_sInt32) (face->Vertices[1]->xformedny*32768.0);
+ face->eMappingU[2] = 32768 + (pl_sInt32) (face->Vertices[2]->xformednx*32768.0);
+ face->eMappingV[2] = 32768 - (pl_sInt32) (face->Vertices[2]->xformedny*32768.0);
+ }
+ if (face->Material->_st &(PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE)) {
+ register pl_uChar a;
+ for (a = 0; a < 3; a ++) {
+ tmp = face->vsLighting[a];
+ if (face->Material->_st & PL_SHADE_GOURAUD) {
+ for (i = 0; i < _numlights ; i++) {
+ tmp2 = 0.0;
+ light = _lights[i].light;
+ if (light->Type & PL_LIGHT_POINT_ANGLE) {
+ nx = _lights[i].l[0] - face->Vertices[a]->xformedx;
+ ny = _lights[i].l[1] - face->Vertices[a]->xformedy;
+ nz = _lights[i].l[2] - face->Vertices[a]->xformedz;
+ MACRO_plNormalizeVector(nx,ny,nz);
+ tmp2 = MACRO_plDotProduct(face->Vertices[a]->xformednx,
+ face->Vertices[a]->xformedny,
+ face->Vertices[a]->xformednz,
+ nx,ny,nz) * light->Intensity;
+ }
+ if (light->Type & PL_LIGHT_POINT_DISTANCE) {
+ double nx2 = _lights[i].l[0] - face->Vertices[a]->xformedx;
+ double ny2 = _lights[i].l[1] - face->Vertices[a]->xformedy;
+ double nz2 = _lights[i].l[2] - face->Vertices[a]->xformedz;
+ if (light->Type & PL_LIGHT_POINT_ANGLE) {
+ double t= (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/light->HalfDistSquared));
+ tmp2 *= plMax(0,plMin(1.0,t))*light->Intensity;
+ } else {
+ tmp2 = (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/light->HalfDistSquared));
+ tmp2 = plMax(0,plMin(1.0,tmp2))*light->Intensity;
+ }
+ }
+ if (light->Type == PL_LIGHT_VECTOR)
+ tmp2 = MACRO_plDotProduct(face->Vertices[a]->xformednx,
+ face->Vertices[a]->xformedny,
+ face->Vertices[a]->xformednz,
+ _lights[i].l[0],_lights[i].l[1],_lights[i].l[2])
+ * light->Intensity;
+ if (tmp2 > 0.0) tmp += tmp2;
+ else if (obj->BackfaceIllumination) tmp -= tmp2;
+ } /* End of light loop */
+ } /* End of gouraud shading if */
+ if (face->Material->_st & PL_SHADE_GOURAUD_DISTANCE)
+ tmp += 1.0-face->Vertices[a]->xformedz/face->Material->FadeDist;
+ face->Shades[a] = (pl_Float) tmp;
+ } /* End of vertex loop for */
+ } /* End of gouraud shading mask if */
+ _faces[facepos].zd = face->Vertices[0]->xformedz+
+ face->Vertices[1]->xformedz+face->Vertices[2]->xformedz;
+ _faces[facepos++].face = face;
+ plRender_TriStats[1] ++;
+ } /* Is it in our area Check */
+ } /* Backface Check */
+ _numfaces = facepos;
+ face++;
+ } while (--x); /* Face loop */
+}
+
+void plRenderObj(pl_Obj *obj) {
+ _RenderObj(obj,0,0);
+}
+
+void plRenderEnd() {
+ _faceInfo *f;
+ if (_cam->Sort > 0) _hsort(_faces,_numfaces,0);
+ else if (_cam->Sort < 0) _hsort(_faces,_numfaces,1);
+ f = _faces;
+ while (_numfaces--) {
+ if (f->face->Material && f->face->Material->_PutFace)
+ {
+ plClipRenderFace(f->face);
+ }
+ f++;
+ }
+ _numfaces=0;
+ _numlights = 0;
+}
+
+static _faceInfo *Base, tmp;
+
+static void _hsort(_faceInfo *base, int nel, int dir) {
+ static int i;
+ Base=base-1;
+ for (i=nel/2; i>0; i--) _sift_down(i,nel,dir);
+ for (i=nel; i>1; ) {
+ tmp = base[0]; base[0] = Base[i]; Base[i] = tmp;
+ _sift_down(1,i-=1,dir);
+ }
+}
+
+#define Comp(x,y) (( x ).zd < ( y ).zd ? 1 : 0)
+
+static void _sift_down(int L, int U, int dir) {
+ static int c;
+ while (1) {
+ c=L+L;
+ if (c>U) break;
+ if ( (c < U) && dir^Comp(Base[c+1],Base[c])) c++;
+ if (dir^Comp(Base[L],Base[c])) return;
+ tmp = Base[L]; Base[L] = Base[c]; Base[c] = tmp;
+ L=c;
+ }
+}
+#undef Comp
diff --git a/Src/Winamp/plush/SPLINE.C b/Src/Winamp/plush/SPLINE.C
new file mode 100644
index 00000000..5a426f15
--- /dev/null
+++ b/Src/Winamp/plush/SPLINE.C
@@ -0,0 +1,49 @@
+/******************************************************************************
+Plush Version 1.2
+spline.c
+n-th Dimensional Spline Interpolator
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+
+void plSplineGetPoint(pl_Spline *s, pl_Float frame, pl_Float *out) {
+ pl_sInt32 i, i_1, i0, i1, i2;
+ pl_Float time1,time2,time3;
+ pl_Float t1,t2,t3,t4,u1,u2,u3,u4,v1,v2,v3;
+ pl_Float a,b,c,d;
+
+ pl_Float *keys = s->keys;
+
+ a = (1-s->tens)*(1+s->cont)*(1+s->bias);
+ b = (1-s->tens)*(1-s->cont)*(1-s->bias);
+ c = (1-s->tens)*(1-s->cont)*(1+s->bias);
+ d = (1-s->tens)*(1+s->cont)*(1-s->bias);
+ v1 = t1 = -a / 2.0; u1 = a;
+ u2 = (-6-2*a+2*b+c)/2.0; v2 = (a-b)/2.0; t2 = (4+a-b-c) / 2.0;
+ t3 = (-4+b+c-d) / 2.0;
+ u3 = (6-2*b-c+d)/2.0;
+ v3 = b/2.0;
+ t4 = d/2.0; u4 = -t4;
+
+ i0 = (pl_uInt) frame;
+ i_1 = i0 - 1;
+ while (i_1 < 0) i_1 += s->numKeys;
+ i1 = i0 + 1;
+ while (i1 >= s->numKeys) i1 -= s->numKeys;
+ i2 = i0 + 2;
+ while (i2 >= s->numKeys) i2 -= s->numKeys;
+ time1 = frame - (pl_Float) ((pl_uInt) frame);
+ time2 = time1*time1;
+ time3 = time2*time1;
+ i0 *= s->keyWidth;
+ i1 *= s->keyWidth;
+ i2 *= s->keyWidth;
+ i_1 *= s->keyWidth;
+ for (i = 0; i < s->keyWidth; i ++) {
+ a = t1*keys[i+i_1]+t2*keys[i+i0]+t3*keys[i+i1]+t4*keys[i+i2];
+ b = u1*keys[i+i_1]+u2*keys[i+i0]+u3*keys[i+i1]+u4*keys[i+i2];
+ c = v1*keys[i+i_1]+v2*keys[i+i0]+v3*keys[i+i1];
+ *out++ = a*time3 + b*time2 + c*time1 + keys[i+i0];
+ }
+}
diff --git a/Src/Winamp/plush/TEXT.C b/Src/Winamp/plush/TEXT.C
new file mode 100644
index 00000000..ff555bb9
--- /dev/null
+++ b/Src/Winamp/plush/TEXT.C
@@ -0,0 +1,123 @@
+/******************************************************************************
+Plush Version 1.1
+text.c
+Text code and data (8xX bitmapped)
+Copyright (c) 1996-2000, Justin Frankel
+******************************************************************************/
+
+#include "plush.h"
+#include <stdarg.h>
+
+static pl_uChar font_height = 16;
+
+static pl_uChar *current_font = plText_DefaultFont;
+
+void plTextSetFont(pl_uChar *font, pl_uChar height) {
+ current_font = font;
+ font_height = height;
+}
+
+void plTextPutChar(pl_Cam *cam, pl_sInt x, pl_sInt y, pl_Float z,
+ pl_uChar color, pl_uChar c) {
+ pl_uChar *font = current_font + (c*font_height);
+ pl_sInt offset = x+(y*cam->ScreenWidth);
+ pl_ZBuffer zz = (pl_ZBuffer) (1.0/z);
+ pl_sInt xx = x, a;
+ pl_uChar len = font_height;
+ pl_uChar ch;
+ pl_uChar *outmem;
+ pl_ZBuffer *zbuffer;
+ if (y+font_height < cam->ClipTop || y >= cam->ClipBottom) return;
+ if (y < cam->ClipTop) {
+ font += (cam->ClipTop-y);
+ offset += (cam->ClipTop-y)*cam->ScreenWidth;
+ len -= (cam->ClipTop-y);
+ y = cam->ClipTop;
+ }
+ if (y+font_height >= cam->ClipBottom) {
+ len = cam->ClipBottom-y;
+ }
+ if (len > 0) {
+ if (cam->zBuffer && z != 0.0) do {
+ outmem = cam->frameBuffer + offset;
+ zbuffer = cam->zBuffer + offset;
+ offset += cam->ScreenWidth;
+ xx = x;
+ ch = *font++;
+ a = 128;
+ while (a) {
+ if (xx >= cam->ClipRight) break;
+ if (xx++ >= cam->ClipLeft)
+ if (ch & a)
+ if (zz > *zbuffer) {
+ *zbuffer = zz;
+ *outmem = color;
+ }
+ zbuffer++;
+ outmem++;
+ a >>= 1;
+ }
+ if (a) break;
+ } while (--len);
+ else do {
+ outmem = cam->frameBuffer + offset;
+ offset += cam->ScreenWidth;
+ xx = x;
+ ch = *font++;
+ a = 128;
+ while (a) {
+ if (xx >= cam->ClipRight) break;
+ if (xx++ >= cam->ClipLeft) if (ch & a) *outmem = color;
+ outmem++;
+ a >>= 1;
+ }
+ if (a) break;
+ } while (--len);
+ }
+}
+
+void plTextPutStr(pl_Cam *cam, pl_sInt x, pl_sInt y, pl_Float z,
+ pl_uChar color, pl_sChar *string) {
+ pl_sInt xx = x;
+ while (*string) {
+ switch (*string) {
+ case '\n': y += font_height; xx = x; break;
+ case ' ': xx += 8; break;
+ case '\r': break;
+ case '\t': xx += 8*5; break;
+ default:
+ plTextPutChar(cam,xx,y,z,color,(pl_uChar) *string);
+ xx += 8;
+ break;
+ }
+ string++;
+ }
+}
+
+void plTextPutStrW(pl_Cam* cam, pl_sInt x, pl_sInt y, pl_Float z,
+ pl_uChar color, const wchar_t* string) {
+ pl_sInt xx = x;
+ while (*string) {
+ switch (*string) {
+ case L'\n': y += font_height; xx = x; break;
+ case L' ': xx += 8; break;
+ case L'\r': break;
+ case L'\t': xx += 8 * 5; break;
+ default:
+ plTextPutChar(cam, xx, y, z, color, (pl_uChar)*string);
+ xx += 8;
+ break;
+ }
+ string++;
+ }
+}
+
+void plTextPrintf(pl_Cam *cam, pl_sInt x, pl_sInt y, pl_Float z,
+ pl_uChar color, pl_sChar *format, ...) {
+ va_list arglist;
+ pl_sChar str[256];
+ va_start(arglist, format);
+ vsprintf((char *)str, (char *) format,arglist);
+ va_end(arglist);
+ plTextPutStr(cam,x,y,z,color,str);
+}
diff --git a/Src/Winamp/precomp.cpp b/Src/Winamp/precomp.cpp
new file mode 100644
index 00000000..6fb53909
--- /dev/null
+++ b/Src/Winamp/precomp.cpp
@@ -0,0 +1,2 @@
+#include "precomp.h"
+#include "main.hpp"
diff --git a/Src/Winamp/precomp.h b/Src/Winamp/precomp.h
new file mode 100644
index 00000000..2c7db5a9
--- /dev/null
+++ b/Src/Winamp/precomp.h
@@ -0,0 +1,14 @@
+#pragma once
+#include <ocidl.h>
+#include "main.h"
+#include "../nu/ns_wc.h"
+#include "setup/setup.h"
+#include "api.h"
+#include "JSAPI.h"
+#include "draw.h"
+#include "WADrawDC.h"
+#include "options.h"
+#include "language.h"
+#include "wa_ipc.h"
+#include "playlist.h"
+#include "videooutput.h"
diff --git a/Src/Winamp/rand.cpp b/Src/Winamp/rand.cpp
new file mode 100644
index 00000000..8bdea897
--- /dev/null
+++ b/Src/Winamp/rand.cpp
@@ -0,0 +1,226 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "random.h"
+#include <wincrypt.h>
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL /* constant vector a */
+#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
+
+static unsigned long mt[N]; /* the array for the state vector */
+static int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
+
+static CRITICAL_SECTION randCS;
+/* initializes mt[N] with a seed */
+void init_genrand(unsigned long s)
+{
+ mt[0] = s & 0xffffffffUL;
+ for (mti = 1; mti < N; mti++)
+ {
+ mt[mti] =
+ (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
+ mt[mti] &= 0xffffffffUL;
+ }
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void init_by_array(unsigned long init_key[], int key_length)
+{
+ int i, j, k;
+ init_genrand(19650218UL);
+ i=1; j=0;
+ k = (N>key_length ? N : key_length);
+ for (; k; k--) {
+ mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ + init_key[j] + j; /* non linear */
+ mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+ i++; j++;
+ if (i>=N) { mt[0] = mt[N-1]; i=1; }
+ if (j>=key_length) j=0;
+ }
+ for (k=N-1; k; k--) {
+ mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
+ - i; /* non linear */
+ mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+ i++;
+ if (i>=N) { mt[0] = mt[N-1]; i=1; }
+ }
+
+ mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
+}
+
+static const unsigned long mag01[2] = {0x0UL, MATRIX_A};
+/* mag01[x] = x * MATRIX_A for x=0,1 */
+
+/* generates a random number on [0,0xffffffff]-interval */
+unsigned long genrand_int32(void)
+{
+ EnterCriticalSection(&randCS);
+ unsigned long y;
+
+ if (mti >= N)
+ { /* generate N words at one time */
+ int kk;
+ // benski> CUT - because we call init_genrand() as the first thing in WinMain
+ //if (mti == N+1) /* if init_genrand() has not been called, */
+ // benski> CUT init_genrand(5489UL); /* a default initial seed is used */
+
+ for (kk = 0;kk < N - M;kk++)
+ {
+ y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
+ }
+ for (;kk < N - 1;kk++)
+ {
+ y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
+ }
+ y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+ mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
+
+ mti = 0;
+ }
+
+ y = mt[mti++];
+
+ LeaveCriticalSection(&randCS);
+
+ /* Tempering */
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+
+ return y;
+}
+
+/* generates a random number on [0,0x7fffffff]-interval */
+long genrand_int31(void)
+{
+ return (long)(genrand_int32() >> 1);
+}
+
+static HCRYPTPROV GetKeySet()
+{
+ HCRYPTPROV hCryptProv;
+ LPCSTR UserName = "WinampKeyContainer"; // name of the key container
+
+ if(CryptAcquireContextA(&hCryptProv, UserName, NULL, PROV_RSA_FULL, 0))
+ {
+ return hCryptProv;
+ }
+ else if(CryptAcquireContextA(&hCryptProv, UserName, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
+ {
+ return hCryptProv;
+ }
+ else
+ return 0;
+}
+
+Random::Random()
+{
+ InitializeCriticalSectionAndSpinCount(&randCS, 1000);
+
+ HCRYPTPROV hCryptProv = GetKeySet();
+ if (hCryptProv)
+ {
+ unsigned long seed_data[8];
+ if (CryptGenRandom(hCryptProv, sizeof(seed_data), (PBYTE)seed_data))
+ {
+ init_by_array(seed_data, 8);
+ }
+ CryptReleaseContext(hCryptProv,0);
+ }
+ else
+ {
+ LARGE_INTEGER performance_counter;
+ QueryPerformanceCounter(&performance_counter);
+
+ unsigned long seed_data[4] = {(unsigned long)performance_counter.HighPart, (unsigned long)performance_counter.LowPart, (unsigned long)GetTickCount64(), (unsigned long)GetCurrentProcessId()};
+ init_by_array(seed_data, 4);
+ }
+}
+
+int warand()
+{
+ return genrand_int31();
+}
+
+float warandf()
+{
+ return genrand_int32()*(1.0f / 4294967295.0f);
+}
+
+
+RandomGenerator Random::GetFunction()
+{
+ return warand;
+}
+
+UnsignedRandomGenerator Random::GetUnsignedFunction()
+{
+ return genrand_int32;
+}
+
+int Random::GetNumber()
+{
+ return genrand_int32();
+}
+
+int Random::GetPositiveNumber()
+{
+ return genrand_int31();
+}
+
+/* generates a random number on [0,1]-real-interval */
+float Random::GetFloat()
+{
+ return genrand_int32()*(1.0f / 4294967295.0f);
+ /* divided by 2^32-1 */
+}
+
+/* generates a random number on [0,1)-real-interval */
+float Random::GetFloat_LessThanOne()
+{
+ return genrand_int32()*(1.0f / 4294967296.0f);
+ /* divided by 2^32 */
+}
+/* generates a random number on (0,1)-real-interval */
+float Random::GetFloat_LessThanOne_NotZero()
+{
+ return (((float)genrand_int32()) + 0.5f)*(1.0f / 4294967296.0f);
+} // (0-1)
+
+/* generates a random number on [0,1) with 53-bit resolution*/
+double Random::GetDouble()
+{
+ unsigned long a = genrand_int32() >> 5, b = genrand_int32() >> 6;
+ return (a*67108864.0 + b)*(1.0 / 9007199254740992.0);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS Random
+START_DISPATCH;
+CB(API_RANDOM_GETFUNCTION, GetFunction)
+CB(API_RANDOM_GETFUNCTION_UNSIGNED, GetUnsignedFunction)
+CB(API_RANDOM_GETNUMBER, GetNumber)
+CB(API_RANDOM_GETPOSITIVENUMBER, GetPositiveNumber)
+CB(API_RANDOM_GETFLOAT, GetFloat)
+CB(API_RANDOM_GETFLOAT2, GetFloat_LessThanOne)
+CB(API_RANDOM_GETFLOAT3, GetFloat_LessThanOne_NotZero)
+CB(API_RANDOM_GETDOUBLE, GetDouble)
+END_DISPATCH \ No newline at end of file
diff --git a/Src/Winamp/random.h b/Src/Winamp/random.h
new file mode 100644
index 00000000..a91565be
--- /dev/null
+++ b/Src/Winamp/random.h
@@ -0,0 +1,30 @@
+#ifndef NULLSOFT_WINAMP_RANDOM_H
+#define NULLSOFT_WINAMP_RANDOM_H
+
+#include "api_random.h"
+#include <windows.h> // for DWORD
+
+
+class Random : public api_random
+{
+public:
+ static const char *getServiceName() { return "Random Number API"; }
+ static const GUID getServiceGuid() { return randomApiGUID; }
+public:
+ Random();
+ RandomGenerator GetFunction();
+ UnsignedRandomGenerator GetUnsignedFunction();
+ int GetNumber();
+ int GetPositiveNumber();
+ float GetFloat(); // [0-1]
+ float GetFloat_LessThanOne(); // [0-1)
+ float GetFloat_LessThanOne_NotZero(); // (0-1)
+ double GetDouble(); // [0-1)
+protected:
+ RECVS_DISPATCH;
+
+
+
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/readme.txt b/Src/Winamp/readme.txt
new file mode 100644
index 00000000..182e3d94
--- /dev/null
+++ b/Src/Winamp/readme.txt
@@ -0,0 +1,35 @@
+README.TXT for Winamp 2.25 - Released August ??th 1999
+
+Winamp is Copyright (C) 1997-1999 Nullsoft, Inc.
+Winamp is a trademark of Nullsoft, Inc.
+
+Table of Contents:
+ Introduction
+ Updates
+ Freeware
+ Bug reporting
+ License
+
+-=-=-=-=-=-=-=-=-= The definitive audio player for Windows =-=-=-=-=-=-=-=-=-
+
+This release includes plug-ins for MP3, MP2, WAV, MOD, XM, IT, S3M, VOC, CDDA,
+WMA, AS, and MIDI. Winamp also supports third-party input plug-ins, and with
+them can support SID, VQF, RA, AAC, and more.
+Check http://www.winamp.com/plugins for plug-ins that add support for more types.
+
+
+Updates:
+ You can go to http://www.winamp.com/ for updates. Feel free to visit
+ http://www.nullsoft.com/ for other Nullsoft projects.
+
+Shareware:
+ Winamp is freeware. Enter licensing info here.
+
+Bug reporting:
+ To report bugs, please visit our online bug report form at
+ http://www.winamp.com/support/feedback.html
+
+
+License:
+
+
diff --git a/Src/Winamp/registry.cpp b/Src/Winamp/registry.cpp
new file mode 100644
index 00000000..e3fe474b
--- /dev/null
+++ b/Src/Winamp/registry.cpp
@@ -0,0 +1,251 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#include "resource.h"
+#include "../nu/AutoWide.h"
+#include "main.hpp"
+#include "api.h"
+
+/* register winamp as a media player (in "set defaults")*/
+BOOL config_registermediaplayer(DWORD accessEnabled)
+{
+ if (config_no_registry)
+ return TRUE;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, (accessEnabled != 2)) == 0 && registrar)
+ {
+ wchar_t programname[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance,programname,MAX_PATH);
+
+ registrar->RegisterMediaPlayer(!!accessEnabled, programname, AutoWide(app_name), config_whichicon);
+ LPCWSTR szProtocols[] = { L"mms", L"mmsu", L"mmst", L"uvox", L"icy", L"sc", L"shout", L"unsv", };
+ for (int i = 0; i < sizeof(szProtocols)/sizeof(*szProtocols); i++)
+ {
+ wchar_t szBuffer[64] = {0};
+ StringCbPrintfW(szBuffer, sizeof(szBuffer), L"%s://", szProtocols[i]);
+ int offset=0;
+ if (NULL != in_setmod_noplay(szBuffer, &offset))
+ registrar->RegisterMediaPlayerProtocol(szProtocols[i], AutoWide(app_name));
+ else
+ registrar->UnregisterMediaPlayerProtocol(szProtocols[i], AutoWide(app_name));
+ }
+
+ registrar->Release();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL config_adddircontext(BOOL use_fallback)
+{
+ if (config_no_registry)
+ return TRUE;
+
+ wchar_t programname[MAX_PATH] = {0};
+ if (!GetModuleFileNameW(hMainInstance,programname,MAX_PATH)) return FALSE;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, !use_fallback) == 0 && registrar)
+ {
+ wchar_t str[MAX_PATH+128] = {0}, langbuf[1024] = {0};
+ StringCchPrintfW(str,MAX_PATH+128,L"\"%s\" \"%%1\"",programname);
+ registrar->AddDirectoryContext(str, WINAMP_PLAYW, getStringW(IDS_CONFIG_PLAYSTR,langbuf,1024));
+
+ StringCchPrintfW(str,MAX_PATH+128,L"\"%s\" /ADD \"%%1\"",programname);
+ registrar->AddDirectoryContext(str, WINAMP_ENQUEUEW, getStringW(IDS_CONFIG_ENQUEUESTR,langbuf,1024));
+
+ StringCchPrintfW(str,MAX_PATH+128,L"\"%s\" /BOOKMARK \"%%1\"",programname);
+ registrar->AddDirectoryContext(str, WINAMP_BOOKMARKW, getStringW(IDS_CONFIG_BOOKMARKSTR,langbuf,1024));
+
+ registrar->Release();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int config_isdircontext(void)
+{
+ if (config_no_registry)
+ return 0;
+ HKEY mp3Key;
+ if (RegOpenKeyA(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes\\Directory\\shell\\" WINAMP_PLAY,&mp3Key) != ERROR_SUCCESS) return 0;
+ RegCloseKey(mp3Key);
+ return 1;
+}
+
+BOOL config_setup_filetype(const wchar_t *winamp_file, const wchar_t *name, BOOL use_fallback)
+{
+ wchar_t programname[MAX_PATH] = {0};
+ if (!GetModuleFileNameW(hMainInstance,programname,MAX_PATH)) return FALSE;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, use_fallback) == 0 && registrar)
+ {
+ wchar_t str[MAX_PATH+32] = {0}, langbuf[1024] = {0};
+ registrar->SetupFileType(programname, winamp_file, name, config_whichicon, config_addtolist?L"Enqueue":L"Play", L"");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" \"%%1\"",programname);
+ registrar->SetupShell(str, winamp_file, getStringW(IDS_CONFIG_PLAYSTR,langbuf,1024), L"Play", L"{46986115-84D6-459c-8F95-52DD653E532E}");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" \"%%1\"",programname);
+ registrar->SetupShell(str, winamp_file, L"", L"open", L"{46986115-84D6-459c-8F95-52DD653E532E}");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" /ADD \"%%1\"",programname);
+ registrar->SetupShell(str, winamp_file, getStringW(IDS_CONFIG_ENQUEUESTR,langbuf,1024), L"Enqueue", L"{77A366BA-2BE4-4a1e-9263-7734AA3E99A2}");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" /BOOKMARK \"%%1\"",programname);
+ registrar->SetupShell(str, winamp_file, getStringW(IDS_CONFIG_BOOKMARKSTR,langbuf,1024), L"ListBookmark", L"");
+
+ registrar->Release();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL config_setup_filetypes(int mode)
+{
+ if (config_no_registry)
+ return TRUE;
+
+ wchar_t programname[MAX_PATH] = {0};
+ if (!GetModuleFileNameW(hMainInstance,programname,MAX_PATH)) return FALSE;
+
+ if (!config_setup_filetype(WINAMP_FILEW, getStringW(IDS_WINAMP_MEDIA_FILE,NULL,0), !mode))
+ return FALSE;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, !mode) == 0 && registrar)
+ {
+ wchar_t str[MAX_PATH+32] = {0}, langbuf[1024] = {0};
+ // droptarget stuff for windows XP
+ // clsid for open
+ registrar->RegisterGUID(programname, L"{46986115-84D6-459c-8F95-52DD653E532E}");
+ // clsid for enqueue
+ registrar->RegisterGUID(programname, L"{77A366BA-2BE4-4a1e-9263-7734AA3E99A2}");
+
+ /* Register playlist shell type */
+
+ registrar->RegisterTypeShell(programname, WINAMP_PLAYLISTW, getStringW(IDS_WINAMP_PLAYLIST_FILE,NULL,0), config_whichicon2, config_addtolist?L"Enqueue":L"Play");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" \"%%1\"",programname);
+ registrar->SetupShell(str, WINAMP_PLAYLISTW, getStringW(IDS_CONFIG_PLAYSTR,langbuf,1024), L"Play", L"");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" \"%%1\"",programname);
+ registrar->SetupShell(str, WINAMP_PLAYLISTW, L"", L"open", L"");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" /ADD \"%%1\"",programname);
+ registrar->SetupShell(str, WINAMP_PLAYLISTW, getStringW(IDS_CONFIG_ENQUEUESTR,langbuf,1024), L"Enqueue", L"");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" /BOOKMARK \"%%1\"",programname);
+ registrar->SetupShell(str, WINAMP_PLAYLISTW, getStringW(IDS_CONFIG_BOOKMARKSTR,langbuf,1024), L"ListBookmark", L"");
+
+ /* Register skin shell type */
+ registrar->RegisterTypeShell(programname, WINAMP_SKINZIPW, getStringW(IDS_WINAMP_EXTENSION_INSTALLATION_FILE,NULL,0), config_whichicon, L"Install");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" \"%%1\"",programname);
+ registrar->SetupShell(str, WINAMP_SKINZIPW, getStringW(IDS_WINAMP_FILE_INSTALL,langbuf,1024), L"Install", L"");
+
+ /* Register language file type */
+ registrar->RegisterTypeShell(programname, WINAMP_LANGZIPW, getStringW(IDS_WINAMP_LANGUAGE_INSTALLATION_FILE,NULL,0), config_whichicon, L"Install");
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" \"%%1\"",programname);
+ registrar->SetupShell(str, WINAMP_LANGZIPW, getStringW(IDS_WINAMP_FILE_INSTALL,langbuf,1024), L"Install", L"");
+
+ regmimetype(L"interface/x-winamp-skin", programname, L".wsz", 0);
+ regmimetype(L"interface/x-winamp-lang", programname, L".wlz", 0);
+
+ StringCchPrintfW(str,MAX_PATH+32,L"\"%s\" /HANDLE \"%%1\"",programname);
+ wchar_t icon[MAX_PATH+32] = {0};
+ StringCchPrintfW(icon,MAX_PATH+32,L"\"%s\",%d",programname, config_whichicon);
+ //registrar->RegisterProtocol(L"winamp", str, icon);
+
+ // regmimetype(L"application/x-winamp-plugin", programname,L"wpz",0);
+ registrar->Release();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// mar-17-2005-benski
+void config_regdvdplayer(void)
+{
+ wchar_t winampPath[MAX_PATH] = {0};
+
+ // get the full path exe
+ if (!GetModuleFileNameW(hMainInstance,winampPath, MAX_PATH))
+ return;
+
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->RegisterDVDPlayer(winampPath, config_whichicon, L"Winamp.DVD", L"Winamp", L"Nullsoft Winamp", L"Play in Winamp");
+ registrar->Release();
+ }
+}
+
+static void _reg_associated_filetypes(int force)
+{
+ wchar_t ext_list[16384] = {0}, *p = ext_list;
+ wchar_t *c_list = in_getextlistW();
+ void _r_sW(const char *name, wchar_t *data, int mlen);
+ _r_sW("config_extlist", ext_list, ARRAYSIZE(ext_list));
+
+ int something_regged=0;
+ while (p && *p)
+ {
+ wchar_t *p2 = p;
+ while (p2 && *p2 && *p2 != L':') p2++;
+ if (p2 && *p2 == L':') *p2++ = 0;
+ if (!config_isregistered(p))
+ {
+ // dropped register on startup for Win8 as we cannot
+ // re-associate due to changes in the OSes behaviour
+ if (force || (!IsWin8() && config_check_ft_startup))
+ {
+ config_register(p, 1);
+ something_regged=1;
+ }
+ }
+ else
+ {
+ int a = 0;
+ wchar_t *w = c_list;
+ if (IsPlaylistExtension(p))
+ a = 1;
+ else while (w && *w && !a)
+ {
+ if (!_wcsicmp(w, p)) a = 1;
+ w += lstrlenW(w) + 1;
+ }
+ if (!a)
+ {
+ config_register(p, 0);
+ something_regged=1;
+ }
+ }
+ p = p2;
+ }
+ GlobalFree((HGLOBAL)c_list);
+ if (something_regged)
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
+}
+
+static int RegisterThread(HANDLE handle, void *user_data, intptr_t id)
+{
+ CoInitializeEx(0,COINIT_MULTITHREADED);
+ _reg_associated_filetypes((int)id);
+ CoUninitialize();
+ return 0;
+}
+
+void reg_associated_filetypes(int force)
+{
+ WASABI_API_THREADPOOL->RunFunction(0, RegisterThread, 0, force, api_threadpool::FLAG_LONG_EXECUTION|api_threadpool::FLAG_REQUIRE_COM_MT);
+} \ No newline at end of file
diff --git a/Src/Winamp/resource.h b/Src/Winamp/resource.h
new file mode 100644
index 00000000..ad31cb48
--- /dev/null
+++ b/Src/Winamp/resource.h
@@ -0,0 +1,1526 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Winamp.rc
+//
+#define IDS_UNINST_1 1
+#define IDS_UNINST_CAP 2
+#define IDC_ID3_REMOVE 3
+#define IDS_UNINST_CANCEL 3
+#define IDC_NEVER 3
+#define IDC_CANCELALL 3
+#define IDRESET 3
+#define IDS_UNINST_SURE 4
+#define IDS_ERROR 4
+#define IDS_ERRORINIT 5
+#define IDS_EQCAPTION 6
+#define IDS_PECAPTION 7
+#define IDS_OPENDIR 8
+#define IDS_OPENDIRMORE 9
+#define IDS_PLUGINERROR 10
+#define IDS_ERRORLOADINGPLUGIN 11
+#define IDS_DYNAMICLINKS 12
+#define IDS_DLINK_UPDATE 13
+#define IDS_PREFS_BOOK 13
+#define IDS_DLINK_NOCONTENT 14
+#define IDS_DLINK_GETTING 15
+#define IDS_DLINK_SUCCESS 16
+#define IDS_BASICINFO 16
+#define IDS_DLINK_ERROR 17
+#define IDS_UNREGSTRING 18
+#define IDS_ARTWORK 18
+#define IDS_STATS 19
+#define IDS_ADVANCED 19
+#define IDS_ONLYHTTP 20
+#define IDS_WINAMP_UPDATE_MSG 20
+#define IDS_NOOUTPUT 21
+#define IDS_PLAYLISTSTRING 22
+#define IDS_ALLTYPES 23
+#define IDS_RETRPL 24
+#define IDS_CONF_HELPSTR 25
+#define IDS_P_IN_INPUTS 26
+#define IDS_P_IN_CONF 27
+#define IDS_P_IN_ABOUT 28
+#define IDS_P_O_DEFEXT 29
+#define IDS_P_SETUP_PROXY 30
+#define IDS_P_OUT_CONF 31
+#define IDS_P_OUT_ABOUT 32
+#define IDS_P_OUT_OUTPUTS 33
+#define IDS_P_O_PRIO 34
+#define IDS_P_SETUP_PRIO 34
+#define IDS_P_DISP_SYSTRAY 35
+#define IDS_P_DISP_TASKBAR 36
+#define IDS_P_DISP_SYSTRAYICON 37
+#define IDS_P_DISP_SYSTRAYTASK 38
+#define IDS_P_DISP_FREESIZE 38
+#define IDS_P_DISP_NONE 39
+#define IDS_P_CLASSICUI 39
+#define IDS_P_DISP_HILITE 40
+#define IDS_P_DISP_SNAP 41
+#define IDS_P_DISP_CB 42
+#define IDS_P_DISP_TTIPS 43
+#define IDS_P_O_SPLASH 44
+#define IDS_P_DISP_TNUMS 45
+#define IDS_P_O_PLCHILD 46
+#define IDS_P_O_SPLB 46
+#define IDS_P_O_EQDS 47
+#define IDS_P_DISP_CURSORS 48
+#define IDS_P_O_ONLOAD 49
+#define IDS_P_O_ONDEM 50
+#define IDS_P_O_RFL 51
+#define IDS_P_O_AMI 52
+#define IDS_P_SETUP_MINST 52
+#define IDS_P_O_CONVERT1 53
+#define IDS_P_O_CONVERT2 54
+#define IDS_P_DISP_STITLE 55
+#define IDS_P_DISP_PLFONT 56
+#define IDS_P_O_LITESTEP 57
+#define IDS_P_O_AOVD 58
+#define IDS_P_FT_EXTENSIONS 59
+#define IDS_P_FT_ALL 60
+#define IDS_P_FT_NO 61
+#define IDS_P_FT_ENQUEUE 62
+#define IDS_P_FT_ICON 63
+#define IDS_P_FT_ICON2 64
+#define IDS_P_SETUP_START 65
+#define IDS_PREFSHLP_FT_DESK 66
+#define IDS_P_VIS_LIB 67
+#define IDS_P_VIS_MOD 68
+#define IDS_P_PLUG_AUTO 69
+#define IDS_P_PLUG_DIS 70
+#define IDS_P_VIS_START 71
+#define IDS_P_VIS_STOP 72
+#define IDS_P_VIS_CONF 73
+#define IDS_P_PLUG_PRIO 74
+#define IDS_P_DSP_LIB 75
+#define IDS_P_DSP_MOD 76
+#define IDS_P_DSP_CONF 77
+#define IDS_P_GEN_LIB 78
+#define IDS_P_GEN_CONF 79
+#define IDS_TOOLTIPS 81
+#define IDS_P_SETUP_START2 82
+#define IDS_P_SETUP_LANG 83
+#define IDS_P_FT_DIRCONTEXT 84
+#define IDS_P_DISP_SNAPW 85
+#define IDS_P_PLUG_VISDIR 86
+#define IDS_P_PLUG_DSPDIR 87
+#define IDS_SELVISDIR 88
+#define IDS_SELDSPDIR 89
+#define IDS_PREFS_SETUP 90
+#define IDS_PREFS_FT 91
+#define IDS_PREFS_OPTIONS 92
+#define IDS_PREFS_DISPLAY 93
+#define IDS_PREFS_TITLES 93
+#define IDS_PREFS_PLUG 94
+#define IDS_PREFS_PLUG_IN 95
+#define IDS_PREFS_PLUG_OUT 96
+#define IDS_PREFS_PLUG_VIS 97
+#define IDS_PREFS_PLUG_DSP 98
+#define IDS_PREFS_PLUG_GEN 99
+#define IDS_P_FT_CD 100
+#define WINAMP_MAIN 101
+#define IDS_MBCAPTION 101
+#define ICON_XP 102
+#define IDS_INETLOC 102
+#define IDD_BUFFERS 103
+#define IDS_PERMDELALL 103
+#define IDD_OUTPUT 104
+#define IDS_LANGCHANGE 104
+#define IDS_SELLANGPACK 105
+#define IDS_DELETEAUTOLOAD1 106
+#define IDS_DELETEAUTOLOAD2 107
+#define IDS_DELETEPRE1 108
+#define IDB_SPLASH 109
+#define IDS_LOADAUTOLOAD 109
+#define IDD_SPLASH 110
+#define IDS_SAVEAUTOLOAD 110
+#define IDS_PLFONT 111
+#define IDS_PLFONT_CHARSET 112
+#define IDS_P_FT_RSTART 113
+#define IDS_P_DISP_BIFONT 114
+#define IDS_GETMORE 115
+#define IDD_PREFS 116
+#define IDS_INST_DONETITLE 116
+#define IDS_INST_SETTITLE 117
+#define IDS_INST_CLOSE 117
+#define IDS_INST_USERINFO 118
+#define IDS_P_DISP_PLPOS 118
+#define IDS_INST_LATER 119
+#define IDS_ART_SEARCH_FAILED 119
+#define IDD_ABOUT1 120
+#define IDS_INST_SENDINGIN 120
+#define IDD_NEWABOUT1 120
+#define IDS_INST_FINISH 121
+#define IDS_INST_INET1 122
+#define IDS_INST_INET2 123
+#define IDS_INST_INET3 124
+#define IDS_INET_CANCEL1 125
+#define IDS_ART_SEARCH_FINISHED 125
+#define IDB_MAINBITMAP 126
+#define IDS_P_SETUP_VER 126
+#define IDB_CBUTTONS 127
+#define IDS_P_SETUP_ADDQL 127
+#define IDS_P_SETUP_INTERNET 127
+#define IDB_MONOSTEREO 128
+#define IDS_P_SETUP_INET1 128
+#define IDB_PLAYPAUSE 129
+#define IDS_P_SETUP_INET2 129
+#define IDB_SHUFFLEREP 130
+#define IDS_P_SETUP_INET3 130
+#define IDI_FILEICON 131
+#define IDS_DSP_NONE 131
+#define IDB_NUMBERS1 132
+#define IDS_CONFIG_PLAYSTR 132
+#define IDB_VOLBAR 133
+#define IDS_CONFIG_ENQUEUESTR 133
+#define IDB_FONT1 134
+#define IDS_PREFS_SKIN 134
+#define IDB_POSBAR 135
+#define IDS_P_O_MPA 135
+#define IDS_P_SK_SEL 136
+#define IDS_P_SK_RND 137
+#define IDS_P_SK_CHDR 138
+#define IDS_PREFS_VIS 139
+#define IDS_PREFS_CLASSICSKIN 139
+#define IDS_PREFS_AG 140
+#define IDD_EQ 141
+#define IDS_P_SETUP_VER2 141
+#define IDD_PLAYLISTEDITOR 142
+#define IDS_P_A_ENABLE 142
+#define IDD_EQUALIZER_UI 142
+#define IDS_P_A_TRAY 143
+#define IDD_FILETYPES 144
+#define IDS_P_FILEASSOCIATIONS 144
+#define IDD_VIS 145
+#define IDS_CONFIG_BOOKMARKSTR 145
+#define IDS_P_O_ONPLAY 146
+#define IDS_P_O_SMS 147
+#define IDR_ACCELERATOR1 148
+#define IDS_PREFS_SHUFFLE 148
+#define IDB_SPEC 149
+#define IDS_VIDEOCAPTION 149
+#define IDB_TB 150
+#define IDS_PREFS_VIDEO 150
+#define IDS_P_O_VIDEO_VSYNC 151
+#define IDD_ABOUT2 152
+#define IDS_P_O_VIDEO_ADJASP 152
+#define IDB_NULLSOFT 153
+#define IDS_P_O_VIDEO_OVERLAYS 153
+#define IDD_ABOUT3 154
+#define IDD_NEWABOUT2 154
+#define IDS_P_O_VIDEO_UPDSIZE 154
+#define IDD_ABOUT4 155
+#define IDS_P_O_VIDEO_AUTOCLOSE 155
+#define IDD_ABOUT5 156
+#define IDS_P_O_VIDEO_NOSS 156
+#define IDD_ABOUT6 157
+#define IDS_P_O_VIDEO_OSD 157
+#define IDR_ACCELERATOR2 158
+#define IDS_P_O_VIDEO_YV12 158
+#define IDS_P_O_VIDEO_STOPCLOSE 159
+#define IDS_P_O_VIDEO_REMOVE_FS_ON_STOP 160
+#define IDD_DISPLAY 161
+#define IDS_P_O_VIDEO_AUTOOPEN 161
+#define IDD_M3U_DELETE 161
+#define IDI_FILEICON2 162
+#define IDS_P_CLASSICVIS 162
+#define IDI_FILEICON3 163
+#define IDS_P_IN_UNINST 163
+#define IDI_FILEICON10 164
+#define IDS_P_VIS_UNINST 164
+#define IDD_ID3EDIT 165
+#define IDS_P_OUT_UNINST 165
+#define IDS_P_SKINS_DELETESKIN 166
+#define IDI_FILEICON5 167
+#define IDS_P_SKINS_DELETESKIN_PROMPT 167
+#define IDS_P_O_VIDEO_AGRESSIVENOSS 168
+#define IDI_FILEICON6 169
+#define IDS_P_PLUG_DISSEHVIS 169
+#define IDS_P_PLUG_DISSEHDSP 170
+#define IDS_P_PLUG_DISSEHGEN 171
+#define IDS_P_SKINS_RN_ERR 172
+#define IDD_LOADPRESET 173
+#define IDS_P_SKINS_RN_ERR_CAP 173
+#define IDD_SAVEPRESET 174
+#define IDS_P_EQ_FILE 174
+#define IDS_P_FILE_EQ 174
+#define IDR_ACCELERATOR3 175
+#define IDS_P_EQ_FILE_READ 175
+#define IDD_OPENLOC 176
+#define IDR_ACCELERATOR4 176
+#define IDS_P_EQ_FILE_WRITE 176
+#define IDD_HTTP 177
+#define IDS_P_FILE_ALL 177
+#define IDI_FILEICON7 178
+#define IDD_PLUGIN 178
+#define IDS_NO_BOOKMARKS 178
+#define IDI_FILEICON8 179
+#define IDS_ART_SEARCH_PROGRESS 179
+#define IDI_FILEICON9 180
+#define IDS_ART_SEARCH_STATUS 180
+#define IDI_FILEICON4 181
+#define IDS_ART_SEARCH_NOT_FOUND_TITLE 181
+#define IDI_FILEICON11 182
+#define IDS_ART_SEARCH_NOT_FOUND 182
+#define IDI_FILEICON12 183
+#define IDS_NO_IMAGE 183
+#define IDD_JUMPDLG 184
+#define IDS_PLAYLISTSTRING_NEW 184
+#define IDD_JUMPFILEDLG 185
+#define IDS_P_LANG_PACK_DELETEWLZ 185
+#define IDS_P_LANG_PACK_DELETEWLZ_PROMPT 186
+#define IDS_RENAME_WLZ 187
+#define IDD_ABOUT7 188
+#define IDD_SKINS 189
+#define IDD_PLUGIN2 190
+#define IDS_P_O_VIDEO_FLIPRGB 190
+#define IDR_PLMENU 191
+#define IDC_REGDLG 191
+#define IDS_SELDOWNLOADDIR 191
+#define IDD_EDITENTRY 192
+#define IDS_STRING192 192
+#define IDS_LANGUAGEPACKS_MENU 192
+#define IDD_OPTIONS 193
+#define IDS_ONLINESERVICE_SELDOWNLOADDIR 193
+#define IDB_EQMAIN 194
+#define IDB_PANBAR 197
+#define IDB_PLEDIT 199
+#define IDS_WHATSNEW_FAIL 200
+#define IDS_WINAMP_CMDLINE 201
+#define IDS_SKINS_INSTALL_PROMPT 202
+#define IDS_SKINS_INSTALL_HEADER 203
+#define IDS_HTTP_LOAD_ERROR 204
+#define IDC_MOVEMAIN 205
+#define IDS_HTTP_INIT_SOCKET 205
+#define IDC_LRSCROLL 206
+#define IDS_HTTP_INIT_SOCKET_ERROR 206
+#define IDC_DANGER 207
+#define IDS_HTTP_SOCKET_CREATE 207
+#define IDC_NORMALCURSOR 208
+#define IDS_HTTP_SOCKET_ERROR 208
+#define IDC_UDSCROLL 209
+#define IDS_HTTP_RESOLVE_PROXY 209
+#define IDB_ME 210
+#define IDC_RESIZE 210
+#define IDS_HTTP_RESOLVE_HOST 210
+#define IDS_HTTP_RESOLVE_PROXY_ERROR 211
+#define IDB_CAT 212
+#define IDS_HTTP_RESOLVE_HOST_ERROR 212
+#define IDS_HTTP_CONNECT_PROXY 213
+#define IDD_NEWSETUP 213
+#define IDD_HTTPGET 214
+#define IDS_HTTP_CONNECT_HOST 214
+#define IDD_NEWPREFS 215
+#define IDS_HTTP_CONNECT_PROXY_ERROR 215
+#define IDS_HTTP_CONNECT_HOST_ERROR 216
+#define IDD_NEWFTYPES 217
+#define IDS_HTTP_SEND_REQUEST 217
+#define IDD_NEWOPTIONS 218
+#define IDS_HTTP_READ_REQUEST 218
+#define IDD_NEWDISPLAY 219
+#define IDS_HTTP_CONNECTION_LOST 219
+#define IDS_HTTP_CONNECTION_CLOSED 220
+#define IDS_HTTP_ERROR_OPEN_FILE 221
+#define IDD_NEWINPUT 222
+#define IDS_HTTP_RETRIEVE_FILE_LENGTH 222
+#define IDD_NEWOUTPUT 223
+#define IDS_HTTP_RETRIEVE_FILE 223
+#define IDD_NEWVIS 224
+#define IDS_HTTP_FILE_INCOMPLETE 224
+#define IDD_NEWDSP 225
+#define IDS_HTTP_SUCCESS 225
+#define IDD_NEWGEN 226
+#define IDS_HTTP_CLOSE 226
+#define IDS_CLOSE_COUNTDOWN 227
+#define IDB_MB 228
+#define IDS_HTTP_WINAMP_UPDATE_SITE 228
+#define IDS_HTTP_INIT 229
+#define IDD_METRIC1 230
+#define IDS_HTTP_ABORT 230
+#define IDD_FIRSTSETUP 231
+#define IDB_EQEX 231
+#define IDS_HTML_ERROR_WRITE 231
+#define IDS_HTTP_RET_FILE 232
+#define IDD_FS_FILES 233
+#define IDS_HTTP_RET_FILE_PERCENT 233
+#define IDD_FS_REG 234
+#define IDD_FS_REG2 235
+#define IDD_NEWSKIN 236
+#define IDD_NEWVIS2 237
+#define IDD_CLASSIC_VIS 237
+#define IDD_ABOUT8 238
+#define IDD_NEWAGENT 239
+#define IDD_NEWBOOKMARKS 240
+#define IDI_UNINST 240
+#define IDS_ML_NO_PLAYLISTS 240
+#define IDD_EDITBOOKMARK 241
+#define IDS_ML_OPEN_PLAYLIST 241
+#define IDB_BITMAP1 242
+#define IDS_ML_OPEN_VIEW_RESULTS 242
+#define IDD_NEWABOUT3 243
+#define IDB_BITMAP2 243
+#define IDs_PE_CLOSE 243
+#define IDS_PE_CLOSE 243
+#define IDD_NEWABOUT4 244
+#define IDS_PE_OPEN 244
+#define IDD_NEWABOUT 245
+#define IDS_ML_EXPORT_PLAYLIST 245
+#define IDD_NEWSHUFFLEOPTS 246
+#define IDS_ML_CLOSE_ML 246
+#define IDS_ML_OPEN_ML 247
+#define IDB_VIDEOLOGO 248
+#define IDS_ML_MANAGE_PLAYLISTS 248
+#define IDB_VIDEO 249
+#define IDS_ML_SMART_VIEW_RESULTS 249
+#define IDB_EMBEDWND 250
+#define IDS_OFD_OPEN_FILES 250
+#define IDS_OFD_ADD_FILES_TO_PLAYLIST 251
+#define IDB_GENEX 252
+#define IDS_OFD_ALL_FILES 252
+#define IDS_STATIONINFOCAPTION 253
+#define IDB_TEAM 254
+#define IDS_STATIONINFO_MENU 254
+#define IDD_BURN 255
+#define IDS_WINAMP_UPDATE 255
+#define IDD_EDITREG 256
+#define WINAMP5_MENUBAR 256
+#define IDS_SENDTO_STR 256
+#define IDD_PREFS_CLASSICSKIN 257
+#define IDS_RATEITEM_STR 257
+#define IDD_CLASSIC_UI 258
+#define IDS_ERROR_DELETING 258
+#define IDD_NEWTITLE 259
+#define IDS_PREFS_PLAYBACK 259
+#define IDD_RENAMESKIN 260
+#define IDS_P_CLASSIC_70FPS 260
+#define IDD_BROWSE_RECDLG 261
+#define IDS_P_CLASSIC_35FPS 261
+#define ICON_TB1 262
+#define IDS_P_CLASSIC_18FPS 262
+#define IDD_NEWABOUT1EGG 263
+#define IDS_P_CLASSIC_9FPS 263
+#define IDS_P_PLUGIN_UNINSTALL 264
+#define IDB_SPLASH2 265
+#define IDS_P_PLUGIN_UNINSTALL_CONFIRM 265
+#define IDS_LANGCHANGE_TITLE 266
+#define IDB_PLATE 267
+#define IDD_STATIONINFO 267
+#define IDS_P_PLAYBACK_RG_SOURCE_TRACK 267
+#define IDB_BITMAP3 268
+#define IDB_SURROUND 268
+#define IDD_PLAYBACK 268
+#define IDS_P_PLAYBACK_RG_SOURCE_ALBUM 268
+#define IDS_P_PLAYBACK_RG_MODE_AG 269
+#define IDD_CRASHDLG 270
+#define IDB_BITMAP4 271
+#define IDB_BETA 271
+#define IDD_CRASHDG 272
+#define IDS_P_PLAYBACK_RG_MODE_AG_PC 277
+#define IDS_P_PLAYBACK_RG_MODE_N 278
+#define IDS_P_PLAYBACK_RG_MODE_PC 279
+#define IDS_P_24BIT_WARNING 280
+#define IDS_P_24BIT_WARNING_TITLE 281
+#define IDS_P_PLDIRECTION_AUTO 282
+#define IDS_P_PLDIRECTION_L2R 283
+#define IDS_P_PLDIRECTION_R2L 284
+#define IDS_P_SELECT_SKINDIR 285
+#define IDS_P_SKIN_NO_INFO_FOUND 286
+#define IDD_EDIT_INFO 286
+#define IDD_ADDSTUFF 287
+#define IDS_P_SKIN_ERR_RENAME 287
+#define IDS_P_SKIN_ERR_RENAME_TITLE 288
+#define IDS_P_TAGZ_ERROR_TITLE 289
+#define IDS_P_TAGZ_NOT_INSTALLED 290
+#define IDS_WINAMP_MENUITEM 301
+#define IDS_ML_MISSING_FOR_BOOKMARKS 302
+#define IDS_PLAYLIST_SUPPORT_NOT_INSTALLED 303
+#define IDS_PLAYLIST_LOAD_ERROR 304
+#define IDS_OPEN_PLAYLIST 305
+#define IDS_ADD_PLAYLIST 306
+#define IDS_SAVE_PLAYLIST 307
+#define IDS_PLAYLIST_FILTER_STRING 308
+#define IDD_NEWLANG 317
+#define IDD_FILEINFO 318
+#define IDD_FILEINFO_METADATA 319
+#define IDS_CONV_SRC_EQUALS_DEST 320
+#define IDD_FILEINFO_ARTWORK 320
+#define IDS_CONV_DECODER_MISSING 323
+#define IDS_CONV_INPUT_PLUGIN_NOT_SUPPORTING 324
+#define IDS_CONV_DRM_DECODE_FAIL 325
+#define IDS_CONV_ERROR_OPEN_FILE 326
+#define IDS_CONV_ERROR_OPEN_ENCODER 327
+#define IDS_CONV_ERROR_OPEN_DEST 328
+#define IDS_NOTPRESENT 329
+#define IDS_ARTDELETE 330
+#define IDS_AREYOUSURE 331
+#define IDD_ARTDOWNLOADER 332
+#define IDD_ARTDOWNLOADER_SCROLLHOST 333
+#define IDD_ARTDOWNLOADER_IMAGE 334
+#define IDD_ARTDOWNLOADER_SCROLLCHILD 335
+#define IDS_BURN_NULLSOFT_STR 336
+#define IDS_BURN_LIBRARY_INIT_FAILED 337
+#define IDS_BURN_INVALID_PLAYLIST_PATH 338
+#define IDS_BURN_INVALID_TEMP_PATH 339
+#define IDS_BURN_INVALID_CONFIG_PATH 340
+#define IDS_BURN_INVALID_CMDLINE 341
+#define IDS_BURN_BAD_DRIVE_LETTER 342
+#define IDS_BURN_LOAD_FROM_PLAYLIST_FAIL 343
+#define IDS_BURN_CREATE_DIALOG_FAIL 344
+#define IDS_BURN_UNKNOWN_ERROR 345
+#define IDS_BURN_INIT_ERROR_REASON 346
+#define IDS_BURN_INIT_ERROR_UNKNOWN 347
+#define IDD_AUTOTAGGING 349
+#define IDD_REPLAY_GAIN_UI 351
+#define IDS_PREAMP 352
+#define IDD_NEWPLUG 352
+#define IDD_NEWVIDEOOPTS 353
+#define IDS_OPTIONS_MENU 353
+#define IDS_DISABLE_AOT 354
+#define IDS_ENABLE_AOT 355
+#define IDS_FILE_INFO_BOX 356
+#define IDS_DISABLE_DOUBLESIZE_MODE 357
+#define IDS_ENABLE_DOUBLESIZE_MODE 358
+#define IDS_VISUALIZATION_MENU 359
+#define IDS_SEEK_TO 360
+#define IDS_VOLUME 361
+#define IDS_BALANCE 362
+#define IDS_BALANCE_CENTRE 363
+#define IDS_BALANCE_LEFT 364
+#define IDS_BALANCE_RIGHT 365
+#define IDS_TITLE_ON_STOP 366
+#define IDS_TITLE_ON_PAUSE 367
+#define IDS_LANG_INSTALL_PROMPT 368
+#define IDS_LANG_INSTALL_HEADER 369
+#define IDS_PLEDIT_NOFILE_WSHADE 370
+#define IDS_AUDIO_CD_FORMAT 371
+#define IDS_CLASSIC_SKIN_NAME 372
+#define IDS_CLASSIC_BASE_SKIN_VERSION 373
+#define IDS_OSD_PROGRESS_TEXT 374
+#define IDS_OSD_VOLUME_TEXT 375
+#define IDS_REFRESH_PLAYLIST_TITLES 376
+#define IDS_ATF_HAS_CHANGED 377
+#define IDS_P_SELECT_LANGDIR 384
+#define IDS_P_LANG_ERR_RENAME 385
+#define IDS_P_LANG_ERR_RENAME_TITLE 386
+#define IDS_LOCALIZATION 387
+#define IDS_NO_MATCHES_FOUND 388
+#define IDS_GRACENOTE_TOOLS_NOT_INSTALLED 389
+#define IDS_NO_MATCH_FOUND 390
+#define IDS_FAILED 391
+#define IDS_SHUFFLE_MORPH_INFO 392
+#define IDS_SHUFFLE_MORPH_RATE 393
+#define IDS_ADD_FOLDER 394
+#define IDS_ADD_URL 395
+#define IDS_SHOW_ALL_HISTORY 396
+#define IDS_P_LNG_CHDR 397
+#define IDS_P_DISP_SPLEDPOS 398
+#define IDS_IMAGE_FILES 399
+#define IDS_P_EQUALIZER 400
+#define IDS_P_4FRONT_EQ 401
+#define IDS_P_CONSTANT_Q 402
+#define IDS_P_WA_FREQ_BANDS 403
+#define IDS_P_ISO_FREQ_BANDS 404
+#define IDS_P_REPLAY_GAIN 405
+#define IDS_TRACK_GAIN_AND_ALBUM_GAIN 406
+#define IDS_EQ_HZ 407
+#define IDS_EQ_DB 408
+#define IDS_EQ_KHZ 409
+#define IDS_JPEG_FILE 410
+#define IDS_PNG_FILE 411
+#define IDS_GIF_FILE 412
+#define IDS_BMP_FILE 413
+#define IDS_P_EQ_TYPE_CHANGE 414
+#define IDS_P_EQ_TYPE_CHANGE_MSG 415
+#define IDS_CUR_WLZ_INFO 416
+#define IDS_SEL_WLZ_INFO 417
+#define IDS_WA_RESTART_FOR_WLZ_NEEDED 418
+#define IDS_DOWNLOADING 419
+#define IDS_COVER 420
+#define IDS_KBPS 421
+#define IDS_METADATA_ERROR 422
+#define IDS_METADATA_ERROR_TITLE 423
+#define IDS_CLICKHERE 424
+#define IDS_WINAMP_MEDIA_FILE 425
+#define IDS_WINAMP_PLAYLIST_FILE 426
+#define IDS_WINAMP_EXTENSION_INSTALLATION_FILE 427
+#define IDS_WINAMP_LANGUAGE_INSTALLATION_FILE 428
+#define IDS_STRING429 429
+#define IDS_WINAMP_FILE_INSTALL 429
+#define IDS_WIN7TOOLBAR_TOOLTIP_PREVIOUS 430
+#define IDS_WIN7TOOLBAR_TOOLTIP_PLAY 431
+#define IDS_WIN7TOOLBAR_TOOLTIP_PAUSE 432
+#define IDS_WIN7TOOLBAR_TOOLTIP_STOP 433
+#define IDS_WIN7TOOLBAR_TOOLTIP_NEXT 434
+#define IDS_SECURITY_APPLICATION_LAUNCHURL 435
+#define IDS_SECURITY_TRANSPORT_EVENTS 436
+#define IDS_SECURITY_TRANSPORT_METADATA 437
+#define IDS_SECURITY_TRANSPORT_CONTROLS 438
+#define IDS_SECURITY_PLAYER_PLAYLIST 439
+#define IDS_SECURITY_PLAYER_METADATA 440
+#define IDS_SECURITY_DOWNLOADER_EVENTS 441
+#define IDS_SECURITY_DOWNLOADER_DOWNLOADMEDIA 442
+#define IDS_SECURITY_SECURITY_AUTH 443
+#define IDS_SECURITY_BOOKMARKS_AUTH 444
+#define IDS_SECURITY_SKIN_AUTH 445
+#define IDS_SECURITY_MEDIACORE_METADATAHOOK 446
+#define IDS_SECURITY_MEDIACORE_METADATA 447
+#define IDS_SECURITY_MEDIACORE_EXTENSIONS 448
+#define IDS_LANG_DIR_MOVE_MESSAGE 449
+#define IDS_SKIN_DIR_MOVE_MESSAGE 450
+#define IDS_DIR_MOVE_ERROR 451
+#define IDS_LANG_DIR_MOVE 452
+#define IDS_SKIN_DIR_MOVE 453
+#define IDS_NOML_SAVE_RATING 454
+#define IDS_STRING455 455
+#define IDS_NOML_SAVE_RATING_TITLE 455
+#define IDS_RELEASED 456
+#define IDS_EQ_TOOLTIPS 457
+#define IDS_VID_TOOLTIPS 458
+#define IDS_PL_TOOLTIPS 459
+#define IDS_P_FT_EXTENSIONS_WIN8 460
+#define IDS_ARTWORK_DETAILS 461
+#define IDS_ORIGIN_NONE 462
+#define IDS_ORIGIN_EMBEDDED 463
+#define IDS_ORIGIN_ALBUM_MATCH 464
+#define IDS_ORIGIN_NFO 465
+#define IDS_ORIGIN_COVER_MATCH 466
+#define IDS_ORIGIN_FOLDER_MATCH 467
+#define IDS_ORIGIN_FRONT_MATCH 468
+#define IDS_ORIGIN_ARTWORK_MATCH 469
+#define IDS_SKINS_INSTALL_ERROR 470
+#define IDS_LANG_INSTALL_ERROR 471
+#define IDS_PREFS_SAFE_MODE 472
+#define IDS_START_SAFE_MODE 474
+#define IDS_FAILED_SAFE_MODE 475
+#define IDS_FAILED_SAFE_MODE_MSG 476
+#define IDS_SAFE_MODE_ALL 477
+#define IDS_SAFE_MODE_NORMAL 478
+#define IDS_RESTART_NORMAL 479
+#define IDS_STRING194 480
+#define IDS_P_PLUG_SAFEMODE 480
+#define IDS_RESTART_SAFE 481
+#define IDS_STRING482 482
+#define IDS_RESTART 482
+#define IDS_NO_MODERN_SKIN_SUPPORT 483
+#define IDS_SKIN_LOAD_ERROR 484
+#define IDS_AUDIO_CD 485
+#define IDS_EMPTY 486
+#define IDS_BYTES 487
+#define IDS_KIB 488
+#define IDS_MIB 489
+#define IDS_GIB 490
+#define IDS_TIB 491
+#define IDS_KB 492
+#define IDS_MB 493
+#define IDS_GB 494
+#define IDS_TB 495
+#define IDS_P_SILENCE_DETECT 496
+#define IDS_SHUFFLE_ON 497
+#define IDS_SHUFFLE_OFF 498
+#define IDS_REPEAT_OFF 499
+#define IDS_REPEAT_PL 500
+#define IDS_REPEAT_TRACK 501
+#define IDS_MAN_ADV_ON 502
+#define IDS_MAN_ADV_ON2 503
+#define IDS_MAN_ADV_OFF 503
+#define IDS_DEF_PROG_LOAD_ERROR 504
+#define IDS_RESET_URLS 505
+#define IDS_RESET_URLS_TITLE 506
+#define IDS_P_DISP_BIFONT_ALT 510
+#define IDS_P_FILE_ASSOC 511
+#define IDS_P_FILE_ASSOC_FAILURE 512
+#define IDS_P_NO_MOUSEWHEEL 513
+#define IDS_P_PLUG_SAFEMODEALWAYS 514
+#define IDS_NOT_LOADED 515
+#define IDS_NO_RATING 516
+#define IDS_X_ITEM_SELECTED 517
+#define IDS_X_ITEMS_SELECTED 518
+#define IDS_UPDATING_FILES 519
+#define IDS_UPDATING_X 520
+#define IDS_ERROR_UPDATING_FILE 521
+#define IDS_INFO_UPDATING_ERROR 522
+#define IDS_P_O_VIDEO_AUTO_FS_ON_START 526
+#define IDS_P_O_VIDEO_ENABLE 527
+#define IDS_P_VIDEO_CHANGE 528
+#define IDS_P_VIDEO_CHANGE_MSG 529
+#define IDS_P_O_VIDEO_HIDE_PREFS 530
+#define IDS_STREAMINFO 532
+#define IDS_P_SK_PROMPT 533
+#define IDS_PREFS_ARTWORK 534
+#define IDS_STRING80 535
+#define IDS_UNKNOWN_MIME 536
+#define IDS_RC_CHANNEL_TITLE 540
+#define IDS_RC_CHANNEL_MESSAGE 541
+#define IDS_RC_CHANNEL_CHECKBOX 542
+#define IDC_BUFFERS_NUMBUFS 1001
+#define IDC_PREFS_VIDEO_FLIPRGB 1001
+#define IDC_EDIT_ARTIST 1002
+#define IDC_CHECK_ARTIST 1003
+#define IDC_8BIT 1004
+#define IDC_CHECK_TITLE 1004
+#define IDC_16BIT 1005
+#define IDC_RG_ASK 1005
+#define IDC_CHECK_ALBUM 1005
+#define IDC_PREFS_SPLASH 1006
+#define IDC_RG_ALBUM 1006
+#define IDC_CHECK_TRACK 1006
+#define IDC_WA_CURSORS 1007
+#define IDC_RG_ALL 1007
+#define IDC_CHECK_GENRE 1007
+#define IDC_PREFS_SYSTRAY 1008
+#define IDC_CHECK_YEAR 1008
+#define IDC_EDIT_TITLE 1009
+#define IDC_EDIT_ALBUM 1010
+#define IDC_PREBUFSLIDER 1011
+#define IDC_EDIT_TRACK 1011
+#define IDC_EDIT_GENRE 1012
+#define IDC_ALLOWMI 1013
+#define IDC_EDIT_YEAR 1013
+#define IDC_FORMAT 1014
+#define IDC_CHECK_COMMENT 1014
+#define IDC_RFL 1015
+#define IDC_USEID3 1015
+#define IDC_EDIT_COMMENT 1015
+#define IDC_REGFILETYPES 1016
+#define IDC_MINST 1016
+#define IDC_USEID6 1016
+#define IDC_CHECK_DISC 1016
+#define IDC_USEID4 1017
+#define IDC_EDIT_DISC 1017
+#define IDC_USEID5 1018
+#define IDC_SPIN1 1018
+#define IDC_CHECK_ALBUMARTIST 1018
+#define IDC_EQ1 1019
+#define IDC_SPIN3 1019
+#define IDC_EDIT_ALBUMARTIST 1019
+#define IDC_EQ2 1020
+#define IDC_SPIN2 1020
+#define IDC_CHECK_PUBLISHER 1020
+#define IDC_EQ3 1021
+#define IDC_STATIC66 1021
+#define IDC_EDIT_PUBLISHER 1021
+#define IDC_EQ4 1022
+#define IDC_CHECK_COMPOSER 1022
+#define IDC_EQ5 1023
+#define IDC_EDIT_COMPOSER 1023
+#define IDC_EQ6 1024
+#define IDC_CHECK_CATEGORY 1024
+#define IDC_EQ7 1025
+#define IDC_EDIT_CATEGORY 1025
+#define IDC_EQ8 1026
+#define IDC_CHECK_BPM 1026
+#define IDC_EQ9 1027
+#define IDC_EDIT_BPM 1027
+#define IDC_EQ10 1028
+#define IDC_CHECK_RATING 1028
+#define IDC_EQ_ENABLED 1029
+#define IDC_EQ_CLOSE 1030
+#define IDC_PLAYLIST_LISTBOX 1031
+#define IDC_EQ_RESET 1031
+#define IDC_EQ11 1031
+#define IDC_TAGZ_HELP 1031
+#define IDC_PLAYLIST_ADDMP3 1032
+#define IDC_EQ_ZERO 1032
+#define IDC_PLAYLIST_ADDPLAYLIST 1033
+#define IDC_PLAYLIST_REMOVEMP3 1034
+#define IDC_PLAYLIST_CROP 1035
+#define IDC_TAGZ_DEFAULT 1035
+#define IDC_PLAYLIST_ADDDIR 1036
+#define IDC_PLAYLIST_CLEAR 1037
+#define IDC_PLAYLIST_EDITID3 1038
+#define IDC_PLAYLIST_ADDLOC 1039
+#define ID_PE_REMOVE 1041
+#define IDC_AUTOSCROLL 1041
+#define IDC_PLAYLIST_MOVEBAR 1042
+#define IDC_SA 1043
+#define IDC_OSC 1044
+#define IDC_NOVIS 1045
+#define IDC_STEREO 1046
+#define IDC_MONO 1047
+#define IDC_REVSTEREO 1048
+#define IDC_FULLRATE 1049
+#define IDC_HALFRATE 1050
+#define IDC_AMP_README 1054
+#define IDC_OUTPUTDEV 1056
+#define IDC_EQVOL 1058
+#define IDC_PLAYLIST_SORT 1059
+#define IDC_PLAYLIST_INVERT 1060
+#define IDC_PLAYLIST_REVERSE 1061
+#define IDC_PLAYLIST_LOADLIST 1062
+#define IDC_PLAYLIST_SAVELIST 1063
+#define IDC_ENC_CONFIG 1063
+#define IDC_SPECFALLOFF 1064
+#define IDC_PLAYLIST_RANDOMIZE 1064
+#define IDC_SPECREFRESH 1065
+#define IDC_SPECSCALE 1066
+#define IDC_TASKBAR 1067
+#define IDC_SYSTRAY 1068
+#define IDC_SYSTRAYANDTASK 1069
+#define IDC_OSCSCALE 1070
+#define IDC_NONE 1070
+#define IDC_FILETYPES_ICONSCROLL 1073
+#define IDC_PREFS_PRIORITY_CLASS 1074
+#define IDC_FILETYPES_ICONSCROLL2 1074
+#define IDC_PREFS_PRIORITY_OUTPUT 1075
+#define IDC_PREFS_PRIORITY_DECODE 1076
+#define IDC_FILETYPES_ICON 1077
+#define IDC_ID3_TITLE 1078
+#define IDC_FILETYPES_ICON2 1078
+#define IDC_ID3_ARTIST 1079
+#define IDC_ID3_ALBUM 1080
+#define IDC_ID3_COMMENT 1081
+#define IDC_ID3_YEAR 1082
+#define IDC_ID3_GENRE 1083
+#define IDC_ID3_FN 1084
+#define IDC_FN 1084
+#define IDC_ARTIST 1087
+#define IDC_ALBUM 1088
+#define IDC_YEAR 1089
+#define IDC_EQ_SAVE 1090
+#define IDC_GENRE 1090
+#define IDC_EQ_SAVEMPX 1091
+#define IDC_COMMENT 1091
+#define IDC_STATION 1091
+#define IDC_EQ_DELETE 1092
+#define IDC_COMPOSER 1092
+#define IDC_EQ_LOAD 1093
+#define IDC_EQ_PRESET 1094
+#define IDC_EQ_AUTOLOAD 1095
+#define IDC_PE_TIME 1096
+#define IDC_TRACK 1097
+#define IDC_LOADEQLIST 1099
+#define IDC_ALBUM_ARTIST 1099
+#define IDC_DISC 1100
+#define IDC_SAVEPRESET_EDIT 1101
+#define IDC_PUBLISHER 1101
+#define IDC_NORMALANALYZER 1102
+#define IDC_SPLASHIMG 1103
+#define IDC_FIREANALYZER 1103
+#define IDC_BUFFER_ALL 1104
+#define IDC_LINEANALYZER 1104
+#define IDC_BUF_SFAST 1106
+#define IDC_SNAP 1108
+#define IDC_ADDSTART 1109
+#define IDC_MAINPARENT 1109
+#define IDC_REMSTART 1110
+#define IDC_URL 1110
+#define IDC_HIGHLIGHT 1110
+#define IDC_ADDICON 1110
+#define IDC_SAVE 1111
+#define IDC_ADDDESKTOP 1111
+#define IDC_PLAY_URL 1111
+#define IDC_VOLUMEENABLED 1112
+#define IDC_ADDQL 1112
+#define IDC_PANREV 1113
+#define IDC_VISLIB 1113
+#define IDC_VISMOD 1114
+#define IDC_ALTVOL 1114
+#define IDC_VISTEST 1115
+#define IDC_VISCONF 1116
+#define IDC_VISPRIO 1117
+#define IDC_SNDLIB 1118
+#define IDC_BLOCKSIZE 1118
+#define IDC_DSPLIB 1118
+#define IDC_VISSTOP 1118
+#define IDC_MPEGINFO 1119
+#define IDC_DSPMOD 1119
+#define IDC_MINUTES 1120
+#define IDC_DSPCONF 1120
+#define IDC_SECONDS 1121
+#define IDC_GENLIB 1121
+#define IDC_TRACKLEN 1122
+#define IDC_SELBOX 1122
+#define IDC_GENCONF 1122
+#define IDC_AUTOEXEC 1123
+#define IDC_OUTPUTINTERP 1124
+#define IDC_HQ 1125
+#define IDC_DISVIS 1126
+#define IDC_ID3FORMAT 1127
+#define IDC_TIPS 1128
+#define IDC_PLAYLIST_BOX 1129
+#define IDC_ADD_BOX 1130
+#define IDC_REMOVE_BOX 1131
+#define IDC_LENGTHTEXT 1132
+#define IDC_MISC_BOX 1133
+#define IDC_SYSTRAY_ICON 1134
+#define IDC_SYSTRAY_SCROLLER 1135
+#define IDC_BUFMAX 1136
+#define IDC_CLUTTERBAR 1137
+#define IDC_ADDFILES 1138
+#define IDC_DIRCONTEXT 1139
+#define IDC_SM 1140
+#define IDC_PLUGINLINK 1141
+#define IDC_SM2 1141
+#define IDC_WINAMPLINK 1142
+#define IDC_PLUGINLINK2 1142
+#define IDC_SM3 1142
+#define IDC_WINAMPLINK2 1143
+#define IDC_WINAMPLINK3 1144
+#define IDC_AFTERSEEK 1144
+#define IDC_WINAMPLINK4 1145
+#define IDC_RESIZETHINGY 1145
+#define IDC_WINAMPLINK5 1146
+#define IDC_PE_ADD 1146
+#define IDC_WINAMPLINK6 1147
+#define IDC_WINAMPLINK7 1148
+#define IDC_NEWDLG 1148
+#define IDC_TTIPS 1148
+#define IDC_WINAMPLINK9 1149
+#define IDC_PROXYSTR 1149
+#define IDC_RANDOM 1150
+#define IDC_WINAMPLINK8 1150
+#define IDC_INPUTS 1151
+#define IDC_CONF 1152
+#define IDC_ABOUT 1153
+#define IDC_ABOUTTEXT 1153
+#define IDC_DEFEXT 1154
+#define IDC_ABOUT3 1154
+#define IDC_UNINSTDSP 1154
+#define IDC_LICINFO 1155
+#define IDC_OUTCONF 1155
+#define IDC_FTYPE_LIST 1156
+#define IDC_OUTABOUT 1156
+#define IDC_CONF2 1156
+#define IDC_USEINFO 1156
+#define IDC_SELALL 1157
+#define IDC_ABOUT2 1157
+#define IDC_SELNONE 1158
+#define IDC_ABOUTIMG 1159
+#define IDC_REFRESH 1159
+#define IDC_CHDIR 1160
+#define IDC_SELALL2 1161
+#define IDC_BUTTON1 1162
+#define IDC_SELALL3 1162
+#define IDC_NAME 1163
+#define IDC_BUTTON4 1163
+#define IDC_REG 1164
+#define IDC_OUTPLUG 1164
+#define IDC_BUTTON5 1164
+#define IDC_EDITBOOK 1165
+#define IDC_OLD 1167
+#define IDC_NEW 1168
+#define IDC_PLNUMS 1168
+#define IDC_PLCHILD 1169
+#define IDC_PLZEROPAD 1169
+#define IDC_EQDSIZE 1170
+#define IDC_OUTPUTS 1171
+#define IDC_CONVERT1 1172
+#define IDC_CONVERT2 1173
+#define IDC_TREE1 1173
+#define IDC_SCROLLTITLE 1174
+#define IDC_UPDATE 1175
+#define IDC_NIFTY 1175
+#define IDC_KEEPONSCREEN 1175
+#define IDC_SHOWPLEDITPOS 1175
+#define IDC_FLUSHCACHE 1176
+#define IDC_PLFONTSIZE 1177
+#define IDC_SAFEMODE 1177
+#define IDC_PLFONTSIZE_TEXT 1178
+#define IDC_AOVD 1179
+#define IDC_SNAPW 1180
+#define IDC_STATUS 1180
+#define IDC_MANUALPLAYLISTADVANCE 1180
+#define IDC_STATUS2 1181
+#define IDC_DROPAOTFS 1181
+#define IDC_POS_IN_SONGTICKER 1181
+#define IDC_STATIC_NO_IPOD 1181
+#define IDC_RADIO1 1182
+#define IDC_INET1 1182
+#define IDC_NO_MOUSEWHEEL 1182
+#define IDC_INET2 1183
+#define IDC_CHLANG 1184
+#define IDC_INET3 1185
+#define IDC_RECT 1186
+#define IDC_DSPDIR 1188
+#define IDC_VISDIR 1189
+#define IDC_CD 1193
+#define IDC_RSTART 1194
+#define IDC_ALLTYPES 1194
+#define IDC_FIRSTNAME 1195
+#define IDC_LASTNAME 1196
+#define IDC_AGE 1197
+#define IDC_COUNTRY 1198
+#define IDC_GENDER 1199
+#define IDC_EMAIL 1200
+#define IDC_EMAILUSE 1201
+#define IDC_BIFONT 1202
+#define IDC_BIFONT_ALT 1203
+#define IDC_EDIT1 1206
+#define IDC_EDIT2 1207
+#define IDC_EXT 1207
+#define IDC_REGKEY 1207
+#define IDC_COMBO1 1208
+#define IDC_EDIT3 1208
+#define IDC_TONAME 1208
+#define IDC_COMBO2 1209
+#define IDC_EDIT5 1209
+#define IDC_REGSTATUS 1209
+#define IDC_BUTTON2 1211
+#define IDC_ALLOW 1211
+#define IDC_SET_DEF_PROGRAM 1211
+#define IDC_NEWVERCHECK 1212
+#define IDC_BUTTON3 1212
+#define IDC_NEWVERCHK 1213
+#define IDC_NEWVERCHECK2 1213
+#define IDC_BUTTON_COPY 1213
+#define IDC_CLEARLANG 1214
+#define IDC_BUTTON_PASTE 1214
+#define IDC_NEWVERCHECK_RC 1214
+#define IDC_RECENT 1215
+#define IDC_BUTTON6 1215
+#define IDC_BUTTON_SAVEAS 1215
+#define IDC_URL_NEW 1216
+#define IDC_RADIO2 1217
+#define IDC_RADIO3 1218
+#define IDC_RADIO4 1219
+#define IDC_RADIO5 1220
+#define IDC_RADIO6 1221
+#define IDC_CHECK1 1222
+#define IDC_RADIO7 1223
+#define IDC_CHECK5 1223
+#define IDC_RADIO8 1224
+#define IDC_CHECK6 1224
+#define IDC_SLIDER1 1225
+#define IDC_SAFEMODEALWAYS 1225
+#define IDC_SLIDER2 1226
+#define IDC_SLIDER3 1227
+#define IDC_RRATE 1228
+#define IDC_RADIO9 1229
+#define IDC_PLUGINVERS 1229
+#define IDC_RADIO10 1230
+#define IDC_SPLB 1230
+#define IDC_RADIO11 1231
+#define IDC_CHECK2 1231
+#define IDC_RADIO12 1232
+#define IDC_CHECK3 1232
+#define IDC_RADIO13 1233
+#define IDC_CHECK4 1233
+#define IDC_24BIT 1233
+#define IDC_LIST1 1234
+#define IDC_EDIT4 1235
+#define IDC_TITLE 1237
+#define IDC_FILE 1238
+#define IDC_ALLOWMETRICS 1246
+#define IDC_TEXT 1247
+#define IDC_MYPLAY 1248
+#define IDC_NC 1249
+#define IDC_RUNWINAMP 1249
+#define IDC_REGTEXT 1250
+#define IDC_PREFS_SHUFFLE_MORPH_RATE 1251
+#define IDC_UNINST 1252
+#define IDC_PREFS_VIDEO_VSYNC 1253
+#define IDC_PREFS_VIDEO_ADJASP 1254
+#define IDC_PREFS_VIDEO_OVERLAYS 1255
+#define IDC_PREFS_VIDEO_UPDSIZE 1256
+#define IDC_PREFS_VIDEO_AUTOCLOSE 1257
+#define IDC_PREFS_VIDEO_NOSS 1258
+#define IDC_PREFS_VIDEO_OSD 1259
+#define IDC_SCREENSHAPE1 1260
+#define IDC_SCREENSHAPE2 1261
+#define IDC_PREFS_VIDEO_YV12 1262
+#define IDC_USE_SCREENSHAPE 1263
+#define IDC_PREFS_VIDEO_STOPCLOSE 1264
+#define IDC_PREFS_VIDEO_REMOVE_FS_ON_STOP 1265
+#define IDC_PREFS_VIDEO_AUTOOPEN 1266
+#define IDC_RENAME_SKIN 1267
+#define IDC_PREFS_VIDEO_ENABLE 1267
+#define IDC_DELETE_SKIN 1268
+#define IDC_PREFS_VIDEO_AUTO_FS_ON_START 1268
+#define IDC_UNINSTVIS 1269
+#define IDC_PREFS_VIDEO_HIDE_PREFS 1269
+#define IDC_UNINSTINPUT 1270
+#define IDC_UNINSTOUT 1271
+#define IDC_PROXY_ONLY_PORT_80 1272
+#define IDC_WEBLINK 1273
+#define IDC_KEY 1274
+#define IDC_WEBLINK2 1274
+#define IDC_REGISTER 1275
+#define IDC_WEBLINK3 1275
+#define IDC_PROGRESS1 1276
+#define IDC_WEBLINK4 1276
+#define IDC_PROGRESS2 1277
+#define IDC_ABORT 1278
+#define IDC_TAB1 1279
+#define IDC_PLUGINLABEL 1280
+#define IDR_RESERVED_GENFF_1 1281
+#define IDR_RESERVED_GENFF_2 1282
+#define IDR_RESERVED_GENFF_3 1283
+#define IDR_RESERVED_GENFF_4 1284
+#define IDR_RESERVED_GENFF_5 1285
+#define IDR_RESERVED_GENFF_6 1286
+#define IDC_WATEXT1 1287
+#define IDC_WATEXT2 1288
+#define IDC_CUSTOMFONT 1289
+#define IDC_NOCUSTOMFONT 1290
+#define IDC_STATIC_CUSTOMFONT 1291
+#define IDC_FRAME1 1292
+#define IDC_PLDIRECTION 1292
+#define IDC_ITEXT1 1293
+#define IDC_ASCII 1294
+#define IDC_STATIC1 1295
+#define IDC_STATIC2 1296
+#define IDC_RECYCLE 1297
+#define IDC_STATIC3 1297
+#define IDC_PREFS_VIDEO_CONTRAST 1298
+#define IDC_PREFS_VIDEO_BRIGHTNESS 1299
+#define IDC_STATIC4 1300
+#define IDC_DELETEM3U 1302
+#define IDC_NODELETE 1303
+#define IDC_PREFS_STATIONINFO_AUTOSHOW 1304
+#define IDC_PREFS_STATIONINFO_AUTOSIZE 1305
+#define IDC_PREFS_STATIONINFO_AUTOSHOW2 1306
+#define IDC_PREFS_STATIONINFO_AUTOHIDE 1306
+#define IDC_TITLELBL 1306
+#define IDC_WORKLBL 1307
+#define IDC_SURROUND 1308
+#define IDC_DITHER 1309
+#define IDC_WORKLBL4 1310
+#define IDC_PROGRESS3 1310
+#define IDC_REPLAY_GROUP 1310
+#define IDC_REPLAY_MODE 1311
+#define IDC_REPLAY_SOURCE 1312
+#define IDC_REPLAY_PREFERRED 1313
+#define IDC_STATIC_SOURCE 1314
+#define IDC_STATIC_MODE 1315
+#define IDC_USE_REPLAY 1316
+#define IDC_NON_REPLAYGAIN 1317
+#define IDC_NON_REPLAYGAIN_DB 1318
+#define IDC_STATIC_ADJ 1319
+#define IDC_ATF_INFO 1320
+#define IDC_RENAME_LNG_PACK 1321
+#define IDC_DELETE_LNG_PACK 1322
+#define IDC_SELECT_LNG_PACK 1323
+#define IDC_PRIORITY 1324
+#define IDC_VER_COMBO 1325
+#define IDC_ABOUT_SEARCH 1326
+#define IDC_FORMATINFO 1327
+#define IDC_ARTLIST 1328
+#define IDC_BUTTON_DOWNLOAD 1330
+#define IDC_REPLAYGAIN 1331
+#define IDC_COMBO_ARTTYPE 1332
+#define IDC_BUTTON_LOAD 1333
+#define IDC_BUTTON_PASTENEW 1334
+#define IDC_BUTTON_CHANGE 1335
+#define IDC_BUTTON_DELETE 1336
+#define IDC_STATIC_FRAME 1337
+#define IDC_ARTHOLDER 1338
+#define IDC_BPM 1339
+#define IDC_STATIC_TRACK 1340
+#define IDC_STATIC_DISC 1341
+#define IDC_STATIC_BPM 1342
+#define IDC_STATIC_TITLE 1343
+#define IDC_CHECK_DIRECTOR 1343
+#define IDC_STATIC_ARTIST 1344
+#define IDC_EDIT_DIRECTOR 1344
+#define IDC_STATIC_ALBUM 1345
+#define IDC_CHECK_PRODUCER 1345
+#define IDC_STATIC_ALBUM_ARTIST 1346
+#define IDC_EDIT_PRODUCER 1346
+#define IDC_STATIC_YEAR 1347
+#define IDC_CHECK_PODCAST 1347
+#define IDC_STATIC_GENRE 1348
+#define IDC_EDIT_PODCAST_CHANNEL 1348
+#define IDC_STATIC_COMMENT 1349
+#define IDC_STATIC_STATION 1349
+#define IDC_CHECK_PODCAST_CHANNEL 1349
+#define IDC_STATIC_COMPOSER 1350
+#define IDC_STATIC_PUBLISHER 1351
+#define IDC_IMAGE 1354
+#define IDC_COMBO_RATING 1354
+#define IDC_IMGTEXT 1355
+#define IDC_PLACEHOLDER 1356
+#define IDC_SELECT 1357
+#define IDC_AUTOTAG 1358
+#define IDC_MOUSE_SCROLL_DOUBLE_LINES 1359
+#define IDC_PLSCROLL 1360
+#define IDC_SHUFFLE_HELP 1361
+#define IDC_LANG_ID_STR 1362
+#define IDC_GN_FILEID 1363
+#define IDC_GN_EXTDATA 1364
+#define IDC_EQ 1365
+#define IDC_FREQ_BANDS 1366
+#define IDC_STATIC_EQ 1367
+#define IDC_STATIC_FREQ 1368
+#define IDC_LIMITER 1369
+#define IDB_EQMAIN_ISO 1370
+#define IDC_EQ_RESTART_TEXT 1370
+#define IDC_LANG_RESTART_TEXT 1371
+#define IDR_ACCELERATOR_EQ 1371
+#define IDC_SEARCHAGAIN 1372
+#define IDR_ACCELERATOR_PL 1372
+#define IDC_SEARCHREFINE_ARTIST 1373
+#define IDR_ACCELERATOR_MAIN 1373
+#define IDC_SEARCHREFINE_ALBUM 1374
+#define IDR_ACCELERATOR_GLOBAL 1374
+#define IDC_LANG_INFO_STR 1374
+#define IDC_SEARCHREFINE_YEAR 1375
+#define IDC_SECURITY_DESCRIPTION 1375
+#define IDC_ALLOW_ALWAYS 1376
+#define IDD_JSAPI2_AUTHORIZATION2 1376
+#define IDC_DENY 1377
+#define IDB_PNG1 1377
+#define IDB_OSD 1377
+#define IDC_TRUST_CHECK 1378
+#define IDD_DIALOG1 1378
+#define IDD_ABOUT_TRANSLATION 1378
+#define IDC_JSAPI2_ALL 1379
+#define IDC_JSAPI2_THIS 1380
+#define IDC_JSAPI2_ONCE 1381
+#define IDC_HELPTEXT 1383
+#define IDC_BUTTON_ALLOW 1384
+#define IDC_BUTTON_DENY 1385
+#define IDC_MESSAGEICON 1386
+#define IDC_MESSAGE 1387
+#define IDC_APPLYTOALL 1388
+#define IDI_TBICON1 1388
+#define IDC_SEPARATOR 1389
+#define IDI_TBICON2 1389
+#define IDC_REPLAYGAIN_PREAMP 1390
+#define IDI_TBICON3 1390
+#define IDC_REPLAYGAIN_PREAMP_DB 1391
+#define IDI_TBICON4 1391
+#define IDC_REPLAY_ADJ 1392
+#define IDI_ICON5 1392
+#define IDI_TBICON5 1392
+#define IDC_AUTHOR_HOMEPAGE 1393
+#define IDD_WIN8_FTYPES 1394
+#define IDC_AUTHOR_HOMEPAGE2 1394
+#define IDC_REGNAME 1394
+#define IDC_REGGROUP1 1395
+#define IDD_SILENCE_DETECT 1395
+#define IDD_CMDLINE 1396
+#define IDC_STATIC8 1396
+#define IDC_STATIC7 1397
+#define IDD_PREFS_FAIL 1397
+#define IDC_STATIC5 1398
+#define IDR_ATF_HTML 1398
+#define IDC_REGGROUP2 1399
+#define IDD_FILEINFO_STREAMDATA 1399
+#define IDC_STATIC10 1400
+#define IDC_STATIC9 1401
+#define IDC_RGAS 1402
+#define IDC_RGC 1403
+#define IDC_RELEASED 1404
+#define IDC_SHOW_LNG_PACK 1405
+#define IDC_USE_SILENCE_DETECT 1406
+#define IDC_CMDLINE 1407
+#define IDC_VIDEO_GROUP1 1412
+#define IDC_VIDEO_GROUP2 1413
+#define IDC_VIDEO_GROUP3 1414
+#define IDC_VIDEO_RESTART 1415
+#define IDC_STATIC_URL 1417
+#define IDC_EXTRA_METADATA 1418
+#define IDC_STATIC_PLAY_URL 1419
+#define IDC_PREFS_VIDEO_LOGO 1420
+#define IDC_SKIN_INSTALL_PROMPT 1421
+#define IDC_LANG_INSTALL_PROMPT 1422
+#define IDS_P_O_RECYCLE 32768
+#define WINAMP_FILE_QUIT 40001
+#define WINAMP_OPTIONS_PREFS 40012
+#define WINAMP_OPTIONS_AOT 40019
+#define WINAMP_FILE_REPEAT 40022
+#define WINAMP_FILE_SHUFFLE 40023
+#define WINAMP_HIGH_PRIORITY 40025
+#define WINAMP_FILE_PLAY 40029
+#define WINAMP_OPTIONS_EQ 40036
+#define WINAMP_OPTIONS_ELAPSED 40037
+#define WINAMP_OPTIONS_REMAINING 40038
+#define WINAMP_OPTIONS_PLEDIT 40040
+#define WINAMP_HELP_ABOUT 40041
+#define WINAMP_MAINMENU 40043
+#define WINAMP_BUTTON1 40044
+#define WINAMP_BUTTON2 40045
+#define WINAMP_BUTTON3 40046
+#define WINAMP_BUTTON4 40047
+#define WINAMP_BUTTON5 40048
+#define WINAMP_VOLUMEUP 40058
+#define WINAMP_VOLUMEDOWN 40059
+#define WINAMP_FFWD5S 40060
+#define WINAMP_REW5S 40061
+#define WINAMP_NEXT_WINDOW 40063
+#define WINAMP_OPTIONS_WINDOWSHADE 40064
+#define WINAMP_OPTIONS_WINDOWSHADE_GLOBAL 40065
+#define WINAMP_BROWSER_ID 40113
+#define WINAMP_BUTTON1_SHIFT 40144
+#define WINAMP_BUTTON2_SHIFT 40145
+#define WINAMP_BUTTON3_SHIFT 40146
+#define WINAMP_BUTTON4_SHIFT 40147
+#define WINAMP_BUTTON5_SHIFT 40148
+#define WINAMP_BUTTON1_CTRL 40154
+#define WINAMP_BUTTON2_CTRL 40155
+#define WINAMP_BUTTON3_CTRL 40156
+#define WINAMP_BUTTON4_CTRL 40157
+#define WINAMP_BUTTON5_CTRL 40158
+#define WINAMP_OPTIONS_DSIZE 40165
+#define IDC_SORT_FILENAME 40166
+#define IDC_SORT_FILETITLE 40167
+#define IDC_SORT_ENTIREFILENAME 40168
+#define IDC_SELECTALL 40169
+#define IDC_SELECTNONE 40170
+#define IDC_SELECTINV 40171
+#define IDM_EQ_LOADPRE 40172
+#define IDM_EQ_LOADMP3 40173
+#define IDM_EQ_LOADDEFAULT 40174
+#define IDM_EQ_SAVEPRE 40175
+#define IDM_EQ_SAVEMP3 40176
+#define IDM_EQ_SAVEDEFAULT 40177
+#define IDM_EQ_DELPRE 40178
+#define IDM_EQ_DELMP3 40180
+#define IDC_PLAYLIST_PLAY 40184
+#define WINAMP_FILE_LOC 40185
+#define WINAMP_OPTIONS_EASYMOVE 40186
+#define WINAMP_FILE_DIR 40187
+#define WINAMP_EDIT_ID3 40188
+#define WINAMP_TOGGLE_AUTOSCROLL 40189
+#define WINAMP_VISSETUP 40190
+#define WINAMP_PLGSETUP 40191
+#define WINAMP_VISPLUGIN 40192
+#define WINAMP_JUMP 40193
+#define WINAMP_JUMPFILE 40194
+#define WINAMP_JUMP10FWD 40195
+#define WINAMP_JUMP10BACK 40197
+#define WINAMP_PREVSONG 40198
+#define WINAMP_OPTIONS_EXTRAHQ 40200
+#define ID_PE_NEW 40201
+#define ID_PE_OPEN 40202
+#define ID_PE_SAVE 40203
+#define ID_PE_SAVEAS 40204
+#define ID_PE_SELECTALL 40205
+#define ID_PE_INVERT 40206
+#define ID_PE_NONE 40207
+#define ID_PE_ID3 40208
+#define ID_PE_S_TITLE 40209
+#define ID_PE_S_FILENAME 40210
+#define ID_PE_S_PATH 40211
+#define ID_PE_S_RANDOM 40212
+#define ID_PE_S_REV 40213
+#define ID_PE_CLEAR 40214
+#define ID_PE_MOVEUP 40215
+#define ID_PE_MOVEDOWN 40216
+#define WINAMP_SELSKIN 40219
+#define WINAMP_VISCONF 40221
+#define ID_PE_NONEXIST 40222
+#define ID_PE_DELETEFROMDISK 40223
+#define ID_PE_CLOSE 40224
+#define WINAMP_VIS_SETOSC 40226
+#define WINAMP_VIS_SETANA 40227
+#define WINAMP_VIS_SETOFF 40228
+#define WINAMP_VIS_DOTSCOPE 40229
+#define WINAMP_VIS_LINESCOPE 40230
+#define WINAMP_VIS_SOLIDSCOPE 40231
+#define WINAMP_VIS_NORMANA 40233
+#define WINAMP_VIS_FIREANA 40234
+#define WINAMP_VIS_LINEANA 40235
+#define WINAMP_VIS_NORMVU 40236
+#define WINAMP_VIS_SMOOTHVU 40237
+#define WINAMP_VIS_FULLREF 40238
+#define WINAMP_VIS_FULLREF2 40239
+#define WINAMP_VIS_FULLREF3 40240
+#define WINAMP_VIS_FULLREF4 40241
+#define WINAMP_OPTIONS_TOGTIME 40242
+#define EQ_ENABLE 40244
+#define EQ_AUTO 40245
+#define EQ_PRESETS 40246
+#define WINAMP_VIS_FALLOFF0 40247
+#define WINAMP_VIS_FALLOFF1 40248
+#define WINAMP_VIS_FALLOFF2 40249
+#define WINAMP_VIS_FALLOFF3 40250
+#define WINAMP_VIS_FALLOFF4 40251
+#define WINAMP_VIS_PEAKS 40252
+#define ID_LOAD_EQF 40253
+#define ID_SAVE_EQF 40254
+#define ID_PE_ENTRY 40255
+#define ID_PE_SCROLLUP 40256
+#define ID_PE_SCROLLDOWN 40257
+#define WINAMP_MAIN_WINDOW 40258
+#define WINAMP_VIS_PFALLOFF0 40259
+#define WINAMP_VIS_PFALLOFF1 40260
+#define WINAMP_VIS_PFALLOFF2 40261
+#define WINAMP_VIS_PFALLOFF3 40262
+#define WINAMP_VIS_PFALLOFF4 40263
+#define ID_PE_TOP 40264
+#define ID_PE_BOTTOM 40265
+#define WINAMP_OPTIONS_WINDOWSHADE_PL 40266
+#define EQ_INC1 40267
+#define EQ_INC2 40268
+#define EQ_INC3 40269
+#define EQ_INC4 40270
+#define EQ_INC5 40271
+#define EQ_INC6 40272
+#define EQ_INC7 40273
+#define EQ_INC8 40274
+#define EQ_INC9 40275
+#define EQ_INC10 40276
+#define EQ_INCPRE 40277
+#define EQ_DECPRE 40278
+#define EQ_DEC1 40279
+#define EQ_DEC2 40280
+#define EQ_DEC3 40281
+#define EQ_DEC4 40282
+#define EQ_DEC5 40283
+#define EQ_DEC6 40284
+#define EQ_DEC7 40285
+#define EQ_DEC8 40286
+#define EQ_DEC9 40287
+#define EQ_DEC10 40288
+#define ID_PE_SCUP 40289
+#define ID_PE_SCDOWN 40290
+#define WINAMP_REFRESHSKIN 40291
+#define ID_PE_PRINT 40292
+#define ID_PE_EXTINFO 40293
+#define WINAMP_PLAYLIST_ADVANCE 40294
+#define WINAMP_VIS_LIN 40295
+#define WINAMP_VIS_BAR 40296
+#define WINAMP_OPTIONS_MINIBROWSER 40298
+#define MB_FWD 40299
+#define MB_BACK 40300
+#define MB_RELOAD 40301
+#define MB_OPENMENU 40302
+#define MB_OPENLOC 40303
+#define WINAMP_NEW_INSTANCE 40305
+#define MB_UPDATE 40309
+#define WINAMP_OPTIONS_WINDOWSHADE_EQ 40310
+#define EQ_PANLEFT 40313
+#define EQ_PANRIGHT 40314
+#define WINAMP_GETMORESKINS 40316
+#define WINAMP_VIS_OPTIONS 40317
+#define WINAMP_PE_SEARCH 40318
+#define ID_PE_BOOKMARK 40319
+#define WINAMP_EDIT_BOOKMARKS 40320
+#define WINAMP_MAKECURBOOKMARK 40321
+#define ID_MAIN_PLAY_BOOKMARK_NONE 40322
+#define ID_MAIN_PLAY_AUDIOCD 40323
+#define ID_MAIN_PLAY_AUDIOCD2 40324
+#define ID_MAIN_PLAY_AUDIOCD3 40325
+#define ID_MAIN_PLAY_AUDIOCD4 40326
+#define ID_MAIN_PLAY_AUDIOCD_SEP 40327
+#define WINAMP_OPTIONS_VIDEO 40328
+#define ID_VIDEOWND_ZOOMFULLSCREEN 40329
+#define ID_VIDEOWND_ZOOM100 40330
+#define ID_VIDEOWND_ZOOM200 40331
+#define ID_VIDEOWND_ZOOM50 40332
+#define ID_VIDEOWND_VIDEOOPTIONS 40333
+#define WINAMP_MINIMIZE 40334
+#define ID_PE_FONTBIGGER 40335
+#define ID_PE_FONTSMALLER 40336
+#define WINAMP_VIDEO_TOGGLE_FS 40337
+#define WINAMP_VIDEO_TVBUTTON 40338
+#define WINAMP_LIGHTNING_CLICK 40339
+#define ID_FILE_ADDTOLIBRARY 40344
+#define ID_HELP_HELPTOPICS 40347
+#define ID_HELP_GETTINGSTARTED 40348
+#define ID_HELP_WINAMPFORUMS 40349
+#define ID_PLAY_VOLUMEUP 40351
+#define ID_PLAY_VOLUMEDOWN 40352
+#define ID_PEFILE_OPENPLAYLISTFROMLIBRARY_NOPLAYLISTSINLIBRARY 40355
+#define ID_PEFILE_ADDFROMLIBRARY 40356
+#define ID_PEFILE_CLOSEPLAYLISTEDITOR 40357
+#define ID_PEPLAYLIST_PLAYLISTPREFERENCES 40358
+#define ID_MLFILE_NEWPLAYLIST 40359
+#define ID_MLFILE_LOADPLAYLIST 40360
+#define ID_MLFILE_SAVEPLAYLIST 40361
+#define ID_MLFILE_ADDMEDIATOLIBRARY 40362
+#define ID_MLFILE_CLOSEMEDIALIBRARY 40363
+#define ID_MLVIEW_NOWPLAYING 40364
+#define ID_MLVIEW_LOCALMEDIA_ALLMEDIA 40366
+#define ID_MLVIEW_LOCALMEDIA_AUDIO 40367
+#define ID_MLVIEW_LOCALMEDIA_VIDEO 40368
+#define ID_MLVIEW_PLAYLISTS_NOPLAYLISTINLIBRARY 40369
+#define ID_MLVIEW_INTERNETRADIO 40370
+#define ID_MLVIEW_INTERNETTV 40371
+#define ID_MLVIEW_LIBRARYPREFERENCES 40372
+#define ID_MLVIEW_DEVICES_NOAVAILABLEDEVICE 40373
+#define ID_MLFILE_IMPORTCURRENTPLAYLIST 40374
+#define ID_MLVIEW_MEDIA 40376
+#define ID_MLVIEW_PLAYLISTS 40377
+#define ID_MLVIEW_MEDIA_ALLMEDIA 40377
+#define ID_MLVIEW_DEVICES 40378
+#define ID_FILE_SHOWLIBRARY 40379
+#define ID_FILE_CLOSELIBRARY 40380
+#define ID_POST_PLAY_PLAYLIST 40381
+#define ID_VIS_NEXT 40382
+#define ID_VIS_PREV 40383
+#define ID_VIS_RANDOM 40384
+#define ID_MANAGEPLAYLISTS 40385
+#define ID_PREFS_SKIN_SWITCHTOSKIN 40386
+#define ID_PREFS_SKIN_DELETESKIN 40387
+#define ID_PREFS_SKIN_RENAMESKIN 40388
+#define ID_VIS_FS 40389
+#define ID_VIS_CFG 40390
+#define ID_VIS_MENU 40391
+#define ID_VIS_SET_FS_FLAG 40392
+#define ID_PE_SHOWPLAYING 40393
+#define WINAMP_FILE_MANUALPLADVANCE 40395
+#define ID_RATING5 40396
+#define ID_RATING4 40397
+#define ID_RATING3 40398
+#define ID_RATING2 40399
+#define ID_RATING1 40400
+#define ID_RATING0 40401
+#define ID_PL_RATING5 40402
+#define ID_PL_RATING4 40403
+#define ID_PL_RATING3 40404
+#define ID_PL_RATING2 40405
+#define ID_ACCELERATOR40405 40405
+#define ID_PL_RATING1 40406
+#define ID_PL_RATING0 40407
+#define ID_VID_AUDIO0 40408
+#define ID_VID_AUDIO1 40409
+#define ID_VID_AUDIO2 40410
+#define ID_VID_AUDIO3 40411
+#define ID_VID_AUDIO4 40412
+#define ID_VID_AUDIO5 40413
+#define ID_VID_AUDIO6 40414
+#define ID_VID_AUDIO7 40415
+#define ID_VID_AUDIO8 40416
+#define ID_VID_AUDIO9 40417
+#define ID_VID_AUDIO10 40418
+#define ID_VID_AUDIO11 40419
+#define ID_VID_AUDIO12 40420
+#define ID_VID_AUDIO13 40421
+#define ID_VID_AUDIO14 40422
+#define ID_VID_AUDIO15 40423
+#define ID_VID_VIDEO0 40424
+#define ID_VID_VIDEO1 40425
+#define ID_VID_VIDEO2 40426
+#define ID_VID_VIDEO3 40427
+#define ID_VID_VIDEO4 40428
+#define ID_VID_VIDEO5 40429
+#define ID_VID_VIDEO6 40430
+#define ID_VID_VIDEO7 40431
+#define ID_VID_VIDEO8 40432
+#define ID_VID_VIDEO9 40433
+#define ID_VID_VIDEO10 40434
+#define ID_VID_VIDEO11 40435
+#define ID_VID_VIDEO12 40436
+#define ID_VID_VIDEO13 40437
+#define ID_VID_VIDEO14 40438
+#define ID_VID_VIDEO15 40439
+#define ID_SONGTITLE_SEND 40446
+#define WINAMP_TOGGLE_LIBRARY 40451
+#define ID_Menu 40454
+#define ID_PREFS_LANG 40457
+#define ID_LANG_SWITCHTOLANGUAGEPACK 40458
+#define ID_LANG_RENAMELANGUAGEPACK 40459
+#define ID_LANG_DELETELANGUAGEPACK 40460
+#define ID_HELP_FEEDBACK 40464
+#define ID_VIDEOWND_VERTICALLYFLIP 40465
+#define ID_FILE_ADDCURRENTPLAYLISTTOLIBRARY 40466
+#define ID_PE_FFOD 40468
+#define ID_PE_FONTRESET 40469
+#define ID_PE_EDIT_SEL 40470
+#define IDS_LOCALIZED_HOMEPAGE 65531
+#define IDS_AUTHOR_HOMEPAGE2 65532
+#define IDS_AUTHOR_HOMEPAGE 65533
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_3D_CONTROLS 1
+#define _APS_NEXT_RESOURCE_VALUE 537
+#define _APS_NEXT_COMMAND_VALUE 40471
+#define _APS_NEXT_CONTROL_VALUE 1423
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Winamp/resource.hm b/Src/Winamp/resource.hm
new file mode 100644
index 00000000..1925e12a
--- /dev/null
+++ b/Src/Winamp/resource.hm
@@ -0,0 +1,4 @@
+// Microsoft Developer Studio generated Help ID include file.
+// Used by Winamp.rc
+//
+#define HIDC_CLUTTERBAR 0x81020471 // IDD_CLASSIC_UI
diff --git a/Src/Winamp/resource/.gitattributes b/Src/Winamp/resource/.gitattributes
new file mode 100644
index 00000000..78d2e402
--- /dev/null
+++ b/Src/Winamp/resource/.gitattributes
@@ -0,0 +1 @@
+TIPS.TXT eol=crlf
diff --git a/Src/Winamp/resource/BALANCE.BMP b/Src/Winamp/resource/BALANCE.BMP
new file mode 100644
index 00000000..fa03724d
--- /dev/null
+++ b/Src/Winamp/resource/BALANCE.BMP
Binary files differ
diff --git a/Src/Winamp/resource/CBUTTONS.BMP b/Src/Winamp/resource/CBUTTONS.BMP
new file mode 100644
index 00000000..09ec8b22
--- /dev/null
+++ b/Src/Winamp/resource/CBUTTONS.BMP
Binary files differ
diff --git a/Src/Winamp/resource/CUR00001.CUR b/Src/Winamp/resource/CUR00001.CUR
new file mode 100644
index 00000000..e1c64ef9
--- /dev/null
+++ b/Src/Winamp/resource/CUR00001.CUR
Binary files differ
diff --git a/Src/Winamp/resource/DANGER.CUR b/Src/Winamp/resource/DANGER.CUR
new file mode 100644
index 00000000..5405ec01
--- /dev/null
+++ b/Src/Winamp/resource/DANGER.CUR
Binary files differ
diff --git a/Src/Winamp/resource/DANGER1.CUR b/Src/Winamp/resource/DANGER1.CUR
new file mode 100644
index 00000000..926f057d
--- /dev/null
+++ b/Src/Winamp/resource/DANGER1.CUR
Binary files differ
diff --git a/Src/Winamp/resource/Eqmain.bmp b/Src/Winamp/resource/Eqmain.bmp
new file mode 100644
index 00000000..45ac332a
--- /dev/null
+++ b/Src/Winamp/resource/Eqmain.bmp
Binary files differ
diff --git a/Src/Winamp/resource/Eqmain_ISO.bmp b/Src/Winamp/resource/Eqmain_ISO.bmp
new file mode 100644
index 00000000..610f1df8
--- /dev/null
+++ b/Src/Winamp/resource/Eqmain_ISO.bmp
Binary files differ
diff --git a/Src/Winamp/resource/ICON1.ICO b/Src/Winamp/resource/ICON1.ICO
new file mode 100644
index 00000000..22d7fc70
--- /dev/null
+++ b/Src/Winamp/resource/ICON1.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON10.ICO b/Src/Winamp/resource/ICON10.ICO
new file mode 100644
index 00000000..18c43755
--- /dev/null
+++ b/Src/Winamp/resource/ICON10.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON11.ICO b/Src/Winamp/resource/ICON11.ICO
new file mode 100644
index 00000000..bed8f2a6
--- /dev/null
+++ b/Src/Winamp/resource/ICON11.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON12.ICO b/Src/Winamp/resource/ICON12.ICO
new file mode 100644
index 00000000..c76d245a
--- /dev/null
+++ b/Src/Winamp/resource/ICON12.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON13.ICO b/Src/Winamp/resource/ICON13.ICO
new file mode 100644
index 00000000..ed104d4f
--- /dev/null
+++ b/Src/Winamp/resource/ICON13.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON2.ICO b/Src/Winamp/resource/ICON2.ICO
new file mode 100644
index 00000000..e405f5b5
--- /dev/null
+++ b/Src/Winamp/resource/ICON2.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON3.ICO b/Src/Winamp/resource/ICON3.ICO
new file mode 100644
index 00000000..fbd49586
--- /dev/null
+++ b/Src/Winamp/resource/ICON3.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON6.ICO b/Src/Winamp/resource/ICON6.ICO
new file mode 100644
index 00000000..f587327e
--- /dev/null
+++ b/Src/Winamp/resource/ICON6.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON7.ICO b/Src/Winamp/resource/ICON7.ICO
new file mode 100644
index 00000000..5aecf2a3
--- /dev/null
+++ b/Src/Winamp/resource/ICON7.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON8.ICO b/Src/Winamp/resource/ICON8.ICO
new file mode 100644
index 00000000..01771505
--- /dev/null
+++ b/Src/Winamp/resource/ICON8.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICON9.ICO b/Src/Winamp/resource/ICON9.ICO
new file mode 100644
index 00000000..77af7240
--- /dev/null
+++ b/Src/Winamp/resource/ICON9.ICO
Binary files differ
diff --git a/Src/Winamp/resource/ICONS.GIF b/Src/Winamp/resource/ICONS.GIF
new file mode 100644
index 00000000..9a5e4926
--- /dev/null
+++ b/Src/Winamp/resource/ICONS.GIF
Binary files differ
diff --git a/Src/Winamp/resource/LRSCROLL.CUR b/Src/Winamp/resource/LRSCROLL.CUR
new file mode 100644
index 00000000..07a7161f
--- /dev/null
+++ b/Src/Winamp/resource/LRSCROLL.CUR
Binary files differ
diff --git a/Src/Winamp/resource/MAIN.BMP b/Src/Winamp/resource/MAIN.BMP
new file mode 100644
index 00000000..a4ba9a3d
--- /dev/null
+++ b/Src/Winamp/resource/MAIN.BMP
Binary files differ
diff --git a/Src/Winamp/resource/MONOSTER.BMP b/Src/Winamp/resource/MONOSTER.BMP
new file mode 100644
index 00000000..ba0bf8f5
--- /dev/null
+++ b/Src/Winamp/resource/MONOSTER.BMP
Binary files differ
diff --git a/Src/Winamp/resource/MOVE.CUR b/Src/Winamp/resource/MOVE.CUR
new file mode 100644
index 00000000..8b73d0ed
--- /dev/null
+++ b/Src/Winamp/resource/MOVE.CUR
Binary files differ
diff --git a/Src/Winamp/resource/Mb.bmp b/Src/Winamp/resource/Mb.bmp
new file mode 100644
index 00000000..596c56a0
--- /dev/null
+++ b/Src/Winamp/resource/Mb.bmp
Binary files differ
diff --git a/Src/Winamp/resource/OSD-Sprite-Controls.png b/Src/Winamp/resource/OSD-Sprite-Controls.png
new file mode 100644
index 00000000..57c74244
--- /dev/null
+++ b/Src/Winamp/resource/OSD-Sprite-Controls.png
Binary files differ
diff --git a/Src/Winamp/resource/PLAYPAUS.BMP b/Src/Winamp/resource/PLAYPAUS.BMP
new file mode 100644
index 00000000..e8b13c51
--- /dev/null
+++ b/Src/Winamp/resource/PLAYPAUS.BMP
Binary files differ
diff --git a/Src/Winamp/resource/POSBAR.BMP b/Src/Winamp/resource/POSBAR.BMP
new file mode 100644
index 00000000..be86278a
--- /dev/null
+++ b/Src/Winamp/resource/POSBAR.BMP
Binary files differ
diff --git a/Src/Winamp/resource/Pledit.bmp b/Src/Winamp/resource/Pledit.bmp
new file mode 100644
index 00000000..d335186f
--- /dev/null
+++ b/Src/Winamp/resource/Pledit.bmp
Binary files differ
diff --git a/Src/Winamp/resource/RESIZE.CUR b/Src/Winamp/resource/RESIZE.CUR
new file mode 100644
index 00000000..107a4636
--- /dev/null
+++ b/Src/Winamp/resource/RESIZE.CUR
Binary files differ
diff --git a/Src/Winamp/resource/SHUFREP.BMP b/Src/Winamp/resource/SHUFREP.BMP
new file mode 100644
index 00000000..7c6d9bce
--- /dev/null
+++ b/Src/Winamp/resource/SHUFREP.BMP
Binary files differ
diff --git a/Src/Winamp/resource/SPEC.BMP b/Src/Winamp/resource/SPEC.BMP
new file mode 100644
index 00000000..b44f231b
--- /dev/null
+++ b/Src/Winamp/resource/SPEC.BMP
Binary files differ
diff --git a/Src/Winamp/resource/TBICON1.ico b/Src/Winamp/resource/TBICON1.ico
new file mode 100644
index 00000000..4bffe8f2
--- /dev/null
+++ b/Src/Winamp/resource/TBICON1.ico
Binary files differ
diff --git a/Src/Winamp/resource/TBICON2.ico b/Src/Winamp/resource/TBICON2.ico
new file mode 100644
index 00000000..185c191f
--- /dev/null
+++ b/Src/Winamp/resource/TBICON2.ico
Binary files differ
diff --git a/Src/Winamp/resource/TBICON3.ico b/Src/Winamp/resource/TBICON3.ico
new file mode 100644
index 00000000..461373fe
--- /dev/null
+++ b/Src/Winamp/resource/TBICON3.ico
Binary files differ
diff --git a/Src/Winamp/resource/TBICON4.ico b/Src/Winamp/resource/TBICON4.ico
new file mode 100644
index 00000000..ea936032
--- /dev/null
+++ b/Src/Winamp/resource/TBICON4.ico
Binary files differ
diff --git a/Src/Winamp/resource/TBICON5.ico b/Src/Winamp/resource/TBICON5.ico
new file mode 100644
index 00000000..4d2b0877
--- /dev/null
+++ b/Src/Winamp/resource/TBICON5.ico
Binary files differ
diff --git a/Src/Winamp/resource/TIPS.TXT b/Src/Winamp/resource/TIPS.TXT
new file mode 100644
index 00000000..8af9f5ac
--- /dev/null
+++ b/Src/Winamp/resource/TIPS.TXT
@@ -0,0 +1,140 @@
+Note that these keyboard shortcuts are a good starting point, but this list
+is far from complete. :)
+
+******* Keyboard Shortcuts (these can be used in most Winamp windows) *******
+
+Key Action
+-----------------------------------------------------------------------------
+F1 Open Help
+Ctrl+F1 About Box
+Ctrl+A Toggle Always on Top (N/A in playlist editor and media library)
+Ctrl+Alt+A Toggle always on top (playlist editor)
+Ctrl+W Toggle Windowshade mode (main window, unless in playlist editor)
+Ctrl+D Toggle Doublesize Mode
+Ctrl+E Toggle Easymove (only applicable in classic skins)
+Ctrl+T Toggle Time Display Mode
+Alt+W Toggle Main Window
+Alt+E Toggle Playlist Editor
+Alt+G Toggle Graphical Equalizer
+Alt+V Toggle Video Window
+Alt+L Toggle Media Library
+Ctrl+Tab Cycle through different Winamp windows
+Alt+S Go to Skin selection
+Ctrl+P Go to Preferences
+Alt+F Open Main Menu
+Alt+K Configure current visualization plug-in
+Ctrl+Sh+K Start/stop current visualization plug-In
+Ctrl+K Open visualization plug-in section of preferences
+Ctrl+J Jump to time in current track
+J or Keypad . Open jump-to-file box
+Ctrl+Alt+N Spawn new Winamp instance
+Ctrl+Alt+B Add current to bookmarks (requires ML and ml_bookmarks)
+Alt+M Minimize Winamp
+Ctrl+H Show recently played files/streams (History :)
+
+
+******* Main Window Keyboard Shortcuts *******
+
+Key Action
+-----------------------------------------------------------------------------
+(options/toggles)
+R Toggle Repeat
+S Toggle Shuffle
+
+Alt+3 Current file info box/tag editor
+
+(playback controls)
+Z Previous Track
+X Play/Restart/Unpause
+C Pause/Unpause
+V Stop
+Shift+V Stop with Fadeout
+Ctrl+V Stop after current track
+B Next Track
+L Open/Play File
+Ctrl+L Open/Play location
+Shift+L Open/Play Directory
+
+Left Arrow Rewind 5 seconds
+Right Arrow Fast-forward 5 seconds
+Up Arrow Turn Volume Up
+Down Arrow Turn Volume Down
+
+Keypad 1 Jump Ten Songs Back
+Keypad 6 Next Track
+Keypad 5 Play/Restart/Unpause
+Keypad 4 Previous Track
+Keypad 3 Jump Ten Songs Forward
+Keypad 7 Rewind 5 seconds
+Keypad 9 Fast-forward 5 seconds
+Keypad 8 Turn Volume Up
+Keypad 2 Turn Volume Down
+Keypad 0 Open/Play File
+Ctrl+Keypad 0 Open/Play location
+Insert Open/Play Directory
+
+
+******* Playlist Window Keyboard Shortcuts *******
+
+Key Action
+-----------------------------------------------------------------------------
+R Toggle Repeat
+S Toggle Shuffle
+Ctrl+Z Go to start of list
+Ctrl+B Go to end of list
+Alt+I Add current to bookmarks (requires ML and ml_bookmarks)
+
+(file io)
+L Add File
+Ctrl+L Add Location
+Shift+L Add Directory
+Ctrl+N New (Clear) Playlist
+Ctrl+O Open (Load) Playlist
+Ctrl+S Save Playlist
+Alt+3 View/Edit Track Info for selected track(s)
+Ctrl+E Edit Selected Track Filename(s)
+Ctrl+Keypad 0 Add Location
+Insert Add Directory
+
+(playlist manipulation)
+Ctrl+A Select All
+Ctrl+I Invert Selection
+Delete Remove Selected Files from Playlist
+Ctrl+Delete Crop Playlist
+Ctrl+Sh+Del Clear Playlist (same as Ctrl+N)
+
+Alt+Down Arrow Move Selected Files Down
+Alt+Up Arrow Move Selected Files Up
+
+Down Arrow Move Cursor Down
+Up Arrow Move Cursor Up
+Enter Play Selected File
+End Jump to End of List
+Home Jump to Start of List
+Page Up Move up by a fifth of a page
+Page Down Move down by a fifth of a page
+
+Alt+Delete Remove missing files from playlist
+
+(playlist sorting)
+Ctrl+Sh+1 Sort Playlist by Title
+Ctrl+Sh+2 Sort Playlist by File Name
+Ctrl+Sh+3 Sort Playlist by File Path and Name
+Ctrl+R Reverse Playlist
+Ctrl+Sh+R Randomize Playlist
+
+Most main window playback controls also work in the playlist editor.
+
+
+******* Equalizer Keyboard Shortcuts (Classic skins only) *******
+
+Key Action
+-----------------------------------------------------------------------------
+1 - 0 Increase EQ bands 1-10
+Q - P Decrease EQ bands 1-10
+` Increase EQ Preamp
+TAB Decrease EQ Preamp
+N Toggle EQ Enabled
+A Toggle EQ Auto-Loading
+S Open Presets Menu
+Ctrl+Alt+S Load Preset \ No newline at end of file
diff --git a/Src/Winamp/resource/WinampIcon.ico b/Src/Winamp/resource/WinampIcon.ico
new file mode 100644
index 00000000..596f578a
--- /dev/null
+++ b/Src/Winamp/resource/WinampIcon.ico
Binary files differ
diff --git a/Src/Winamp/resource/ZIPICON.ICO b/Src/Winamp/resource/ZIPICON.ICO
new file mode 100644
index 00000000..16d23925
--- /dev/null
+++ b/Src/Winamp/resource/ZIPICON.ICO
Binary files differ
diff --git a/Src/Winamp/resource/atf.htm b/Src/Winamp/resource/atf.htm
new file mode 100644
index 00000000..2bfa5720
--- /dev/null
+++ b/Src/Winamp/resource/atf.htm
@@ -0,0 +1,1097 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Winamp - Advanced Title Formatting (ATF) Documentation</title>
+<meta name="generator" content="Notepad++" />
+<meta name="date" content="2007-04-27" />
+<meta name="keywords" content="Advanced Title Formatting, Winamp, ATF" />
+<style type="text/css">
+<!--
+DIV.clearer {CLEAR: both; LINE-HEIGHT: 0; HEIGHT: 0px}
+DIV.no {PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px}
+EM.u {FONT-STYLE: normal; TEXT-DECORATION: underline}
+p.atf {TEXT-ALIGN: left; padding: 0em; FONT-SIZE: 100%; FONT-WEIGHT: normal; FONT-STYLE: normal; WHITE-SPACE: nowrap }
+DIV.atf .header {PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; MARGIN-TOP: 10px; MARGIN-BOTTOM: 0px;}
+DIV.atf .pagename {FONT-WEIGHT: bolder; FONT-SIZE: 200%; FLOAT: left; VERTICAL-ALIGN: middle; COLOR: #dee7ec; TEXT-ALIGN: left; border: solid 2px #dee7ec; PADDING-RIGHT: 5px; PADDING-LEFT: 5px; PADDING-BOTTOM: 4px; PADDING-TOP: 1px; MARGIN-LEFT: 10px; MARGIN-TOP: 0px; MARGIN-RIGHT: 0px; MARGIN-BOTTOM: 0px;}
+DIV.atf .pagename A {COLOR: #436976! important; TEXT-DECORATION: none! important}
+DIV.atf .logo {FONT-WEIGHT: normal; FONT-SIZE: 50%; FLOAT: right; VERTICAL-ALIGN: middle; TEXT-ALIGN: right; MARGIN-RIGHT: 15px;}
+DIV.atf .logo A {COLOR: #dee7ec; LETTER-SPACING: 0pt; TEXT-DECORATION: none}
+DIV.atf .bar {CLEAR: both; PADDING-RIGHT: 10px; BORDER-TOP: #8cacbb 1px solid; PADDING-LEFT: 1px; BACKGROUND: #dee7ec; PADDING-BOTTOM: 2px; PADDING-TOP: 1px; BORDER-BOTTOM: #8cacbb 1px solid; HEIGHT: 25px; MARGIN-TOP: 6px; MARGIN-BOTTOM: 5px;}
+DIV.atf .bar-left {FLOAT: left; HEIGHT: 25px;}
+DIV.atf .bar-right {FLOAT: right; TEXT-ALIGN: right; HEIGHT: 25px;}
+DIV.atf #bar__bottom {MARGIN-BOTTOM: 2px}
+DIV.atf DIV.meta {CLEAR: both; MARGIN-TOP: 1em; FONT-SIZE: 70%; COLOR: #638c9c}
+DIV.atf DIV.meta DIV.user {FLOAT: left}
+DIV.atf DIV.meta DIV.doc {TEXT-ALIGN: right}
+* {PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px}
+BODY {FONT: 80% "Lucida Grande",Verdana,Lucida,Helvetica,Arial,sans-serif; COLOR: #000; BACKGROUND-COLOR: #fff}
+.indent {MARGIN-LEFT: 62px; WHITE-SPACE: nowrap}
+.indent2 {MARGIN-LEFT: 67px; WHITE-SPACE: nowrap}
+.smaller {FONT-SIZE: 6px}
+.smallest {FONT-SIZE: 2px}
+DIV.atf DIV.page {MARGIN: 4px 2em 0px 1em; TEXT-ALIGN: left}
+DIV.atf IMG {BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px}
+DIV.atf P {MARGIN: 0px 0px 1em}
+DIV.atf HR {BORDER-TOP: #8cacbb 1px solid; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; HEIGHT: 0px; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 0px}
+DIV.atf FORM {BORDER-STYLE: none; PADDING: 0px;}
+DIV.atf DIV.toolbar {MARGIN: 2px 0px; TEXT-ALIGN: left}
+DIV.atf .nowrap {WHITE-SPACE: nowrap}
+.nowrap {WHITE-SPACE: nowrap}
+DIV.atf INPUT.button {HEIGHT: 23px; VERTICAL-ALIGN: middle; TEXT-ALIGN: center; BORDER: #8cacbb 1px solid; PADDING-RIGHT: 4px; PADDING-LEFT: 4px; FONT-SIZE: 100%; BACKGROUND-COLOR: #fff; PADDING-BOTTOM: 2px; MARGIN-LEFT: 1px; MARGIN-TOP: 1px; MARGIN-BOTTOM: 0px; MARGIN-RIGHT: 25px; CURSOR: pointer; COLOR: #000; PADDING-TOP: 1px; TEXT-DECORATION: none;}
+DIV.atf A:link {COLOR: #436976; TEXT-DECORATION: none}
+DIV.atf A:visited {COLOR: #436976; TEXT-DECORATION: none}
+DIV.atf A:hover {COLOR: #000; TEXT-DECORATION: underline}
+DIV.atf A:active {COLOR: #000; TEXT-DECORATION: underline}
+DIV.atf H1 A {COLOR: #000! important; TEXT-DECORATION: none! important}
+DIV.atf H2 A {COLOR: #000! important; TEXT-DECORATION: none! important}
+DIV.atf H3 A {COLOR: #000! important; TEXT-DECORATION: none! important}
+DIV.atf H4 A {COLOR: #000! important; TEXT-DECORATION: none! important}
+DIV.atf H5 A {COLOR: #000! important; TEXT-DECORATION: none! important}
+DIV.atf A.nolink {COLOR: #000; TEXT-DECORATION: none}
+DIV.atf A.urlextern:link {COLOR: #436976! important}
+DIV.atf A.urlextern:visited {COLOR: #436976! important}
+DIV.atf A.link1 {COLOR: #090! important}
+DIV.atf A.link2 {COLOR: #f30! important}
+DIV.atf SPAN.user {FONT-SIZE: 90%; COLOR: #ccc}
+DIV.atf LI.minor {COLOR: #666; FONT-STYLE: italic}
+DIV.atf ACRONYM {CURSOR: help; BORDER-BOTTOM: #000 1px dotted}
+DIV.atf H1 {CLEAR: left; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 1em; COLOR: #000; PADDING-TOP: 10px; BORDER-BOTTOM: #8cacbb 1px solid}
+DIV.atf H2 {CLEAR: left; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: normal; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 1em; COLOR: #000; PADDING-TOP: 5px; BORDER-BOTTOM: #8cacbb 1px solid}
+DIV.atf H3 {CLEAR: left; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 1em; COLOR: #000; PADDING-TOP: 5px; BORDER-BOTTOM: #8cacbb 1px solid}
+DIV.atf H4 {CLEAR: left; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 1em; COLOR: #000; PADDING-TOP: 5px; BORDER-BOTTOM: #8cacbb 1px solid}
+DIV.atf H5 {CLEAR: left; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 1em; COLOR: #000; PADDING-TOP: 5px; BORDER-BOTTOM: #8cacbb 1px solid}
+DIV.atf H6 {FONT-WEIGHT: bold; FONT-SIZE: 120%; MARGIN-LEFT: 40px; BORDER-BOTTOM-STYLE: none; CLEAR: left; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: normal; FONT-SIZE: 120%; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 1em; COLOR: #000; PADDING-TOP: 0.5em}
+DIV.atf H1 {FONT-WEIGHT: bold; FONT-SIZE: 160%; MARGIN-LEFT: 0px}
+DIV.atf H2 {FONT-SIZE: 150%; MARGIN-LEFT: 20px}
+DIV.atf H3 {FONT-WEIGHT: bold; FONT-SIZE: 140%; MARGIN-LEFT: 40px; BORDER-BOTTOM-STYLE: none}
+DIV.atf H4 {FONT-WEIGHT: bold; FONT-SIZE: 120%; MARGIN-LEFT: 60px; BORDER-BOTTOM-STYLE: none}
+DIV.atf H5 {FONT-WEIGHT: bold; FONT-SIZE: 100%; MARGIN-LEFT: 80px; BORDER-BOTTOM-STYLE: none}
+DIV.atf DIV.level1 {MARGIN-LEFT: 3px}
+DIV.atf DIV.level2 {MARGIN-LEFT: 23px}
+DIV.atf DIV.level3 {MARGIN-LEFT: 43px}
+DIV.atf DIV.level4 {MARGIN-LEFT: 63px}
+DIV.atf DIV.level5 {MARGIN-LEFT: 83px}
+DIV.atf UL {LIST-STYLE-IMAGE: none; MARGIN: 0px 0px 0.5em 1.5em; COLOR: #638c9c; LINE-HEIGHT: 1.5em; LIST-STYLE-TYPE: square}
+DIV.atf OL {FONT-WEIGHT: bold; LIST-STYLE-IMAGE: none; MARGIN: 0px 0px 0.5em 1.5em; COLOR: #638c9c; LINE-HEIGHT: 1.5em}
+DIV.atf .li {FONT-WEIGHT: normal; COLOR: #000}
+DIV.atf OL {LIST-STYLE-TYPE: decimal}
+DIV.atf OL OL {LIST-STYLE-TYPE: upper-roman}
+DIV.atf OL OL OL {LIST-STYLE-TYPE: lower-alpha}
+DIV.atf DIV.toc {CLEAR: both; FONT-SIZE: 80%; FLOAT: right; MARGIN: 1.2em 0px 0px 1.7em; WIDTH: 205px}
+DIV.atf DIV.tocheader {BORDER: #8cacbb 1px solid; PADDING: 3px; FONT-WEIGHT: bold; MARGIN-BOTTOM: 2px; BACKGROUND-COLOR: #dee7ec; TEXT-ALIGN: left}
+DIV.atf DIV.tocheader IMG {FLOAT: right; MARGIN: 0.3em 3px 0px 0px; WIDTH: 0.8em; CURSOR: pointer; HEIGHT: 0.8em}
+DIV.atf #toc__inside {BORDER: #8cacbb 1px solid; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0.7em; PADDING-TOP: 0.5em; BACKGROUND-COLOR: #fff; TEXT-ALIGN: left}
+DIV.atf UL.toc {PADDING-LEFT: 0.3em; LIST-STYLE-IMAGE: none; MARGIN: 0px; LINE-HEIGHT: 1.2em; LIST-STYLE-TYPE: none}
+DIV.atf UL.toc LI {PADDING-LEFT: 0.3em; BACKGROUND: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAFElEQVQI12OwCYpxSSph0HHzAbIAGeoDrdYV6fMAAAAASUVORK5CYII=) no-repeat 0px 0.6em}
+DIV.atf UL.toc LI.clear {PADDING-LEFT: 0.4em; BACKGROUND-IMAGE: none}
+DIV.atf A.toc:link {COLOR: #436976}
+DIV.atf A.toc:visited {COLOR: #436976}
+DIV.atf A.toc:hover {COLOR: #000}
+DIV.atf A.toc:active {COLOR: #000}
+-->
+</style>
+<!-- originally saved from http://www.myplugins.info/winamp-wiki/doku.php/advanced_title_formatting -->
+<!-- original credits to Shane Hird and Ben Allison - this document modified and edited for Winamp by DJ Egg -->
+</head>
+
+<body>
+
+<div class="atf">
+<a href="top" name="top"></a>
+<div class="stylehead">
+
+<div class="header">
+<div class="pagename"><a href="javascript: window.location.reload()">Advanced&nbsp;Title&nbsp;Formatting</a></div>
+<div class="clearer"></div>
+</div>
+
+<div class="bar" id="bar__top">
+<div class="bar-left" id="bar__topleft"></div>
+<!--<div class="langform" id="langselect">
+<form name="lang" action="" method="post">
+<select name="xfer" size="1" onmouseup= "location = '' + this.options[this.selectedIndex ].value;">
+<option value="atf.htm" selected="selected">English</option>
+<option value="atf-nl.htm">Dutch</option>
+<option value="atf-fr.htm">French</option>
+<option value="atf-de.htm">German</option>
+<option value="atf-it.htm">Italian</option>
+<option value="atf-jp.htm">Japanese</option>
+<option value="atf-pl.htm">Polish</option>
+<option value="atf-pt.htm">Portuguese</option>
+<option value="atf-ro.htm">Romanian</option>
+<option value="atf-ru.htm">Russian</option>
+<option value="atf-es.htm">Spanish</option>
+<option value="atf-se.htm">Swedish</option>
+<option value="atf-tr.htm">Turkish</option>
+</select>
+</form>
+</div>-->
+<div class="bar-right" id="bar__topright"></div>
+</div>
+
+</div>
+
+<div class="page">
+<div class="toc">
+<div class="tocheader" id="toc__header">Table of Contents</div>
+<div id="toc__inside">
+
+<ul class="toc">
+<li class="clear">
+
+<ul class="toc">
+<li class="level2"><div class="li"><span class="li"><a href="#winamp_atf_reference" class="toc">Winamp ATF Reference</a></span></div>
+<ul class="toc">
+<li class="level3"><div class="li"><span class="li"><a href="#atf_usage" class="toc">ATF Usage</a></span></div></li>
+
+<li class="level3"><div class="li"><span class="li"><a href="#fields" class="toc">Fields</a></span></div>
+<ul class="toc">
+
+<li class="level4"><div class="li"><span class="li"><a href="#provided_by_winamp" class="toc">Provided by Winamp</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#filename" class="toc">%filename%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#folder" class="toc">%folder%</a></span></div></li>
+</ul>
+</li>
+
+<li class="level4"><div class="li"><span class="li"><a href="#provided_by_ml" class="toc">Provided by ML</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#rating" class="toc">%rating%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#playcount" class="toc">%playcount%</a></span></div></li>
+</ul>
+</li>
+
+<li class="level4"><div class="li"><span class="li"><a href="#provided_by_ml_or_input_plugin" class="toc">Provided by ML or input plugin</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#artist" class="toc">%artist%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#title" class="toc">%title%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#album" class="toc">%album%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#year" class="toc">%year%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#genre" class="toc">%genre%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#comment" class="toc">%comment%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#tracknumber" class="toc">%tracknumber%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#bitrate" class="toc">%bitrate%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#type" class="toc">%type%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#vbr" class="toc">%vbr%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#category" class="toc">%category%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#producer" class="toc">%producer%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#director" class="toc">%director%</a></span></div></li>
+</ul>
+</li>
+
+<li class="level4"><div class="li"><span class="li"><a href="#provided_by_input_plugin" class="toc">Provided by input plugin</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#length" class="toc">%length%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#disc" class="toc">%disc%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#track" class="toc">%track%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#composer" class="toc">%composer%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#streamtitle" class="toc">%streamtitle%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#albumartist" class="toc">%albumartist%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#mood" class="toc">%mood%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#bpm" class="toc">%bpm%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#key" class="toc">%key%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#publisher" class="toc">%publisher%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#lyricist" class="toc">%lyricist%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#conductor" class="toc">%conductor%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#tool" class="toc">%tool%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#family" class="toc">%family%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#encoder" class="toc">%encoder%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#isrc" class="toc">%ISRC%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#replaygain_track_gain" class="toc">%replaygain_track_gain%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#replaygain_album_gain" class="toc">%replaygain_album_gain%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#replaygain_track_peak" class="toc">%replaygain_track_peak%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#replaygain_album_peak" class="toc">%replaygain_album_peak%</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#gain" class="toc">%gain%</a></span></div></li>
+</ul>
+</li>
+</ul>
+</li>
+
+<li class="level3"><div class="li"><span class="li"><a href="#functions" class="toc">Functions</a></span></div>
+<ul class="toc">
+<li class="level4"><div class="li"><span class="li"><a href="#control_flow" class="toc">Control Flow</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#conditional_section" class="toc">[...] Conditional section</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#if" class="toc">$if</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#if2" class="toc">$if2</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#if3" class="toc">$if3</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#decode" class="toc">$decode</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#ifgreater" class="toc">$ifgreater</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#iflonger" class="toc">$iflonger</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#ifstrequal2" class="toc">$IfStrEqual2</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#ifstrequal" class="toc">$IfStrEqual</a></span></div></li>
+</ul>
+</li>
+
+<li class="level4"><div class="li"><span class="li"><a href="#logic_operations" class="toc">Logic Operations</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#and" class="toc">$and</a></span></div></li>
+</ul>
+</li>
+
+<li class="level4"><div class="li"><span class="li"><a href="#arithmetic_operations" class="toc">Arithmetic Operations</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#mod" class="toc">$mod</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#div" class="toc">$div</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#mul" class="toc">$mul</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#muldiv" class="toc">$muldiv</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#sub" class="toc">$sub</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#add" class="toc">$add</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#greater" class="toc">$greater</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#max" class="toc">$max</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#min" class="toc">$min</a></span></div></li>
+</ul>
+</li>
+
+<li class="level4"><div class="li"><span class="li"><a href="#string_operations" class="toc">String Operations</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#lower" class="toc">$lower</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#upper" class="toc">$upper</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#replace" class="toc">$replace</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#left" class="toc">$left</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#right" class="toc">$right</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#len" class="toc">$len</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#substr" class="toc">$substr</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#strstr" class="toc">$strstr</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#strrchr" class="toc">$strrchr</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#strlchr" class="toc">$strlchr</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#strchr" class="toc">$strchr</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#shortest" class="toc">$shortest</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#longest" class="toc">$longest</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#abbr" class="toc">$abbr</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#padcut" class="toc">$padcut</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#cut" class="toc">$cut</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#pad" class="toc">$pad</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#lpad" class="toc">$lpad</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#trim" class="toc">$trim</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#repeat" class="toc">$repeat</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#caps" class="toc">$caps</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#caps2" class="toc">$caps2</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#fileext" class="toc">$fileext</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#filepart" class="toc">$filepart</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#filename1" class="toc">$filename</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#directory" class="toc">$directory</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#split" class="toc">$split</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#ext" class="toc">$ext</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#hex" class="toc">$hex</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#dec" class="toc">$dec</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#num" class="toc">$num</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#null" class="toc">$null</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#pathlpart" class="toc">$PathLPart</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#pathrpart" class="toc">$PathRPart</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#pathltrim" class="toc">$PathLTrim</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#pathrtrim" class="toc">$PathRTrim</a></span></div></li>
+</ul>
+</li>
+
+<li class="level4"><div class="li"><span class="li"><a href="#variables" class="toc">Variables</a></span></div>
+<ul class="toc">
+
+<li class="level5"><div class="li"><span class="li"><a href="#puts" class="toc">$puts</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#put" class="toc">$put</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#get" class="toc">$get</a></span></div></li>
+</ul>
+</li>
+<li class="level4"><div class="li"><span class="li"><a href="#system_info" class="toc">System Info</a></span></div>
+<ul class="toc">
+<li class="level5"><div class="li"><span class="li"><a href="#systime_second" class="toc">$systime_second</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#systime_minute" class="toc">$systime_minute</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#systime_hour" class="toc">$systime_hour</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#systime_day" class="toc">$systime_day</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#systime_month" class="toc">$systime_month</a></span></div></li>
+<li class="level5"><div class="li"><span class="li"><a href="#systime_year" class="toc">$systime_year</a></span></div></li>
+</ul>
+</li>
+<li class="level4"><div class="li"><span class="li"><a href="#others._todo" class="toc">Others. (TODO)</a></span></div></li></ul>
+</li>
+<li class="level3"><div class="li"><span class="li"><a href="#examples" class="toc">Examples</a></span></div>
+<ul class="toc">
+<li class="level4"><div class="li"><span class="li"><a href="#standard_atf" class="toc">Standard ATF syntax</a></span></div></li>
+<li class="level4"><div class="li"><span class="li"><a href="#advanced_atf" class="toc">Advanced ATF syntax</a></span></div></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li></ul>
+</div>
+</div>
+
+<h1><a id="winamp_atf_reference" name="winamp_atf_reference">Winamp ATF Reference</a></h1>
+<div class="level1">
+<p>Below is an extract of the Winamp supported ATF functionality.<br/>
+ATF determines how Winamp should display metadata in the Playlist window and Main window songticker.
+The global ATF string can be manually edited via the 'Titles' page in the Winamp Preferences.
+<span class="smallest"><br/><br/><br/></span>
+The default ATF string in Winamp is:<br/><i>[%artist% - ]$if2(%title%,$filepart(%filename%)</i>
+<span class="smallest"><br/><br/><br/></span>
+This will be displayed as: '<i>Artist&nbsp;-&nbsp;Title</i>'
+if the Artist and Title metadata fields are populated in the file tags,
+otherwise it will just display the <i>filename</i> instead.</p>
+</div>
+
+<h2><a id="atf_usage" name="atf_usage">ATF Usage</a></h2>
+<div class="level2">
+<p>%blah% denotes a metadata field.<br/><br/>
+$blah() denotes a function call.<br/><br/>
+[] means &quot;don't display unless metadata was found&quot;.</p>
+<p>&#8216;&nbsp;&#8217; (single quotation marks) outputs raw text without parsing. eg.
+&#8216;blah$blah%blah[]&#8217; which will output all the string and ignore the special
+characters ($,%,[,]). </p></div>
+
+<h2><a id="fields" name="fields">Fields</a></h2>
+<div class="level2">
+<p>Note: Fields are defined by various components within Winamp. Some are
+specific to the Media Library (%rating%, %playcount%), some are provided by
+Winamp (%filename%, %folder%). In most cases, however, the input plugin provides
+the fields. Some input plugins provide a greater variety of fields than others.
+For example, the Windows Media plugin (in_wm, Winamp 5.12+), will provide values
+for ANY field in the form %WM/*% (see the extended attributes section of
+<i>View File Info</i> on any wma/wmv/asf file for examples).<br/></p></div>
+
+<h3><a id="provided_by_winamp" name="provided_by_winamp">Provided by Winamp</a></h3>
+<div class="level3"></div>
+
+<h4><a id="filename" name="filename">%filename%</a></h4>
+<div class="level4">
+<p>Returns the full path of the file. To display the filename only, use the
+<a class="link1" title="$filepart" href="#filepart">$filepart</a> function.</p></div>
+
+<h4><a id="folder" name="folder">%folder%</a></h4>
+<div class="level4">
+<p>Returns the containing folder.<br/>Winamp 5.2+ Only.</p></div>
+
+<h3><a id="provided_by_ml" name="provided_by_ml">Provided by ML</a></h3>
+<div class="level3"></div>
+
+<h4><a id="rating" name="rating">%rating%</a></h4>
+<div class="level4">
+<p>Returns the track rating as an integer from 1 to 5, if set. To display as stars or another character,
+use the <a class="link1" title="$repeat" href="#repeat">$repeat</a> function.</p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="playcount" name="playcount">%playcount%</a></h4>
+<div class="level4">
+<p>Returns the playcount (number of times track has been played), if the file is stored in the Media Library database.</p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h3><a id="provided_by_ml_or_input_plugin"
+name="provided_by_ml_or_input_plugin">Provided by ML or input plugin</a></h3>
+<div class="level3">
+<p>For the fields listed below, info is taken from ML only if the file is
+present in the ML database and if the following option is checkmarked:<br/>
+Prefs
+(Ctrl+P) &gt; Media Library &gt; Local Media &gt; &#8216;Use Library title information
+for Playlist Item Formatting&#8217;</p>
+<p>In all other cases, the info is provided by the input plugin (if the
+respective input plugin supports the field). </p>
+<p>Most of these are straightforward and are taken from the standard file tags,
+and therefore don't require any additional explanatory notes.</p></div>
+
+<h4><a id="artist" name="artist">%artist%</a></h4>
+<div class="level4"><p>Returns the Artist field.</p></div>
+
+<h4><a id="title" name="title">%title%</a></h4>
+<div class="level4"><p>Returns the Title field.</p></div>
+
+<h4><a id="album" name="album">%album%</a></h4>
+<div class="level4"><p>Returns the Album field.</p></div>
+
+<h4><a id="year" name="year">%year%</a></h4>
+<div class="level4"><p>Returns the Year field.</p></div>
+
+<h4><a id="genre" name="genre">%genre%</a></h4>
+<div class="level4"><p>Returns the Genre field.</p></div>
+
+<h4><a id="comment" name="comment">%comment%</a></h4>
+<div class="level4"><p>Returns the Comment field.</p></div>
+
+<h4><a id="tracknumber" name="tracknumber">%tracknumber%</a></h4>
+<div class="level4"><p>Returns the TrackNumber with no padding, eg. Track 1 will be displayed as 1.<br/>
+To pad with zeros, eg. 01, 02...10, 11, use the <a class="link1" title="$num" href="#num">$num</a> or <a class="link1" title="$lpad" href="#lpad">$lpad</a> function.</p></div>
+
+<h4><a id="track" name="track">%track%</a></h4>
+<div class="level4"><p>Same as %tracknumber%</p></div>
+
+<h4><a id="albumartist" name="albumartist">%albumartist%</a></h4>
+<div class="level4">
+<p>Returns the Album Artist field.<br/>
+Winamp 5.3+ Only.</p></div>
+
+<h4><a id="disc" name="disc">%disc%</a></h4>
+<div class="level4">
+<p>Returns the Disc No. tag, if available, eg. 1/2 (Disc #1 of a 2CD set).</p></div>
+
+<h4><a id="composer" name="composer">%composer%</a></h4>
+<div class="level4"><p>Returns the Composer field.</p></div>
+
+<h4><a id="publisher" name="publisher">%publisher%</a></h4>
+<div class="level4"><p>Returns the Publisher (Record Label) field.<br/>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="streamtitle" name="streamtitle">%streamtitle%</a></h4>
+<div class="level4"><p>Returns the Streaming Title for streams, if one exists.</p></div>
+
+<h4><a id="bitrate" name="bitrate">%bitrate%</a></h4>
+<div class="level4"><p>Returns the Bitrate (will use average bitrate for vbr).</p></div>
+
+<h4><a id="length" name="length">%length%</a></h4>
+<div class="level4">
+<p>Returns length of the track in miliseconds. For a formatted track length,
+use<br/><i>$div(%length%,60000):$num($div($mod(%length%,60000),1000),2)</i>
+</p></div>
+
+<h4><a id="type" name="type">%type%</a></h4>
+<div class="level4">
+<p>Returns 1 for video, 0 for audio.<br/>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="vbr" name="vbr">%vbr%</a></h4>
+<div class="level4">
+<p>Returns 1 for VBR(Variable Bitrate) audio, 0 for CBR(Constant Bitrate)
+audio.</p></div>
+
+<h4><a id="category" name="category">%category%</a></h4>
+<div class="level4"><p>Returns the Category field.<br/>Winamp 5.55+ Only.<br/></p></div>
+
+<h4><a id="producer" name="producer">%producer%</a></h4>
+<div class="level4"><p>Returns the (record or film) Producer field.<br/>Winamp 5.57+ Only.<br/></p></div>
+
+<h4><a id="director" name="director">%director%</a></h4>
+<div class="level4"><p>Returns the (film) Director field, mainly used for videos.<br/>Winamp 5.57+ Only.<br/></p></div>
+
+<h3><a id="provided_by_input_plugin" name="provided_by_input_plugin">Provided by
+input plugin</a></h3>
+<div class="level3">
+<p>The fields listed below may not work for all file formats.</p></div>
+
+<h4><a id="trackartist" name="trackartist">%trackartist%</a></h4>
+<div class="level4"><p>Returns the Track Artist field (equivalent to Artist), if different to Album Artist.<br/>
+Winamp 5.3+ Only.</p></div>
+
+<h4><a id="mood" name="mood">%mood%</a></h4>
+<div class="level4"><p>Returns the Mood field.<br/>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="bpm" name="bpm">%bpm%</a></h4>
+<div class="level4"><p>Returns the BPM (Beats Per Minute), if data&#47;field exists.<br/>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="key" name="key">%key%</a></h4>
+<div class="level4"><p>Returns the Key field (eg. E Minor), if it exists.<br/>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="lyricist" name="lyricist">%lyricist%</a></h4>
+<div class="level4"><p>Returns the Lyricist field.<br/>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="conductor" name="conductor">%conductor%</a></h4>
+<div class="level4"><p>Returns the Conductor field.<br/>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="tool" name="tool">%tool%</a></h4>
+<div class="level4"><p>Returns the Encoded&#47;Tool (software used to rip&#47;encode track) field, eg. Winamp 5.34.<br/>
+Winamp 5.3+ Only.</p></div>
+
+<h4><a id="family" name="family">%family%</a></h4>
+<div class="level4"><p>Returns the filetype's Family, eg. M4A returns: MPEG-4 Audio File Format<br/>Winamp 5.5+ Only.</p></div>
+
+<h4><a id="encoder" name="encoder">%encoder%</a></h4>
+<div class="level4"><p>Returns the Encoder, eg. LAME 3.97<br/>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="isrc" name="isrc">%ISRC%</a></h4>
+<div class="level4">
+<p>International Standard Recording Code, or ISO 3901 (<a class="urlextern" title="http://www.id3.org/isrc.html"
+href="http://www.id3.org/isrc.html" rel="nofollow" target="_blank">Info</a>)<br/>Winamp 5.3+ Only.
+</p></div>
+
+<h4><a id="replaygain_track_gain" name="replaygain_track_gain">%replaygain_track_gain%</a></h4>
+<div class="level4"><p>Returns the ReplayGain Track Gain value (eg. -3.16 dB), if it exists.<br/>
+Winamp 5.3+ Only.</p></div>
+
+<h4><a id="replaygain_album_gain" name="replaygain_album_gain">%replaygain_album_gain%</a></h4>
+<div class="level4"><p>Returns the ReplayGain Album Gain value, if it exists.<br/>
+Winamp 5.3+ Only.</p></div>
+
+<h4><a id="replaygain_track_peak" name="replaygain_track_peak">%replaygain_track_peak%</a></h4>
+<div class="level4"><p>Returns the ReplayGain Track Peak value, if it exists.<br/>
+Winamp 5.3+ Only.</p></div>
+
+<h4><a id="replaygain_album_peak" name="replaygain_album_peak">%replaygain_album_peak%</a></h4>
+<div class="level4"><p>Returns the ReplayGain Album Peak value, if it exists.<br/>
+Winamp 5.3+ Only.</p></div>
+
+<h4><a id="gain" name="gain">%gain%</a></h4>
+<div class="level4"><p>Returns the Gain value, if it exists.<br/>Winamp 5.3+ Only.</p></div>
+
+<h2><a id="functions" name="functions">Functions</a></h2>
+<div class="level2">
+<p>Notes: Be careful about spaces after commas. <i>$if(%title%, Has A Title,
+Has No Title)</i> will display<br/>&#8220;&nbsp;Has A Title&#8221; (note leading
+space)<br/><b>not</b> &#8220;Has A Title&#8221;.<br/>The proper form should be
+<i>$if(%title%,Has A Title,Has No Title)</i>.<br/></p></div>
+
+<h3><a id="control_flow" name="control_flow">Control Flow</a></h3>
+<div class="level3"></div>
+
+<h4><a id="conditional_section" name="conditional_section">[...] Conditional
+section</a></h4>
+<div class="level4"></div>
+
+<h4><a id="if" name="if">$if</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a, then,
+else)</i><br/><b>Returns:</b> If <i>a</i> contains at least one
+valid, non-empty field, <i>then</i> is evaluated and returned, otherwise the
+<i>else</i> parameter is. Note that $if(A,A,B) is equivalent to
+$if2(A,B)<br/><b>Example:</b> <i>$if(%artist%,Has an artist tag,Has no
+artist tag)</i></p></div>
+
+<h4><a id="if2" name="if2">$if2</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a, else)</i><br/><b>Returns:</b>
+If <i>a</i> contains a valid, non-empty field, <i>a</i> is evaluated and
+returned, otherwise the <i>else</i> parameter is.<br/><b>Example:</b>
+<i>$if2(%album%,no-album)</i> </p></div>
+
+<h4><a id="if3" name="if3">$if3</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, ..., aN,
+else)</i><br/><b>Returns:</b> If one of <i>a1</i>... <i>aN</i>
+contains a valid, non-empty field, the value is evaluated and returned,
+otherwise the <i>else</i> parameter is used.<br/><b>Example:</b>
+<i>$if3(%artist%,%filename%,%album%,no field)</i></p></div>
+
+<h4><a id="decode" name="decode">$decode</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a, b1, c1, ..., bN, cN,
+else)</i><br/><b>Returns:</b> <i>cN</i> or <i>else</i>. A
+switch/case function, which determines which <i>bN</i> parameter is equal to
+<i>a</i> and returns the corresponding <i>cN</i> parameter. If none are
+matched, it returns the final parameter
+<i>else</i>.<br/><b>Example:</b>
+<i>$decode($fileext(%filename%),MP3,MPEG-1 Layer 3,MP4,MPEG-4 Container,Other)</i></p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="ifgreater" name="ifgreater">$ifgreater</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2, then,
+else)</i><br/><b>Returns:</b> Compares the integer numbers x1 and x2,
+if x1 is greater than x2, <i>then</i> is evaluated and its value returned.
+Otherwise the <i>else</i> part is evaluated and its value
+returned.<br/><b>Example:</b> <i>$ifgreater(%rating%,2,Highly rated
+song,Not highly rated song)</i></p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="iflonger" name="iflonger">$iflonger</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1, then,
+else)</i><br/><b>Returns:</b> Compares whether the length of string a1
+is longer than x1 characters, if a1 is longer, the <i>then</i> part is evaluated and its value returned. Otherwise the <i>else</i> part is evaluated and its value
+returned.<br/><b>Example:</b> <i>$iflonger(%title%,15,A long title,A
+short title)</i></p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="ifstrequal2" name="ifstrequal2">$IfStrEqual2</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(A, B, then,
+else)</i><br/><b>Returns:</b> If <i>A = B</i> do <i>then</i> else
+do <i>else</i><br/>
+<b>Example:</b> <i>$IfStrEqual2(%year%,2007,New!:,Old:)</i><br/>
+<b>Example:</b> <i>$IfStrEqual2(%type%,1,'(Video)','(Audio)')</i></p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="ifstrequal" name="ifstrequal">$IfStrEqual</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(A, B,
+then)</i><br/><b>Returns:</b> If <i>A = B</i> do <i>then</i> else
+nothing<br/><b>Example:</b> <i>$IfStrEqual(%year%,2007,New!:)</i>
+will print &#8220;New!&#8221; if the media was published in 2007.</p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h3><a id="logic_operations" name="logic_operations">Logic Operations</a></h3>
+<div class="level3"></div>
+
+<h4><a id="and" name="and">$and</a></h4>
+<div class="level4">
+<p>&#8211; Removed &#8211;<br/><b>Parameters:</b> <i>(%a%, %b%)</i> &#8211; The fields
+to check if populated.<br/><b>Returns:</b> 1 if the fields %a% and %b%
+are populated. An empty string if not. (?????)<br/><b>Example:</b>
+<i>$if($and(%artist%,%title%),Has both artist and title,One field is
+missing)</i></p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h3><a id="arithmetic_operations" name="arithmetic_operations">Arithmetic
+Operations</a></h3>
+<div class="level3"></div>
+
+<h4><a id="mod" name="mod">$mod</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2)</i><br/><b>Returns:</b>
+remainder of a division of <i>x1</i> by
+<i>x2</i><br/><b>Example:</b> <i>$mod(21,8)</i> returns &#8220;5&#8221;. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="div" name="div">$div</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2)</i><br/><b>Returns:</b>
+x1 / x2. Result of a division of <i>x1</i> by
+<i>x2</i><br/><b>Example:</b> <i>$div(60,10)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="mul" name="mul">$mul</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1,x2,...,xn)</i> - List of numbers to
+multiply<br/><b>Returns:</b> x1 * x2 * ... * xn. The supplied numbers
+multiplied<br/><b>Example:</b> <i>$mul(7,8,3,4)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="muldiv" name="muldiv">$muldiv</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2,
+x3)</i><br/><b>Returns:</b> x1 * x2 / 3. <i>x1</i> multiplied by
+<i>x2</i>, divided by <i>x3</i>. Result is rounded to nearest
+integer.<br/><b>Example:</b> <i>$muldiv(10,6,3)</i> returns &#8220;20&#8221;.
+</p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="sub" name="sub">$sub</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1,x2,...,xn)</i> - List of numbers to
+subtract<br/><b>Returns:</b> x1 - x2 - ... - xn. The result of x2...xn
+subtracted from x1.<br/><b>Example:</b> <i>$sub(25,1,3,2,3)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="add" name="add">$add</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1,x2,...,xn)</i> - List of numbers to
+add<br/><b>Returns:</b> x1 + x2 +...+ xn. The addition of all the
+numbers supplied<br/><b>Example:</b>
+<i>$add(2,3,%playcount%,%rating%)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="greater" name="greater">$greater</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2)</i> - Two numbers to
+compare<br/><b>Returns:</b> 1 if <i>x1</i> is greater than
+<i>x2</i>, otherwise nothing. Similar in use to
+$ifgreater()<br/><b>Example:</b> <i>$greater(3,2)</i> &#8211; note does not
+appear to work within a $if() function. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="max" name="max">$max</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1,...,xn)</i> - List of numbers to
+compare<br/><b>Returns:</b> The largest number in the arguments
+supplied<br/><b>Example:</b> <i>$max(7,8,3,4)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="min" name="min">$min</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1,...,xn)</i> - List of numbers to
+compare<br/><b>Returns:</b> The smallest number in the arguments
+supplied<br/><b>Example:</b> <i>$min(7,8,3,4)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h3><a id="string_operations" name="string_operations">String Operations</a></h3>
+<div class="level3"></div>
+
+<h4><a id="lower" name="lower">$lower</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b> lower
+case of <i>a1</i><br/><b>Example:</b> <i>$lower(%title%)</i>
+</p></div>
+
+<h4><a id="upper" name="upper">$upper</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b> upper
+case of <i>a1</i><br/><b>Example:</b> <i>$upper(%title%)</i>
+</p></div>
+
+<h4><a id="replace" name="replace">$replace</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, a2,
+a3)</i><br/><b>Returns:</b> <i>a1</i> with all occurences of
+<i>a2</i> replaced by <i>a3</i><br/><b>Example:</b>
+<i>$replace(dum,u,o)</i> writes &#8220;dom&#8221;. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="left" name="left">$left</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+the first <i>x1</i> characters of <i>a1</i><br/><b>Example:</b>
+<i>$left(%title%)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="right" name="right">$right</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+the last <i>x1</i> characters of <i>a1</i><br/><b>Example:</b>
+<i>$right(%title%)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="len" name="len">$len</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b> the
+number of characters of <i>a1</i><br/><b>Example:</b>
+<i>$len(%artist%)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="substr" name="substr">$substr</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> TODO: <i>(a1,
+a2)</i><br/><b>Returns:</b> TODO:
+<i>a1</i><br/><b>Example:</b> TODO: <i>$substr()</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="strstr" name="strstr">$strstr</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, a2)</i><br/><b>Returns:</b>
+index of first occurence of string <i>a2</i> in
+<i>a1</i><br/><b>Example:</b> <i>$strstr(aacbbabb,ab)</i> returns
+&#8220;6&#8221;. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="strrchr" name="strrchr">$strrchr</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, a2)</i><br/><b>Returns:</b>
+index of last occurence of character <i>a2</i> in
+<i>a1</i><br/><b>Example:</b> <i>$strrchr(aacbbabb,a)</i> returns
+&#8220;6&#8221;. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="strlchr" name="strlchr">$strlchr</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, a2)</i><br/><b>Returns:</b>
+index of first occurence of character <i>a2</i> in
+<i>a1</i><br/><b>Example:</b> <i>$strlchr(aacbbabb,a)</i> returns
+&#8220;1&#8221;. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="strchr" name="strchr">$strchr</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, a2)</i><br/><b>Returns:</b>
+index of first occurence of character <i>a2</i> in
+<i>a1</i><br/><b>Example:</b> <i>$strchr(aacbbabb,a)</i> returns
+&#8220;1&#8221; (same as <i>$strlchr()</i> ??). </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="shortest" name="shortest">$shortest</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, a2)</i><br/><b>Returns:</b>
+<i>a1</i> or <i>a2</i> based on which has the shorter
+length.<br/><b>Example:</b> <i>$shortest(%album%,%folder%)</i>
+</p></div>
+
+<h4><a id="longest" name="longest">$longest</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, a2)</i><br/><b>Returns:</b>
+<i>a1</i> or <i>a2</i> based on which has the greater
+length.<br/><b>Example:</b> <i>$longest(%album%,%folder%)</i>
+</p></div>
+
+<h4><a id="abbr" name="abbr">$abbr</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/>
+<b>Returns:</b> <i>a1</i> abbreviated.<br/>
+<b>Examples:</b> <i>$abbr(%album%)</i> converts Album name of eg. &#8220;Final Fantasy VI&#8221; to &#8220;FFVI&#8221;.<br/>
+<i>$abbr(Advanced Title Formatting,10)</i> writes &#8220;ATF&#8221;.<br/>
+<i>$abbr(%album%,10)</i> writes abbreviated Album name, only if longer than 10 char's.<br/>
+<i>x1</i> is optional. If defined,
+<i>a1</i> will only be abbreviated when its length exceeds <i>x1</i> char's.</p></div>
+
+<h4><a id="padcut" name="padcut">$padcut</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x2)</i><br/><b>Returns:</b>
+<i>a1</i> padded with spaces or cut off, resulting in a string of <i>x2</i>
+characters<br/><b>Example:</b> <i>$padcut(%artist%,15)</i> </p></div>
+
+<h4><a id="cut" name="cut">$cut</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x2)</i><br/><b>Returns:</b>
+<i>a1</i>, cut off after the <i>x2</i>th
+character<br/><b>Example:</b> <i>$cut(%comment%,15)</i> writes the first 15 characters of the Comment field.</p></div>
+
+<h4><a id="pad" name="pad">$pad</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(string, num,
+padstr)</i><br/><b>Returns:</b> <i>string</i> padded to at least
+<i>num</i> chars, with spaces by default, or specify a character (or repeating
+string) as <i>padstr</i>.<br/><b>Example:</b>
+<i>$pad(%artist%,40)</i>, or <i>$pad(%artist%,40,.)</i> to pad with periods.
+</p></div>
+
+<h4><a id="lpad" name="lpad">$lpad</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(string, num,
+padstr)</i><br/><b>Returns:</b> <i>string</i> padded to at least
+<i>num</i> chars on the left, with spaces by default, or specify a character
+(or repeating string) as <i>padstr</i>.<br/><b>Example:</b>
+<i>$lpad(%tracknumber%,3)</i>, or <i>$lpad(%tracknumber%,3,0)</i> to pad
+zeros in front. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="trim" name="trim">$trim</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b>
+<i>a1</i> without any leading or trailing spaces<br/><b>Example:</b>
+<i>$trim(%artist%)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="repeat" name="repeat">$repeat</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+<i>a1</i> repeated <i>x1</i> times.<br/><b>Example:</b>
+<i>$repeat(*,%rating%)</i> </p>
+<p>($fill() performed this function in Winamp 5.2 and was removed after 5.21.)
+</p></div>
+
+<h4><a id="caps" name="caps">$caps</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b> lower
+case of <i>a1</i>, with first letter of each word in upper
+case<br/><b>Example:</b> <i>$caps(%artist%)</i> </p></div>
+
+<h4><a id="caps2" name="caps2">$caps2</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b>
+<i>a1</i>, with first letter of each word in upper
+case<br/><b>Example:</b> <i>$caps2(%artist%)</i> </p></div>
+
+<h4><a id="fileext" name="fileext">$fileext</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b> file
+extension of <i>a1</i><br/><b>Example:</b>
+<i>$fileext(%filename%)</i> </p></div>
+
+<h4><a id="filepart" name="filepart">$filepart</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b>
+filename of <i>a1</i> (i.e. without the leading
+path)<br/><b>Example:</b> <i>$filepart(%filename%)</i> </p></div>
+
+<h4><a id="filename1" name="filename1">$filename</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b>
+filename of <i>a1</i> (i.e. without the leading
+path)<br/><b>Example:</b> <i>$filename(%filename%)</i> </p></div>
+
+<h4><a id="directory" name="directory">$directory</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+directory name of <i>a1</i>, after going up by <i>x1</i>
+levels<br/><b>Example:</b> <i>$directory(%filename%,2)</i><br/>The
+above example will output &#8220;Music&#8221; if the full path of the file is
+&#8220;C:\Music\Artist - Album\Song.mp3&#8221;. <i>x1</i> is optional, default is 1. </p>
+<p>Winamp 5.2+ Only. </p></div>
+
+<h4><a id="split" name="split">$split</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a, token, which)</i><br/><b>Returns:</b> Splitting of disc and&#47;or track strings, eg. to show &quot;1&quot; instead of &quot;1&#47;11&quot;
+<br/><b>Example:</b> <i>[$num(%track%,2)$IfStrNotEqual($split(%track%,/,1),,/$num($split(%track%,/,1),2))]</i>
+</p>
+<p>Winamp 5.5+ Only.</p></div>
+
+<h4><a id="ext" name="ext">$ext</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1)</i><br/><b>Returns:</b> file
+extension of <i>a1</i><br/><b>Example:</b> <i>$ext(%filename%)</i>
+</p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="hex" name="hex">$hex</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2)</i><br/><b>Returns:</b>
+<i>x1</i> formatted as hexidecimal to <i>x2</i> number of digits, padded to
+the left with zeros.<br/><b>Example:</b> <i>$hex(%tracknumber%,4)</i>
+</p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="dec" name="dec">$dec</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2)</i><br/><b>Returns:</b>
+<i>x1</i> zero padded to the left to form a <i>x2</i> digit
+number.<br/><b>Example:</b> <i>$dec(%tracknumber%,5)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="num" name="num">$num</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(x1, x2)</i><br/><b>Returns:</b>
+<i>x1</i> zero padded to the left to form a <i>x2</i> digit
+number.<br/><b>Example:</b> <i>$num(%tracknumber%,5)</i><br/></p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="null" name="null">$null</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> Any number of
+parameters<br/><b>Returns:</b> Nothing<br/><b>Example:</b>
+<i>$null()</i><br/>Does absolutely nothing. It is useful mainly in places where
+a parameter is required, but you want an empty string. </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="pathlpart" name="pathlpart">$PathLPart</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+The first <i>x1</i> levels of <i>a1</i><br/><b>Example:</b>
+<i>$PathLPart(%filename%,2)</i><br/>The above example will output &#8220;C:\Music&#8221; if
+the full path of the file is &#8220;C:\Music\Sonic Youth - Daydream Nation\01 - Teen
+Age Riot.mp3&#8221;.<br/></p>
+<p>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="pathrpart" name="pathrpart">$PathRPart</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+The last <i>x1</i> levels of <i>a1</i><br/><b>Example:</b>
+<i>$PathRPart(%filename%,2)</i><br/>The above example will output &#8220;Sonic Youth
+- Daydream Nation\01 - Teen Age Riot.mp3&#8221; if the full path of the file is
+&#8220;C:\Music\Sonic Youth - Daydream Nation\01 - Teen Age Riot.mp3&#8221;.<br/></p>
+<p>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="pathltrim" name="pathltrim">$PathLTrim</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+<i>a1</i> minus the first <i>x1</i> levels of
+<i>a1</i><br/><b>Example:</b>
+<i>$PathLTrim(%filename%,1)</i><br/>The above example will output &#8220;Music\Sonic
+Youth - Daydream Nation\01 - Teen Age Riot.mp3&#8221; if the full path of the file is
+&#8220;C:\Music\Sonic Youth - Daydream Nation\01 - Teen Age Riot.mp3&#8221;.<br/></p>
+<p>Winamp 5.3+ Only.</p></div>
+
+<h4><a id="pathrtrim" name="pathrtrim">$PathRTrim</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(a1, x1)</i><br/><b>Returns:</b>
+<i>a1</i> minus the last <i>x1</i> levels of
+<i>a1</i><br/><b>Example:</b>
+<i>$PathRTrim(%filename%,1)</i><br/>The above example will output
+&#8220;C:\Music\Sonic Youth - Daydream Nation&#8221; if the full path of the file is
+&#8220;C:\Music\Sonic Youth - Daydream Nation\01 - Teen Age Riot.mp3&#8221;.<br/></p>
+<p>Winamp 5.3+ Only.</p></div>
+
+<h3><a id="variables" name="variables">Variables</a></h3>
+<div class="level3"></div>
+
+<h4><a id="puts" name="puts">$puts</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(name,
+value)</i><br/><b>Returns:</b> Stores <i>value</i> to the named
+variable <i>name</i>. It may be later retrieved using $get(<i>name</i>). Use
+$put() to store a value and also return the value with the one
+function.<br/><b>Example:</b> <i>$puts(artist_title,%artist% -
+%title%)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="put" name="put">$put</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(name,
+value)</i><br/><b>Returns:</b> <i>value</i>. Stores <i>value</i>
+to the named variable <i>name</i>. It may be later retrieved using
+$get(<i>name</i>). Use $puts() to store a value without returning
+it.<br/><b>Example:</b> <i>$put(artist_title,%artist% - %title%)</i>
+</p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="get" name="get">$get</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> <i>(name)</i><br/><b>Returns:</b>
+<i>value</i> of <i>name</i> variable previously set by a $put() or $puts()
+function<br/><b>Example:</b> <i>$get(artist_title)</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h3><a id="system_info" name="system_info">System Info</a></h3>
+<div class="level3"></div>
+
+<h4><a id="systime_second" name="systime_second">$systime_second</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> TODO: <i>(a1,
+a2)</i><br/><b>Returns:</b> TODO:
+<i>a1</i><br/><b>Example:</b> TODO: <i>$systime_second()</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="systime_minute" name="systime_minute">$systime_minute</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> TODO: <i>(a1,
+a2)</i><br/><b>Returns:</b> TODO:
+<i>a1</i><br/><b>Example:</b> TODO: <i>$systime_minute()</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="systime_hour" name="systime_hour">$systime_hour</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> TODO: <i>(a1,
+a2)</i><br/><b>Returns:</b> TODO:
+<i>a1</i><br/><b>Example:</b> TODO: <i>$systime_hour()</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="systime_day" name="systime_day">$systime_day</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> TODO: <i>(a1,
+a2)</i><br/><b>Returns:</b> TODO:
+<i>a1</i><br/><b>Example:</b> TODO: <i>$systime_day()</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="systime_month" name="systime_month">$systime_month</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> TODO: <i>(a1,
+a2)</i><br/><b>Returns:</b> TODO:
+<i>a1</i><br/><b>Example:</b> TODO: <i>$systime_month()</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h4><a id="systime_year" name="systime_year">$systime_year</a></h4>
+<div class="level4">
+<p><b>Parameters:</b> TODO: <i>(a1,
+a2)</i><br/><b>Returns:</b> TODO:
+<i>a1</i><br/><b>Example:</b> TODO: <i>$systime_year()</i> </p>
+<p>Winamp 5.2+ Only.</p></div>
+
+<h3><a id="others._todo" name="others._todo">Others. (TODO)</a></h3>
+<div class="level4">
+<h6><b>$select</b><br/><br/><b>$tab</b><br/><br/><b>$crlf</b><br/><br/><b>$char</b></h6></div>
+
+<h2><a id="examples" name="examples">Examples</a></h2>
+<div class="level2">
+<p>[ .... ] - displays contents of brackets only if at least one of the fields referenced inside has been found, eg.
+<i>[%artist% - ]</i> will show:&nbsp; &quot;Artist - &quot; &nbsp;only if the %artist% tag is populated,
+otherwise it will not show anything at all (including the hyphen and spaces).</p></div>
+
+<h3><a id="standard_atf" name="standard_atf">Standard ATF syntax</a></h3>
+<div class="level3"><p><b>Syntax:</b>&nbsp;[%artist%&nbsp;-&nbsp;][%album%&nbsp;-&nbsp;][$num(%track%,2)&nbsp;-&nbsp;]$if2(%title%,$filepart(%filename%))<br/>
+<b>Example:</b> Pink Floyd - Animals - 02 - Dogs</p></div>
+<div class="level3"><p></p></div>
+
+<div class="level4">
+<p></p></div>
+
+<h3><a id="advanced_atf" name="advanced_atf">Advanced ATF syntax</a></h3>
+<div class="level3"><p class="atf"><b>Syntax:</b>&nbsp;[$if2(%albumartist%,%artist%)&nbsp;-&nbsp;][%album%&nbsp;-&nbsp;][$num(%track%,2)&nbsp;-&nbsp;]<br/>
+<span class="indent">$IfStrNotEqual(%artist%,$if2(%albumartist%,%artist%),[%artist%&nbsp;-&nbsp;])</span><br/>
+<span class="indent">[$if2(%title%,$filepart(%filename%))][$if($fileext(%filename%),'&nbsp;&nbsp;&nbsp;[&nbsp;&nbsp;',)]</span><br/>
+<span class="indent">[%year%&nbsp;&nbsp;|&nbsp;&nbsp;][$fileext(%filename%)&nbsp;][$if(%bitrate%,&nbsp;'|'&nbsp;&nbsp;,)][%bitrate%&nbsp;'kbps'&nbsp;]</span><br/>
+<span class="indent">[$if($fileext(%filename%),']',)][&nbsp;&nbsp;&nbsp;$repeat(*,%rating%)&nbsp;]</span><br/>
+<b>Returns:</b>&nbsp;AlbumArtist&nbsp;-&nbsp;Album&nbsp;-&nbsp;##&nbsp;-&nbsp;Artist&nbsp;-&nbsp;Title&nbsp;&nbsp;[&nbsp;Year&nbsp;|&nbsp;Ext&nbsp;|&nbsp;Bitrate&nbsp;]&nbsp;&nbsp;StarRating<br/>
+<span class="indent2">if AlbumArtist is different to TrackArtist, otherwise shows Standard format.</span><br/>
+<b>Example:</b>&nbsp;Various&nbsp;-&nbsp;Arcana&nbsp;-&nbsp;01&nbsp;-&nbsp;Tripswitch&nbsp;-&nbsp;Calabi&nbsp;Yau&nbsp;&nbsp;&nbsp;[&nbsp;2006&nbsp;&nbsp;|&nbsp;&nbsp;mp3&nbsp;&nbsp;|&nbsp;&nbsp;205&nbsp;kbps&nbsp;]&nbsp;&nbsp;*****</p></div>
+<div class="level3"><p></p></div>
+
+<div class="level4">
+<p></p></div>
+
+</div>
+
+<div class="clearer"></div>
+
+<div class="stylefoot"><br/>
+<div class="meta">
+<div class="user"></div>
+<div class="doc"><!--advanced_title_formatting.htm - Last modified: 2007/04/27 by DJ Egg --></div>
+</div>
+
+<div class="bar" id="bar__bottom">
+<div class="bar-left" id="bar__bottomleft"></div>
+<div class="bar-right" id="bar__bottomright">
+<form action="" method="get">
+<a class="nolink" href="#top"><input class="button" title="Back to top" onclick="window.scrollTo(0, 0)" type="button" value="Back to top" /></a>
+</form>
+</div>
+<div class="clearer"></div>
+</div>
+
+</div>
+</div>
+
+<div class="no"><br/></div>
+</body>
+</html> \ No newline at end of file
diff --git a/Src/Winamp/resource/bitmap1.bmp b/Src/Winamp/resource/bitmap1.bmp
new file mode 100644
index 00000000..86587882
--- /dev/null
+++ b/Src/Winamp/resource/bitmap1.bmp
Binary files differ
diff --git a/Src/Winamp/resource/bitmap2.bmp b/Src/Winamp/resource/bitmap2.bmp
new file mode 100644
index 00000000..f7e6bbd2
--- /dev/null
+++ b/Src/Winamp/resource/bitmap2.bmp
Binary files differ
diff --git a/Src/Winamp/resource/cmdline.txt b/Src/Winamp/resource/cmdline.txt
new file mode 100644
index 00000000..9658392a
--- /dev/null
+++ b/Src/Winamp/resource/cmdline.txt
@@ -0,0 +1,79 @@
+Command Description
+--------------------------------------------------------------------------------------------------------------------------------------------------
+/NEW Creates a new instance of Winamp.
+/ADD <file> Add the specified 'file' to the playlist editor.
+/BOOKMARK <file> Add the specified 'file' to Winamp's bookmarks.
+
+/CONFIG=<file> Instructs Winamp to use the specified config file instead of the default.
+/INIDIR= Instructs Winamp to use a different settings folder from the default in paths.ini.
+/M3UDIR= Instructs Winamp to use a different folder for storing playlists from the default in paths.ini.
+/CLASS= Specify a different window class to use for Winamp instead of the default "Winamp v1.x".
+
+/REG=[ACDLNSV] Associate Winamp with specific files and OS actions.
+/NOREG Prevent Winamp from using the Windows registry i.e. like a portable mode.
+/UNREG Removes any Winamp file and OS associations previously created by this Winamp install.
+
+/CLOSE or /QUIT or /EXIT Close Winamp.
+/KILL Attempt to kill the Winamp process if it refuses to exit normally.
+
+/SAFE=[1|2] Run Winamp in a safe mode where only officially known plug-ins are loaded.
+ Using /SAFE=2 will also disable the loading of media library plug-ins.
+/SAFEALWAYS Run Winamp like /SAFE=1 but without the prompt, which is otherwise shown.
+
+/ALLOW_COMPAT_MODE This will allow Winamp to be run without the warning shown if Windows compatibility mode
+ is detected, as there are some cases where this is the only way to run Winamp as wanted.
+
+/ADDPLAYLIST <file> <name> [<guid>] Allows for adding the specified playlist to Winamp's library playlists.
+ The <guid> parameter is optional and auto-generated if not specified.
+/APPENDPLAYLIST <guid> <file> Append the specified <file> to the end of the specified playlist.
+ You need to use the correct <guid> otherwise this will fail.
+/CREATEPLAYLIST <name> [<guid>] Will create a new playlist in Winamp's library playlists using the name
+ specified. The <guid> parameter is optional and is auto-generated if
+ not specified.
+/ENUMPLAYLISTS Enumerates through Winamp's library playlists and sends the output to 'stdout'
+ e.g. winamp.exe /ENUMPLAYLISTS > playlists.txt
+ The output is UTF-8 encoded (no BOM) and the formatting is: <GUID>,<file>,<name>
+/DELM3U Instructs Winamp to remove the current copy of winamp.m3u(8) from the playlists folder.
+
+/REV Rewind the currently playing item by the native amount e.g. 5 seconds.
+/FWD Fast forward the currently playing item by the native amount e.g. 5 seconds.
+/PREV Move the currently playing item to the previous item in the playlist editor.
+/NEXT Move the currently playing item to the next item in the playlist editor.
+/PLAY Start Winamp playing.
+/PAUSE Pause playback or restart playback if Winamp is already paused.
+/PLAYPAUSE Pause / resume playback if already playing or starts playback if not already playing.
+/STOP Stop Winamp playing.
+/STOPFADE Stop Winamp playing with fadeout.
+/STOPAFTER Stop Winamp playing after the current item finishes.
+
+/RANDOM or /RANDOM=[0|1] Toggle Winamp's shuffle mode or set it to the specified value.
+/SHUFFLE or /SHUFFLE=[0|1] Random and Shuffle are the same as far as Winamp is concerned.
+
+/REPEAT or /REPEAT=[0|1] Toggle Winamp's repeat mode or set it to the specified value.
+
+/PANLEFT or /PANRIGHT Move the panning (or balance) to the left or the right by ~5%.
+/PAN=[-127 - 127] Set the panning (or balance) to the specified value.
+
+/VOLUP or /VOLDOWN Increase or decrease the current volume by ~5%.
+/VOL=[0 - 100] Set the volume to the specified value.
+
+/CD[0-3] Loads (and plays if applicable from other settings) the specified CD (check the main menu).
+/JUMPTO Open (or toggle) the 'Jump to File' window (subject to its configuration options).
+/CLEAR Clear the contents of the current playlist editor.
+
+/STARTMIN Attempts to start Winamp in a minimized (hidden) state - the OS and plug-ins can override.
+/STARTMAX Attempts to start Winamp in a maximized (visible) state - the OS and plug-ins can override.
+
+
+/COMMAND=<id> Will send the specified command or message <id> via the appropriate message type so
+ less general options can be used without Winamp specifically coding it into these options.
+
+/WA_IPC <id> <param> These will not return any values and are just for sending an action e.g. toggling a state.
+ You will need to consult the Winamp SDK or use a resource editor to obtain appropriate <id>
+ and <param> values to be able to use these.
+
+
+Optional from JTFE (if installed and the functionality is enabled):
+
+/ADD \\QUEUE <file> Add the specified file to the Winamp playlist editor and also to the JTFE queue
+/ADD \\ADDML <file> Add (or update) the specified file in Winamp's Media Library.
diff --git a/Src/Winamp/resource/djegg.bmp b/Src/Winamp/resource/djegg.bmp
new file mode 100644
index 00000000..7992d91c
--- /dev/null
+++ b/Src/Winamp/resource/djegg.bmp
Binary files differ
diff --git a/Src/Winamp/resource/eq_ex.bmp b/Src/Winamp/resource/eq_ex.bmp
new file mode 100644
index 00000000..937e33f8
--- /dev/null
+++ b/Src/Winamp/resource/eq_ex.bmp
Binary files differ
diff --git a/Src/Winamp/resource/gen.bmp b/Src/Winamp/resource/gen.bmp
new file mode 100644
index 00000000..4c170c2e
--- /dev/null
+++ b/Src/Winamp/resource/gen.bmp
Binary files differ
diff --git a/Src/Winamp/resource/genex.bmp b/Src/Winamp/resource/genex.bmp
new file mode 100644
index 00000000..f84a379d
--- /dev/null
+++ b/Src/Winamp/resource/genex.bmp
Binary files differ
diff --git a/Src/Winamp/resource/icon5.ico b/Src/Winamp/resource/icon5.ico
new file mode 100644
index 00000000..3f54a858
--- /dev/null
+++ b/Src/Winamp/resource/icon5.ico
Binary files differ
diff --git a/Src/Winamp/resource/numbers.bmp b/Src/Winamp/resource/numbers.bmp
new file mode 100644
index 00000000..d8827e77
--- /dev/null
+++ b/Src/Winamp/resource/numbers.bmp
Binary files differ
diff --git a/Src/Winamp/resource/splash2.bmp b/Src/Winamp/resource/splash2.bmp
new file mode 100644
index 00000000..0cd90c81
--- /dev/null
+++ b/Src/Winamp/resource/splash2.bmp
Binary files differ
diff --git a/Src/Winamp/resource/team.bmp b/Src/Winamp/resource/team.bmp
new file mode 100644
index 00000000..d97f3608
--- /dev/null
+++ b/Src/Winamp/resource/team.bmp
Binary files differ
diff --git a/Src/Winamp/resource/text.bmp b/Src/Winamp/resource/text.bmp
new file mode 100644
index 00000000..774dd9b1
--- /dev/null
+++ b/Src/Winamp/resource/text.bmp
Binary files differ
diff --git a/Src/Winamp/resource/titlebar-font.png b/Src/Winamp/resource/titlebar-font.png
new file mode 100644
index 00000000..88c31646
--- /dev/null
+++ b/Src/Winamp/resource/titlebar-font.png
Binary files differ
diff --git a/Src/Winamp/resource/titlebar.bmp b/Src/Winamp/resource/titlebar.bmp
new file mode 100644
index 00000000..8a9b9f37
--- /dev/null
+++ b/Src/Winamp/resource/titlebar.bmp
Binary files differ
diff --git a/Src/Winamp/resource/uninstallwa.ico b/Src/Winamp/resource/uninstallwa.ico
new file mode 100644
index 00000000..6b573d38
--- /dev/null
+++ b/Src/Winamp/resource/uninstallwa.ico
Binary files differ
diff --git a/Src/Winamp/resource/video.bmp b/Src/Winamp/resource/video.bmp
new file mode 100644
index 00000000..522a22e8
--- /dev/null
+++ b/Src/Winamp/resource/video.bmp
Binary files differ
diff --git a/Src/Winamp/resource/video_logo.bmp b/Src/Winamp/resource/video_logo.bmp
new file mode 100644
index 00000000..bcdeaf9d
--- /dev/null
+++ b/Src/Winamp/resource/video_logo.bmp
Binary files differ
diff --git a/Src/Winamp/resource/volume.bmp b/Src/Winamp/resource/volume.bmp
new file mode 100644
index 00000000..de2ae315
--- /dev/null
+++ b/Src/Winamp/resource/volume.bmp
Binary files differ
diff --git a/Src/Winamp/setup/checkbox.bmp b/Src/Winamp/setup/checkbox.bmp
new file mode 100644
index 00000000..4730c42b
--- /dev/null
+++ b/Src/Winamp/setup/checkbox.bmp
Binary files differ
diff --git a/Src/Winamp/setup/headerstrip.bmp b/Src/Winamp/setup/headerstrip.bmp
new file mode 100644
index 00000000..a40b51dd
--- /dev/null
+++ b/Src/Winamp/setup/headerstrip.bmp
Binary files differ
diff --git a/Src/Winamp/setup/httpgrab.cpp b/Src/Winamp/setup/httpgrab.cpp
new file mode 100644
index 00000000..6f45914a
--- /dev/null
+++ b/Src/Winamp/setup/httpgrab.cpp
@@ -0,0 +1,183 @@
+#include "main.h"
+#include "./httpgrab.h"
+
+
+static HHOOK g_hook = NULL;
+static HWND g_hook_host = NULL;
+static HWND g_hook_fwd = NULL;
+static DWORD g_hook_flags = 0;
+static HWND *g_hook_phwnd =NULL;
+
+static LRESULT CALLBACK TargetWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK LabelWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static BOOL IsDialog(HWND hwnd)
+{
+ wchar_t szName[256] = {0};
+ return (GetClassNameW(hwnd, szName, sizeof(szName)/sizeof(wchar_t)) &&
+ CSTR_EQUAL == CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
+ NORM_IGNORECASE, szName, -1, L"#32770", -1));
+}
+
+static LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
+{
+ if (HCBT_CREATEWND == code && IsDialog((HWND)wParam) && ((CBT_CREATEWND*)lParam)->lpcs->hwndParent == g_hook_host)
+ {
+ LRESULT result;
+
+ result = CallNextHookEx(g_hook, code, wParam, lParam);
+ UnhookWindowsHookEx(g_hook);
+ g_hook = NULL;
+
+ if (0 == result)
+ {
+ ((CBT_CREATEWND*)lParam)->lpcs->style &= ~WS_VISIBLE;
+ WNDPROC oldProc = (WNDPROC)SetWindowLongPtrW((HWND)wParam, GWLP_WNDPROC, (LONG_PTR)TargetWndProc);
+ if (oldProc)
+ {
+ SetPropW((HWND)wParam, L"WNDPROC", oldProc);
+ if (g_hook_fwd) SetPropW((HWND)wParam, L"FWDHWND", g_hook_fwd);
+ if (g_hook_flags) SetPropW((HWND)wParam, L"FLAGS", (HANDLE)(INT_PTR)g_hook_flags);
+ if (g_hook_phwnd) *g_hook_phwnd = (HWND)wParam;
+ }
+ }
+ else if (g_hook_host && IsWindow(g_hook_host)) DestroyWindow(g_hook_host);
+
+ g_hook_fwd = NULL;
+ g_hook_flags = 0;
+ g_hook_host = NULL;
+ return result;
+ }
+ return CallNextHookEx(g_hook, code, wParam, lParam);
+}
+
+HWND BeginGrabHTTPText(HWND hwndFwd, UINT flags, HWND *phwndTarget)
+{
+
+ g_hook_host = CreateWindowExW(0x08000000/*WS_EX_NOACTIVATE*/ | WS_EX_NOPARENTNOTIFY, L"STATIC", L"", WS_DISABLED | WS_POPUP, -10000, -10000, 0, 0, NULL, NULL, NULL, NULL);
+ if (!g_hook_host) return NULL;
+
+ g_hook = SetWindowsHookEx(WH_CBT, HookProc, NULL, GetCurrentThreadId());
+ if (!g_hook)
+ {
+ if (g_hook_host) DestroyWindow(g_hook_host);
+ g_hook_host = NULL;
+ g_hook_fwd = NULL;
+ g_hook_flags = 0;
+ g_hook_phwnd = NULL;
+ }
+ else
+ {
+ g_hook_fwd = hwndFwd;
+ g_hook_flags = flags;
+ g_hook_phwnd = phwndTarget;
+ }
+ return g_hook_host;
+}
+
+void EndGrabHTTPText(HWND hwndHost)
+{
+ if (g_hook_host == hwndHost)
+ {
+ if (g_hook) UnhookWindowsHookEx(g_hook);
+ g_hook = NULL;
+ g_hook_host = NULL;
+ g_hook_fwd = NULL;
+ g_hook_flags = 0;
+ }
+ if (IsWindow(hwndHost)) DestroyWindow(hwndHost);
+}
+
+static LRESULT CALLBACK TargetWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC fnOldProc = (WNDPROC)GetPropW(hwnd, L"WNDPROC");
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hwndFwd;
+
+ hwndFwd = (HWND)GetPropW(hwnd, L"FWDHWND");
+ DWORD flags = (DWORD)(INT_PTR)GetPropW(hwnd, L"FLAGS");
+ RemovePropW(hwnd, L"FLAGS");
+ RemovePropW(hwnd, L"FWDHWND");
+
+ if (hwndFwd)
+ {
+ HWND hwndText;
+ if (HTTPGRAB_USESTATUSTEXT & flags)
+ {
+ hwndText = GetDlgItem(hwnd, 1180/*IDC_STATUS*/);
+ WNDPROC oldProc = (WNDPROC)SetWindowLongPtrW(hwndText, GWLP_WNDPROC, (LONG_PTR)LabelWndProc);
+ if (oldProc) SetPropW(hwndText, L"WNDPROC", oldProc);
+ else hwndText = hwnd;
+ }
+ else hwndText = hwnd;
+ SetPropW(hwndText, L"FWDTEXT", hwndFwd);
+
+ WCHAR szText[256] = {0};
+ GetWindowTextW(hwndText, szText, sizeof(szText)/sizeof(wchar_t));
+ SetWindowTextW(hwndFwd, szText);
+ }
+ }
+ break;
+ case WM_DESTROY:
+ {
+ RemovePropW(hwnd, L"WNDPROC");
+ RemovePropW(hwnd, L"FWDTEXT");
+ if (fnOldProc) SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)fnOldProc);
+ HWND hwndOwner;
+ hwndOwner = GetWindow(hwnd, GW_OWNER);
+ if (hwndOwner) DestroyWindow(hwndOwner);
+ }
+ break;
+ case WM_STYLECHANGING:
+ if (GWL_STYLE & wParam) ((STYLESTRUCT*)lParam)->styleNew &= ~WS_VISIBLE;
+ return 0;
+ case WM_STYLECHANGED:
+ if ((GWL_STYLE & wParam) && (WS_VISIBLE & ((STYLESTRUCT*)lParam)->styleNew))
+ SetWindowLongPtrW(hwnd, GWL_STYLE, (((STYLESTRUCT*)lParam)->styleNew & ~WS_VISIBLE));
+ return 0;
+ case WM_WINDOWPOSCHANGING:
+ ((WINDOWPOS*)lParam)->flags = (((WINDOWPOS*)lParam)->flags & ~(SWP_SHOWWINDOW | SWP_FRAMECHANGED)) | SWP_NOACTIVATE | SWP_NOZORDER;
+ return 0;
+ case WM_SETTEXT:
+ {
+ HWND hwndFwd = (HWND)GetPropW(hwnd, L"FWDTEXT");
+ if (hwndFwd)
+ {
+ (IsWindowUnicode(hwndFwd)) ? SendMessageW(hwndFwd, WM_SETTEXT, wParam, lParam) :
+ SendMessageA(hwndFwd, WM_SETTEXT, wParam, lParam);
+ }
+ }
+ break;
+ }
+ if (!fnOldProc) return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ return (IsWindowUnicode(hwnd)) ? CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnOldProc, hwnd, uMsg, wParam, lParam);
+}
+
+static LRESULT CALLBACK LabelWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC fnOldProc = (WNDPROC)GetPropW(hwnd, L"WNDPROC");
+
+ switch(uMsg)
+ {
+ case WM_SETTEXT:
+ {
+ HWND hwndFwd = (HWND)GetPropW(hwnd, L"FWDTEXT");
+ if (hwndFwd)
+ {
+ (IsWindowUnicode(hwndFwd)) ? SendMessageW(hwndFwd, WM_SETTEXT, wParam, lParam) :
+ SendMessageA(hwndFwd, WM_SETTEXT, wParam, lParam);
+ }
+ }
+ case WM_DESTROY:
+ RemovePropW(hwnd, L"WNDPROC");
+ RemovePropW(hwnd, L"FWDTEXT");
+ if (fnOldProc) SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)fnOldProc);
+ break;
+ }
+ if (!fnOldProc) return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ return (IsWindowUnicode(hwnd)) ? CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnOldProc, hwnd, uMsg, wParam, lParam);
+}
diff --git a/Src/Winamp/setup/httpgrab.h b/Src/Winamp/setup/httpgrab.h
new file mode 100644
index 00000000..94845df8
--- /dev/null
+++ b/Src/Winamp/setup/httpgrab.h
@@ -0,0 +1,13 @@
+#ifndef WINAMP_HTTP_GRAB_TEXT_HEADER
+#define WINAMP_HTTP_GRAB_TEXT_HEADER
+
+#include <windows.h>
+
+#define HTTPGRAB_USEWINDOWTEXT 0x0000
+#define HTTPGRAB_USESTATUSTEXT 0x0001
+
+HWND BeginGrabHTTPText(HWND hwndFwd, UINT flags, HWND *phwndTarget); // returns hwnd that you need to supply as parent of http funciton
+void EndGrabHTTPText(HWND hwndHost);
+
+
+#endif //WINAMP_HTTP_GRAB_TEXT_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/ifc_setupjob.h b/Src/Winamp/setup/ifc_setupjob.h
new file mode 100644
index 00000000..ae239810
--- /dev/null
+++ b/Src/Winamp/setup/ifc_setupjob.h
@@ -0,0 +1,42 @@
+#ifndef WINAMP_IFC_SETUP_JOB_HEADER
+#define WINAMP_IFC_SETUP_JOB_HEADER
+
+#include <bfc/dispatch.h>
+#include <windows.h>
+
+class NOVTABLE ifc_setupjob : public Dispatchable
+{
+protected:
+ ifc_setupjob(void) {}
+ virtual ~ifc_setupjob(void) {}
+
+public:
+ HRESULT Execute(HWND hwndText);
+ HRESULT Cancel(HWND hwndText);
+ HRESULT IsCancelSupported(void);
+
+public:
+ DISPATCH_CODES
+ {
+ API_SETUPJOB_EXECUTE = 10,
+ API_SETUPJOB_CANCEL = 20,
+ API_SETUPJOB_ISCANCELSUPPORTED = 30,
+ };
+};
+
+inline HRESULT ifc_setupjob::Execute(HWND hwndText)
+{
+ return _call(API_SETUPJOB_EXECUTE, E_NOTIMPL, hwndText);
+}
+
+inline HRESULT ifc_setupjob::Cancel(HWND hwndText)
+{
+ return _call(API_SETUPJOB_CANCEL, E_NOTIMPL, hwndText);
+}
+
+inline HRESULT ifc_setupjob::IsCancelSupported(void)
+{
+ return _call(API_SETUPJOB_ISCANCELSUPPORTED, E_NOTIMPL);
+}
+
+#endif //WINAMP_IFC_SETUP_JOB_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/ifc_setuppage.h b/Src/Winamp/setup/ifc_setuppage.h
new file mode 100644
index 00000000..3ea57de8
--- /dev/null
+++ b/Src/Winamp/setup/ifc_setuppage.h
@@ -0,0 +1,62 @@
+#ifndef WINAMP_IFC_SETUP_PAGE_HEADER
+#define WINAMP_IFC_SETUP_PAGE_HEADER
+
+#include <bfc/dispatch.h>
+#include <windows.h>
+
+class NOVTABLE ifc_setuppage : public Dispatchable
+{
+protected:
+ ifc_setuppage(void) {}
+ virtual ~ifc_setuppage(void) {}
+
+public:
+ HRESULT GetName(bool bShort, const wchar_t **pszName);
+ HRESULT Save(HWND hwndText); // setup will allways call this no matter of IsDirty result. (you can check dirty state inside save());
+ HRESULT CreateView(HWND hwndParent, HWND *phwnd);
+ HRESULT Revert(void);
+ HRESULT IsDirty(void); // S_OK - valid, S_FALSE - page is not dirty ( no save required), E_NOTIMPL - not impl. all errors counts as dirty
+ HRESULT Validate(void); // S_OK - valid, S_FALSE - invalid, E_NOTIMPL - not impl. all errors counts as page is valid
+
+public:
+ DISPATCH_CODES
+ {
+ API_SETUPPAGE_GET_NAME = 10,
+ API_SETUPPAGE_CREATEVIEW = 20,
+ API_SETUPPAGE_SAVE = 30,
+ API_SETUPPAGE_ISDIRTY = 40,
+ API_SETUPPAGE_REVERT = 50,
+ API_SETUPPAGE_VALIDATE = 60,
+ };
+};
+
+inline HRESULT ifc_setuppage::GetName(bool bShort, const wchar_t **pszName)
+{
+ return _call(API_SETUPPAGE_GET_NAME, E_NOTIMPL, bShort, pszName);
+}
+
+inline HRESULT ifc_setuppage::CreateView(HWND hwndParent, HWND *phwnd)
+{
+ return _call(API_SETUPPAGE_CREATEVIEW, E_NOTIMPL, hwndParent, phwnd);
+}
+
+inline HRESULT ifc_setuppage::Save(HWND hwndText)
+{
+ return _call(API_SETUPPAGE_SAVE, E_NOTIMPL, hwndText);
+}
+
+inline HRESULT ifc_setuppage::IsDirty(void)
+{
+ return _call(API_SETUPPAGE_ISDIRTY, E_NOTIMPL);
+}
+
+inline HRESULT ifc_setuppage::Revert(void)
+{
+ return _call(API_SETUPPAGE_REVERT, E_NOTIMPL);
+}
+
+inline HRESULT ifc_setuppage::Validate(void)
+{
+ return _call(API_SETUPPAGE_VALIDATE, E_NOTIMPL);
+}
+#endif //WINAMP_IFC_SETUP_PAGE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/langutil.cpp b/Src/Winamp/setup/langutil.cpp
new file mode 100644
index 00000000..a461fc3b
--- /dev/null
+++ b/Src/Winamp/setup/langutil.cpp
@@ -0,0 +1,43 @@
+#include "main.h"
+#include "./langutil.h"
+
+
+
+INT_PTR WADialogBoxParam(LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam)
+{
+ INT_PTR ret(0);
+ HINSTANCE hInst = (language_pack_instance) ? language_pack_instance : hMainInstance;
+ while(hInst)
+ {
+ ret = DialogBoxParamW(hInst, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam);
+ if (-1 == ret && hInst != hMainInstance) hInst = hMainInstance;
+ else break;
+ }
+ return ret;
+}
+
+HWND WACreateDialogParam(LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam)
+{
+ HWND ret(NULL);
+ HINSTANCE hInst = (language_pack_instance) ? language_pack_instance : hMainInstance;
+ while(hInst)
+ {
+ ret = CreateDialogParamW(hInst, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam);
+ if (NULL == ret && hInst != hMainInstance) hInst = hMainInstance;
+ else break;
+ }
+ return ret;
+}
+
+HBITMAP WALoadImage2(LPCWSTR pszSectionName, LPCWSTR lpImageName, BOOL bPremult)
+{
+ HBITMAP ret(NULL);
+ HINSTANCE hInst = (language_pack_instance) ? language_pack_instance : hMainInstance;
+ while(hInst)
+ {
+ ret = WALoadImage(hInst, pszSectionName, lpImageName, bPremult);
+ if (NULL == ret && hInst != hMainInstance) hInst = hMainInstance;
+ else break;
+ }
+ return ret;
+} \ No newline at end of file
diff --git a/Src/Winamp/setup/langutil.h b/Src/Winamp/setup/langutil.h
new file mode 100644
index 00000000..dc4168de
--- /dev/null
+++ b/Src/Winamp/setup/langutil.h
@@ -0,0 +1,18 @@
+#ifndef WINAMP_SETUP_LANGUTIL_HEADER
+#define WINAMP_SETUP_LANGUTIL_HEADER
+
+#include <windows.h>
+#include "./loadimage.h"
+
+INT_PTR WADialogBoxParam(LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam);
+HWND WACreateDialogParam(LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam);
+HBITMAP WALoadImage2(LPCWSTR pszSectionName, LPCWSTR lpImageName, BOOL bPremult);
+
+
+#define WADialogBox(lpTemplate, hWndParent, lpDialogFunc) \
+WADialogBoxParam(lpTemplate, hWndParent, lpDialogFunc, 0L)
+
+#define WACreateDialog(lpName, hWndParent, lpDialogFunc) \
+WACreateDialogParam(lpName, hWndParent, lpDialogFunc, 0L)
+
+#endif //WINAMP_SETUP_LANGUTIL_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/loadimage.cpp b/Src/Winamp/setup/loadimage.cpp
new file mode 100644
index 00000000..54bbe566
--- /dev/null
+++ b/Src/Winamp/setup/loadimage.cpp
@@ -0,0 +1,235 @@
+#include "main.h"
+#include "./loadimage.h"
+#include "./api.h"
+#include <api/service/waServiceFactory.h>
+#include <api/service/svcs/svc_imgload.h>
+
+#define ABS(x) (((x) > 0) ? (x) : (-x))
+
+static HANDLE ReadFromFile(LPCWSTR pszImage, DWORD *size, HANDLE *hres)
+{
+ HANDLE hFile = CreateFileW(pszImage, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL), hmem(NULL);
+ *size = 0;
+ if (INVALID_HANDLE_VALUE != hFile)
+ {
+ *size = GetFileSize(hFile, NULL);
+ if (INVALID_FILE_SIZE != *size)
+ {
+ hmem = HeapAlloc(GetProcessHeap(), 0, *size);
+ if (hmem)
+ {
+ DWORD readed = 0;
+ if (!ReadFile(hFile, hmem, *size, &readed, NULL) || *size != readed)
+ {
+ HeapFree(GetProcessHeap(), 0, hmem);
+ hmem = NULL;
+ }
+ }
+ }
+ CloseHandle(hFile);
+ }
+
+ *hres = hmem;
+ return hmem;
+}
+
+static HANDLE ReadFromRes(HMODULE hMod, LPCWSTR pszSection, LPCWSTR pszImage, DWORD *size, HANDLE *hres)
+{
+ *size = 0;
+ HRSRC res = FindResourceW(hMod, pszImage, pszSection);
+ if (res)
+ {
+ *hres = LoadResource(hMod, res);
+ *size = SizeofResource(hMod, res);
+ return LockResource(*hres);
+ }
+ return NULL;
+}
+
+static HANDLE LoadImg(HANDLE data, DWORD size, INT *cx, INT *cy, BOOL premult)
+{
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ if (l->testData(data,size))
+ {
+ HANDLE ret;
+ ret = (premult) ? l->loadImage(data, size, cx, cy) : l->loadImageData(data, size, cx, cy);
+ sf->releaseInterface(l);
+ return ret;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return NULL;
+}
+
+HBITMAP WALoadImage(HMODULE hMod, LPCWSTR pszSection, LPCWSTR pszImage, BOOL bPremult)
+{
+ BITMAPINFOHEADER header = {0};
+ HBITMAP hbmp = NULL;
+ HANDLE hres = NULL;
+ LPVOID dib = NULL;
+ DWORD size = 0;
+
+ header.biBitCount = 32;
+ header.biPlanes = 1;
+ header.biSize = sizeof(BITMAPINFOHEADER);
+
+ LPVOID data = (!hMod) ? ReadFromFile(pszImage, &size, &hres) : ReadFromRes(hMod, pszSection, pszImage, &size, &hres);
+
+ if (data) data = LoadImg(data, size, (int*)&header.biWidth, (int*)&header.biHeight, bPremult);
+
+ if (hres)
+ {
+ (hMod) ? FreeResource(hres) : HeapFree(GetProcessHeap(), 0, hres);
+ }
+
+ if (data)
+ {
+ header.biHeight = 0 - header.biHeight;
+ hbmp = CreateDIBSection(NULL, (LPBITMAPINFO)&header, DIB_RGB_COLORS, &dib, NULL, 0);
+ if (hbmp) CopyMemory(dib, data, header.biWidth * ABS(header.biHeight) * sizeof(DWORD));
+ WASABI_API_MEMMGR->sysFree(data);
+ }
+ else hbmp = NULL;
+ return hbmp;
+}
+
+HBITMAP WAResizeImage(HBITMAP hbmp, INT cx, INT cy, HBRUSH hbBk)
+{
+ BITMAP bi = {0};
+
+ if (!hbmp || !GetObject(hbmp, sizeof(BITMAP), &bi)) return hbmp;
+
+ if (bi.bmWidth != cx || bi.bmHeight != cy)
+ {
+ INT ix = cx, iy = cy;
+
+ HDC hdc = GetDC(NULL),
+ hdcSrc = CreateCompatibleDC(hdc),
+ hdcDst = CreateCompatibleDC(hdc);
+ HBITMAP hbmpOld1 = (HBITMAP)SelectObject(hdcSrc, hbmp);
+ hbmp = CreateCompatibleBitmap(hdc, cx, cy);
+ HBITMAP hbmpOld2 = (HBITMAP)SelectObject(hdcDst, hbmp);
+ if (ix != cx || iy != cy)
+ {
+ RECT r;
+ SetRect(&r, 0, 0, cx, cy);
+ FillRect(hdcDst, &r, hbBk);
+ }
+ SetStretchBltMode(hdcDst, HALFTONE);
+ StretchBlt(hdcDst, (cx - ix)/2, (cy - iy)/2, ix, iy, hdcSrc, 0, 0, bi.bmWidth, bi.bmHeight, SRCCOPY);
+
+ SelectObject(hdcDst, hbmpOld2);
+ hbmpOld2 = (HBITMAP)SelectObject(hdcSrc, hbmpOld1);
+ if (hbmpOld2) DeleteObject(hbmpOld2);
+
+ DeleteDC(hdcSrc);
+ DeleteDC(hdcDst);
+ ReleaseDC(NULL, hdc);
+ }
+ return hbmp;
+}
+
+HBITMAP WABlendOnColor(HBITMAP hbmp, COLORREF rgbBk)
+{
+ DIBSECTION dibsec = {0};
+ LONG pitch, x;
+ INT cx, cy;
+ LPBYTE cursor = NULL, line = NULL, pData = NULL;
+
+ if (!hbmp || sizeof(DIBSECTION) != GetObjectW(hbmp, sizeof(DIBSECTION), &dibsec) ||
+ BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || 32 != dibsec.dsBm.bmBitsPixel) return hbmp;
+
+ cx = dibsec.dsBm.bmWidth;
+ cy = dibsec.dsBm.bmHeight;
+ pitch = dibsec.dsBm.bmWidth*4;
+ pData = (LPBYTE)dibsec.dsBm.bmBits;
+
+ for (line = pData; cy-- != 0; line += pitch )
+ {
+ for (x = cx, cursor = line; x-- != 0; cursor += 4)
+ {
+ if (0x00 == cursor[3])
+ {
+ cursor[0] = GetBValue(rgbBk);
+ cursor[1] = GetGValue(rgbBk);
+ cursor[2] = GetRValue(rgbBk);
+ cursor[3] = 0xFF;
+ }
+ else if (cursor[3] != 0xFF)
+ {
+ cursor[0] = (cursor[0]*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*GetBValue(rgbBk) + 127)/255;
+ cursor[1] = (cursor[1]*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*GetGValue(rgbBk) + 127)/255;
+ cursor[2] = (cursor[2]*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*GetRValue(rgbBk) + 127)/255;
+ cursor[3] = 0xFF;
+ }
+ }
+ }
+ return hbmp;
+}
+
+HBITMAP WACreatePatternBitmap(INT cx, INT cy, INT bpp, HBRUSH hbPattern, LPBYTE *ppData)
+{
+ BITMAPINFOHEADER bi = {0};
+ RECT r;
+ HDC hdcTmp = CreateCompatibleDC(NULL);
+
+ bi.biSize = sizeof (bi);
+ bi.biWidth= cx;
+ bi.biHeight = -cy;
+ bi.biPlanes = 1;
+ bi.biBitCount= (WORD)bpp;
+
+ HBITMAP hbmpPattern = CreateDIBSection(hdcTmp, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (LPVOID*)ppData, NULL, NULL);
+ if (!hbmpPattern) return NULL;
+
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcTmp, hbmpPattern);
+ SetRect(&r, 0, 0, cx, cy);
+ FillRect(hdcTmp, &r, hbPattern);
+ SelectObject(hdcTmp, hbmpOld);
+ DeleteDC(hdcTmp);
+ return hbmpPattern;
+}
+
+HBITMAP WABlendOnARGB32(HBITMAP hbmp, LPBYTE pRGB)
+{
+ DIBSECTION dibsec = {0};
+ LONG pitch, x;
+ INT cx, cy;
+ LPBYTE cursor = NULL, cursor2 = NULL, line = NULL, line2 = NULL, pData = NULL;
+
+ if (!hbmp || sizeof(DIBSECTION) != GetObjectW(hbmp, sizeof(DIBSECTION), &dibsec) ||
+ BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || 32 != dibsec.dsBm.bmBitsPixel) return hbmp;
+
+ cx = dibsec.dsBm.bmWidth;
+ cy = dibsec.dsBm.bmHeight;
+ pitch = dibsec.dsBm.bmWidth*4;
+ pData = (LPBYTE)dibsec.dsBm.bmBits;
+
+ for (line = pData, line2 = pRGB; cy-- != 0; line += pitch, line2 += pitch )
+ {
+ for (x = cx, cursor = line, cursor2 = line2; x-- != 0; cursor += 4, cursor2 += 4)
+ {
+ if (0x00 == cursor[3]) *((DWORD*)cursor) = *((DWORD*)cursor2);
+ else if (cursor[3] != 0xFF)
+ {
+ cursor[0] = (cursor[0]*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*cursor2[0] + 127)/255;
+ cursor[1] = (cursor[1]*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*cursor2[1] + 127)/255;
+ cursor[2] = (cursor[2]*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*cursor2[2] + 127)/255;
+ }
+ cursor[3] = 0xFF;
+ }
+ }
+
+ return hbmp;
+} \ No newline at end of file
diff --git a/Src/Winamp/setup/loadimage.h b/Src/Winamp/setup/loadimage.h
new file mode 100644
index 00000000..eb873753
--- /dev/null
+++ b/Src/Winamp/setup/loadimage.h
@@ -0,0 +1,12 @@
+#ifndef WINAMP_LOADIMAGE_HEADER
+#define WINAMP_LOADIMAGE_HEADER
+
+#include <windows.h>
+
+HBITMAP WALoadImage(HMODULE hMod, LPCWSTR pszSection, LPCWSTR pszImage, BOOL bPremult);
+HBITMAP WAResizeImage(HBITMAP hbmp, INT cx, INT cy, HBRUSH hbBk);
+HBITMAP WABlendOnColor(HBITMAP hbmp, COLORREF rgbBk);
+HBITMAP WABlendOnARGB32(HBITMAP hbmp, LPBYTE pRGB);
+HBITMAP WACreatePatternBitmap(INT cx, INT cy, INT bpp, HBRUSH hbPattern, LPBYTE *ppData);
+
+#endif //WINAMP_LOADIMAGE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/navitemstrip.bmp b/Src/Winamp/setup/navitemstrip.bmp
new file mode 100644
index 00000000..0eb654ce
--- /dev/null
+++ b/Src/Winamp/setup/navitemstrip.bmp
Binary files differ
diff --git a/Src/Winamp/setup/navstrip.bmp b/Src/Winamp/setup/navstrip.bmp
new file mode 100644
index 00000000..6105816d
--- /dev/null
+++ b/Src/Winamp/setup/navstrip.bmp
Binary files differ
diff --git a/Src/Winamp/setup/png.rc b/Src/Winamp/setup/png.rc
new file mode 100644
index 00000000..e66ee65c
--- /dev/null
+++ b/Src/Winamp/setup/png.rc
@@ -0,0 +1,72 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "setup_resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Data
+//
+
+IDB_ABOUT ".\\smokingllama.png"
+IDB_PREVIEW_CLASSIC ".\\preview_classicskin.png"
+IDB_PREVIEW_NO_1 ".\\preview_no.png"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""setup_resource.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Winamp/setup/postsetup.cpp b/Src/Winamp/setup/postsetup.cpp
new file mode 100644
index 00000000..55eafa94
--- /dev/null
+++ b/Src/Winamp/setup/postsetup.cpp
@@ -0,0 +1,68 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include ".\postsetup.h"
+#include "./setup_resource.h"
+#include "./langutil.h"
+#include "api.h"
+
+
+static BOOL SleepMsg(DWORD dwTimeout)
+{
+ DWORD dwStart = GetTickCount();
+ DWORD dwElapsed;
+ while ((dwElapsed = GetTickCount() - dwStart) < dwTimeout)
+ {
+ DWORD dwStatus = MsgWaitForMultipleObjectsEx(0, NULL, dwTimeout - dwElapsed, QS_ALLINPUT, MWMO_WAITALL | MWMO_INPUTAVAILABLE);
+ if (dwStatus == WAIT_OBJECT_0) while (application->app_messageLoopStep());
+ }
+ return TRUE; // timed out
+}
+
+BOOL StartWinamp(BOOL bWaitShow, HWND *phwndWA, LPCSTR pszParam)
+{
+ HWND hwndWA;
+ DWORD pid;
+ wchar_t buf[MAX_PATH] = L"\"";
+ STARTUPINFOW si = {sizeof(si), };
+ PROCESS_INFORMATION pi;
+
+ if (phwndWA) *phwndWA = NULL;
+
+ GetModuleFileNameW(NULL, buf + 1, sizeof(buf)/sizeof(wchar_t) - 1);
+ StringCchCatW(buf, MAX_PATH, L"\" /NEW ");
+ if (*pszParam && lstrlenA(pszParam))
+ {
+ int count, len;
+ len = sizeof(buf)/sizeof(wchar_t) - lstrlenW(buf)- 1;
+ count = MultiByteToWideChar(CP_ACP, 0, pszParam, -1, NULL, 0);
+ if (count < len) MultiByteToWideChar(CP_ACP, 0, pszParam, -1, buf + lstrlenW(buf), len);
+ }
+ si.dwFlags = STARTF_FORCEONFEEDBACK | STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOWNOACTIVATE;
+ if ( 0 ==CreateProcessW(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+ {
+ return FALSE;
+ }
+
+ hwndWA = NULL;
+ if (bWaitShow)
+ {
+ for (int a = 0; a < 20; a++)
+ {
+ if (!hwndWA)
+ {
+ while (NULL != (hwndWA = FindWindowExW(NULL, hwndWA, szAppName, NULL)))
+ {
+ GetWindowThreadProcessId(hwndWA, &pid);
+ if (pid == pi.dwProcessId) break;
+ }
+ }
+ SleepMsg(250);
+ if (hwndWA && IsWindowVisible(hwndWA))
+ break;
+ }
+ }
+
+ if (phwndWA) *phwndWA = hwndWA;
+ return TRUE;
+} \ No newline at end of file
diff --git a/Src/Winamp/setup/postsetup.h b/Src/Winamp/setup/postsetup.h
new file mode 100644
index 00000000..001ed6ae
--- /dev/null
+++ b/Src/Winamp/setup/postsetup.h
@@ -0,0 +1,10 @@
+#ifndef WINAMP_POSTSETUP_HEADER
+#define WINAMP_POSTSETUP_HEADER
+
+#include <windows.h>
+
+HWND CreateStatusWnd(HWND hwndParent, INT x, INT y, INT cx, INT cy);
+void SetStatusText();
+BOOL StartWinamp(BOOL bWaitShow, HWND *phwndWA, LPCSTR pszParam);
+
+#endif //WINAMP_POSTSETUP_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/preview_classic.png b/Src/Winamp/setup/preview_classic.png
new file mode 100644
index 00000000..7a02a1da
--- /dev/null
+++ b/Src/Winamp/setup/preview_classic.png
Binary files differ
diff --git a/Src/Winamp/setup/preview_no.png b/Src/Winamp/setup/preview_no.png
new file mode 100644
index 00000000..317bc0ab
--- /dev/null
+++ b/Src/Winamp/setup/preview_no.png
Binary files differ
diff --git a/Src/Winamp/setup/resource.h b/Src/Winamp/setup/resource.h
new file mode 100644
index 00000000..7a1e3e2c
--- /dev/null
+++ b/Src/Winamp/setup/resource.h
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by png.rc
+//
+#define IDB_PREVIEW_NO_1 115
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 117
+#define _APS_NEXT_COMMAND_VALUE 40017
+#define _APS_NEXT_CONTROL_VALUE 1033
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Winamp/setup/setup.cpp b/Src/Winamp/setup/setup.cpp
new file mode 100644
index 00000000..4ec461ae
--- /dev/null
+++ b/Src/Winamp/setup/setup.cpp
@@ -0,0 +1,1131 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include "./setup.h"
+#include "./setup_resource.h"
+#include "./loadimage.h"
+#include "./langutil.h"
+#include "../nu/AutoWide.h"
+#include "api.h"
+
+#define HEADER_FONT_NAME "Arial"//"Lucida Sans Unicode"//"Verdana"//"Trebuchet MS"//"Arial Unicode MS"
+#define HEADER_FONT_SIZE 13 //11
+#define HEADER_FONT_ITALIC FALSE
+#define HEADER_FONT_WEIGHT FW_MEDIUM
+#define HEADER_TEXT_COLOR RGB(255,255,255)//RGB(16, 72, 148)//RGB(7, 30, 140)
+#define HEADER_BORDER_COLOR RGB(236, 233, 216)
+
+#define HEADER_PAGENUM_FONT_NAME "Lucida Sans Unicode"//"Lucida Sans Unicode"//"Verdana"//"Trebuchet MS"//"Arial Unicode MS"
+#define HEADER_PAGENUM_FONT_SIZE 10
+#define HEADER_PAGENUM_FONT_ITALIC FALSE
+#define HEADER_PAGENUM_FONT_WEIGHT FW_SEMIBOLD//FW_MEDIUM
+#define HEADER_PAGENUM_TEXT_COLOR RGB(210,120,42)
+
+#define NAVIGATION_FONT_NAME "Arial"
+#define NAVIGATION_FONT_SIZE 9
+#define NAVIGATION_FONT_ITALIC FALSE
+#define NAVIGATION_FONT_WEIGHT FW_MEDIUM
+
+#define NAVIGATION_SEL_FONT_NAME "Arial"
+#define NAVIGATION_SEL_FONT_SIZE 10
+#define NAVIGATION_SEL_FONT_ITALIC FALSE
+#define NAVIGATION_SEL_FONT_WEIGHT FW_MEDIUM//FW_SEMIBOLD
+
+#define NAVIGATION_SEL_TEXT_COLOR RGB(252, 252, 255)
+#define NAVIGATION_TEXT_COLOR RGB(222, 225, 234)
+#define NAVIGATION_BACK_COLOR RGB(137,145,156)//RGB(150,156,163)
+#define NAVIGATION_PADDING_LEFT 0
+#define NAVIGATION_PADDING_RIGHT 0
+
+#define PAGE_BACK_COLOR RGB(236, 234, 232)
+
+
+typedef struct _UI
+{
+ ULONG ref;
+ HBRUSH hbPage;
+ HBRUSH hbHeader;
+ HBRUSH hbNavItemSel;
+ HBRUSH hbNavBack;
+ HFONT hfHeader;
+ HFONT hfNavItem;
+ HFONT hfNavItemSel;
+ HFONT hfHeaderPageNum;
+ INT nHdrTxtHeight;
+ INT nHdrPageTxtHeight;
+ INT nNavTxtHeight;
+ INT nNavTxtSelHeight;
+ INT nHdrHeight;
+ INT nNavItemHeight;
+ COLORREF rgbPageBk;
+} UI;
+
+typedef struct _SPTHEME
+{
+ WNDPROC fnOldProc;
+ UI *pui;
+ BOOL bUnicode;
+} SPTHEME;
+
+static WASetup *g_pAttachInstance = NULL;
+static BOOL bUseMarquee = -1;
+
+static INT_PTR WINAPI AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static INT_PTR WINAPI JobStatusDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static INT_PTR WINAPI ErrorPageDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT WINAPI PageWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static INT ConvertFontHeight(HWND hwnd, INT ptHeight);
+static DWORD GetHighestFontQuality(void);
+static BOOL InitializeUI(UI *pui, HWND hwndCtrl);
+static BOOL ReleaseUI(UI *pui);
+static const wchar_t *GetUnknownStr(void);
+static LRESULT WINAPI FrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL JobStatus_Advance(HWND hwndStatus);
+
+WASetup::WASetup(void)
+ : ref((size_t)1), hwnd(NULL), hwndActive(NULL), nPageActive((size_t)-1), pui(NULL), hWinamp(NULL)
+{
+}
+
+WASetup::~WASetup(void)
+{
+ if (hwnd && IsWindow(hwnd)) DestroyWindow(hwnd);
+ size_t index;
+ index = pageList.size();
+ while(index--)
+ {
+ pageList[index]->Release();
+ }
+
+ index = jobList.size();
+ while(index--)
+ {
+ jobList[index]->Release();
+ }
+}
+svc_setup *WASetup::CreateInstance()
+{
+ WASetup *instance = new WASetup();
+ return (svc_setup*)instance;
+}
+
+int WASetup::AddRef(void)
+{
+ return ++ref;
+}
+
+int WASetup::Release(void)
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+
+HRESULT WASetup::InsertPage(ifc_setuppage *pPage, int* pIndex)
+{
+ size_t index;
+ if (!pIndex || !pPage) return E_INVALIDARG;
+
+ index = *pIndex;
+ if (index >= pageList.size())
+ {
+ index = pageList.size();
+ pageList.push_back(pPage);
+ }
+ else
+ {
+ //pageList.insertBefore(*pIndex, pPage);
+ pageList.insert(pageList.begin() + index, pPage);
+ }
+
+ *pIndex = (int)index;
+ pPage->AddRef();
+ return S_OK;
+}
+
+HRESULT WASetup::RemovePage(size_t index)
+{
+ if (index >= pageList.size())
+ return HRESULT_FROM_WIN32(ERROR_INVALID_INDEX);
+ pageList[index]->Release();
+ pageList.erase(pageList.begin() + index);
+ return S_OK;
+}
+
+HRESULT WASetup::GetPageCount(int *pCount)
+{
+ if (!pCount) return E_INVALIDARG;
+ *pCount = (int)pageList.size();
+ return S_OK;
+}
+
+HRESULT WASetup::GetPage(size_t index, ifc_setuppage **pPage)
+{
+ if (index >= pageList.size()) return HRESULT_FROM_WIN32(ERROR_INVALID_INDEX);
+ *pPage = pageList[index];
+ return S_OK;
+}
+
+HRESULT WASetup::AddJob(ifc_setupjob *pJob)
+{
+ for (size_t i = 0; i < jobList.size(); i++)
+ {
+ if (jobList[i] == pJob) return S_OK;
+ }
+ jobList.push_back(pJob);
+ pJob->AddRef();
+ return S_OK;
+}
+
+HRESULT WASetup::RemoveJob(ifc_setupjob *pJob)
+{
+ for (size_t i = 0; i < jobList.size(); i++)
+ {
+ if (jobList[i] == pJob)
+ {
+ jobList[i]->Release();
+ jobList.erase(jobList.begin() + i);
+ return S_OK;
+ }
+ }
+ return E_INVALIDARG;
+}
+
+HRESULT WASetup::GetActiveIndex(int* pIndex)
+{
+ if (!pIndex) return E_INVALIDARG;
+ *pIndex = (int)nPageActive;
+ return S_OK;
+}
+
+HRESULT WASetup::CreateStatusWnd(HWND *phwndStatus)
+{
+ HWND hwndStatus;
+
+ if (!phwndStatus) return S_FALSE;
+ *phwndStatus = NULL;
+
+ if (-1 == bUseMarquee)
+ {
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ bUseMarquee = (GetVersionEx(&vi) && (vi.dwMajorVersion > 5 || (vi.dwMajorVersion == 5 && vi.dwMinorVersion > 0)));
+ }
+
+ hwndStatus = WACreateDialog(MAKEINTRESOURCEW(IDD_SETUPSTATUS), NULL, JobStatusDialog);
+ if (!hwndStatus) return S_FALSE;
+
+ if (rcUI.right != rcUI.left)
+ {
+ RECT rw;
+ GetWindowRect(hwndStatus, &rw);
+ SetWindowPos(hwndStatus, NULL, rcUI.left + ((rcUI.right - rcUI.left) - (rw.right - rw.left))/2,
+ rcUI.top + ((rcUI.bottom - rcUI.top) - (rw.bottom - rw.top))/2, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+
+ HWND hwndCtrl = GetDlgItem(hwndStatus, IDC_PROGRESS);
+ if (hwndCtrl)
+ {
+ if (bUseMarquee)
+ {
+ SetWindowLongPtrW(hwndCtrl, GWL_STYLE, GetWindowLongPtrW(hwndCtrl, GWL_STYLE) | 0x08/*PBS_MARQUEE*/);
+ SendMessageW(hwndCtrl, (WM_USER + 10)/*PBM_SETMARQUEE*/, TRUE, (LPARAM)200);
+ }
+ else
+ {
+ SendMessageW(hwndCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 1 + (INT)(pageList.size() + jobList.size())));
+ SendMessageW(hwndCtrl, PBM_SETPOS, 0, 0L);
+ SendMessageW(hwndCtrl, PBM_SETSTEP, 1, 0L);
+ }
+ }
+
+ *phwndStatus = hwndStatus;
+ return S_OK;
+}
+
+static BOOL WaSetup_MessageLoop(HWND hMainWnd, HACCEL hAccel)
+{
+ MSG msg;
+
+ for (;;)
+ {
+ DWORD status = MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+ if (WAIT_OBJECT_0 == status)
+ {
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ //if (!CallMsgFilter(&msg, MSGF_DIALOGBOX))
+ {
+ if (msg.message == WM_QUIT)
+ return (BOOL)msg.wParam;
+
+ if (!TranslateAcceleratorW(hMainWnd, hAccel, &msg) &&
+ !IsDialogMessageW(hMainWnd, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ }
+ }
+ }
+ }
+}
+
+HRESULT WASetup::Start(HWND hwndWinamp)
+{
+ INT_PTR r(IDOK);
+
+ SetRectEmpty(&rcUI);
+
+ hWinamp = hwndWinamp;
+
+ if (pageList.size())
+ {
+ HACCEL hAccel;
+ static UI ui = {0, };
+
+ for (size_t i = 0; i < pageList.size(); i++) pageList[i]->Revert();
+ g_pAttachInstance = this;
+
+ InitializeUI(&ui, hwnd);
+ pui = &ui;
+
+ hwnd = WACreateDialog(MAKEINTRESOURCEW(IDD_SETUP), NULL, ::DialogProc);
+ if (!hwnd) return E_UNEXPECTED;
+ HINSTANCE hInst = (language_pack_instance) ? language_pack_instance : hMainInstance;
+ hAccel = LoadAcceleratorsW(hInst, MAKEINTRESOURCEW(IDR_ACCEL_SETUP));
+
+ r = WaSetup_MessageLoop(hwnd, hAccel);
+
+ g_pAttachInstance = NULL;
+ ReleaseUI(&ui);
+ }
+
+ return (IDOK == r) ? S_OK : S_FALSE;
+}
+
+HRESULT WASetup::Save(HWND hwndStatus)
+{
+ HRESULT hr(S_OK);
+ HWND hwndText = GetDlgItem(hwndStatus, IDC_LBL_STATUS);
+ for (size_t i = 0; i < pageList.size(); i++)
+ {
+ if (hwndText) SetWindowTextW(hwndText, getStringW(IDS_STATUS_SAVING, NULL, 0));
+ if (S_OK != pageList[i]->Save(hwndText)) hr = S_FALSE;
+ JobStatus_Advance(hwndStatus);
+ }
+ WritePrivateProfileStringW(L"WinampReg", L"WAVer", AutoWide(APP_VERSION), INI_FILE);
+ return hr;
+}
+HRESULT WASetup::ExecJobs(HWND hwndStatus)
+{
+ HRESULT hr(S_OK);
+ HWND hwndText = GetDlgItem(hwndStatus, IDC_LBL_STATUS);
+ HWND hwndBtn = GetDlgItem(hwndStatus, IDC_BTN_SKIP);
+ for (size_t i = 0; i < jobList.size(); i++)
+ {
+ if (hwndText) SetWindowTextW(hwndText, getStringW(IDS_STATUS_JOBS, NULL, 0));
+ if (hwndBtn && S_OK == jobList[i]->IsCancelSupported() &&
+ SetPropW(hwndStatus, L"JOB", (HANDLE)jobList[i]))
+ {
+ EnableWindow(hwndBtn, TRUE);
+ }
+
+ if (S_OK != jobList[i]->Execute(hwndText)) hr = S_FALSE;
+ if (hwndBtn) EnableWindow(hwndBtn, FALSE);
+ JobStatus_Advance(hwndStatus);
+ }
+
+ return hr;
+}
+
+HRESULT WASetup::GetWinampWnd(HWND *phwndWinamp)
+{
+ if (NULL == phwndWinamp)
+ return E_INVALIDARG;
+ *phwndWinamp = hWinamp;
+ return (NULL == hWinamp) ? E_UNEXPECTED : S_OK;
+}
+
+static INT_PTR CALLBACK tmpProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+INT_PTR WASetup::OnInitDialog(HWND hwndFocused, LPARAM lParam)
+{
+ HWND hwndLB, hwndFrame, hwndHeader;
+ RECT rw, rc;
+ HICON hIcon = LoadIconW(hMainInstance, MAKEINTRESOURCE(ICON_XP));
+
+ // make other people's dialogs show the winamp icon
+ HWND h = CreateDialogW(hMainInstance, MAKEINTRESOURCE(IDD_OPENLOC), NULL, tmpProc);
+ SetClassLongPtrW(h, GCLP_HICON, (LONG_PTR)hIcon);
+ DestroyWindow(h);
+
+ SendMessageW(hwnd, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwnd, IDC_BTN_NEXT), TRUE);
+
+ wchar_t buf[256] = {0};
+ StringCchPrintfW(buf,256, getStringW(IDS_SETUP_WND_TITLE,NULL,0), AutoWideDup(app_version_string));
+ SetWindowTextW(hwnd, buf);
+
+ // adjust dialog
+ rw.left = GetPrivateProfileIntW(L"SETUP", L"left", 0, INI_FILE);
+ rw.top = GetPrivateProfileIntW(L"SETUP", L"top", 0, INI_FILE);
+ rw.right = GetPrivateProfileIntW(L"SETUP", L"right", 0, INI_FILE);
+ rw.bottom = GetPrivateProfileIntW(L"SETUP", L"bottom", 0, INI_FILE);
+
+ if (rw.left != rw.right && rw.top != rw.bottom)
+ {
+ INT x, y;
+ GetWindowRect(hwnd, &rc);
+ x = (rw.right) ? (rw.left + ((rw.right - rw.left) - (rc.right - rc.left))/2) : rw.left;
+ y = (rw.bottom) ? (rw.top + ((rw.bottom - rw.top) - (rc.bottom - rc.top))/2) : rw.top;
+ SetWindowPos(hwnd, NULL, x, y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+
+ hwndFrame = GetDlgItem(hwnd, IDC_FRAME);
+
+ // TODO if this is needed again then remove
+ // deletes the 'Tools' menu as it's not used
+ DeleteMenu(GetMenu(hwnd), 2, MF_BYPOSITION);
+ DrawMenuBar(hwnd);
+
+ WNDPROC fnOldProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwndFrame, GWLP_WNDPROC, (LONG_PTR)FrameWndProc);
+ if (fnOldProc) SetPropW(hwndFrame, L"SKINFRAME", fnOldProc);
+
+ SetWindowLongPtrW(hwndFrame, GWL_STYLE, GetWindowLongPtrW(hwndFrame, GWL_STYLE) | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
+ if (!IsWinXPTheme()) SetWindowLongPtrW(hwndFrame, GWL_EXSTYLE, (GetWindowLongPtrW(hwndFrame, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE) | WS_EX_STATICEDGE);
+ SetWindowPos(hwndFrame, HWND_BOTTOM, 0,0,0,0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
+
+ GetClientRect(hwndFrame, &rc);
+ MapWindowPoints(hwndFrame, hwnd, (POINT*)&rc, 2);
+
+ hwndLB = GetDlgItem(hwnd, IDC_LB_NAVIGATION);
+ if (hwndLB)
+ {
+ GetWindowRect(hwndLB, &rw);
+ SetWindowPos(hwndLB, GetDlgItem(hwnd, IDC_BTN_BACK), rc.left, rc.top, rw.right - rw.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+ SendMessageW(hwndLB, WM_SETFONT, (WPARAM)pui->hfNavItem, FALSE);
+ }
+
+ hwndHeader = GetDlgItem(hwnd, IDC_HEADER);
+ if (hwndHeader)
+ {
+ SendMessageW(hwndHeader, WM_SETFONT, (WPARAM)pui->hfHeader, FALSE);
+ GetWindowRect(hwndLB, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ SetWindowPos(hwndHeader, NULL, rw.right, rc.top, rc.right - rw.right, pui->nHdrHeight, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
+ }
+
+ if (hwndLB)
+ {
+ for (size_t i = 0; i < pageList.size(); i++) SendMessageW(hwndLB, LB_ADDSTRING, 0, (LPARAM)i);
+ SendMessageW(hwndLB, LB_SETCURSEL, 0, 0L);
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_LB_NAVIGATION, LBN_SELCHANGE), (LPARAM)hwndLB);
+ }
+
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ DWORD ourThreadID, foregroundThreadID;
+ foregroundThreadID = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
+ ourThreadID = GetCurrentThreadId();
+
+ if (foregroundThreadID != ourThreadID) AttachThreadInput(foregroundThreadID, ourThreadID, TRUE);
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ if (foregroundThreadID != ourThreadID) AttachThreadInput(foregroundThreadID, ourThreadID, FALSE);
+
+ return 0;
+}
+
+void WASetup::OnDestroy(void)
+{
+ GetWindowRect(hwnd, &rcUI);
+}
+
+void WASetup::OnCancel(void)
+{
+ BOOL bNeedSave = FALSE;
+ WCHAR szTitle[128] = {0};
+
+ for (size_t i = 0; i < pageList.size() && !bNeedSave; i++)
+ {
+ bNeedSave = (S_FALSE != pageList[i]->IsDirty());
+ }
+
+ GetWindowTextW(hwnd, szTitle, sizeof(szTitle)/sizeof(WCHAR));
+ if (bNeedSave)
+ {
+ INT nr = MessageBoxW(hwnd, getStringW(IDS_SAVE_CHANGES_BEFORE_EXIT, NULL, 0), szTitle, MB_YESNOCANCEL | MB_ICONWARNING);
+ switch(nr)
+ {
+ case IDYES: SendMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDM_FILE_SAVECHANGES, 0), 0L); break;
+ case IDCANCEL: return;
+ }
+ }
+ else if (IDNO == MessageBoxW(hwnd, getStringW(IDS_QUIT_OK, NULL, 0), szTitle, MB_YESNO | MB_ICONWARNING)) return;
+
+ DestroyWindow(hwnd);
+ PostQuitMessage(IDCANCEL);
+}
+
+void WASetup::OnNext_Clicked(HWND hwndCtrl)
+{
+ HWND hwndLB = GetDlgItem(hwnd, IDC_LB_NAVIGATION);
+ INT index = (INT)SendMessageW(hwndLB, LB_GETCURSEL, 0, 0L) + 1;
+ if (index > -1) SendMessageW(hwndLB, LB_SETCURSEL, (WPARAM)index, 0L);
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_LB_NAVIGATION, LBN_SELCHANGE), (LPARAM)hwndLB);
+}
+
+void WASetup::OnBack_Clicked(HWND hwndCtrl)
+{
+ HWND hwndLB = GetDlgItem(hwnd, IDC_LB_NAVIGATION);
+ INT index = (INT)SendMessageW(hwndLB, LB_GETCURSEL, 0, 0L) -1;
+ if (index > -1) SendMessageW(hwndLB, LB_SETCURSEL, (WPARAM)index, 0L);
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_LB_NAVIGATION, LBN_SELCHANGE), (LPARAM)hwndLB);
+}
+
+void WASetup::OnNavigation_SelChange(HWND hwndCtrl)
+{
+ HWND hwndFrame;
+ HMENU hMenu;
+ MENUITEMINFO mii;
+
+ INT idList[] = { IDC_BTN_BACK, IDC_BTN_NEXT};
+ INT count = (INT)SendMessageW(hwndCtrl, LB_GETCOUNT, 0, 0L);
+ INT index = (INT)SendMessageW(hwndCtrl, LB_GETCURSEL, 0, 0L);
+
+ if (nPageActive == (size_t)index) return;
+
+ if (-1 != nPageActive && S_FALSE == pageList[nPageActive]->Validate())
+ {
+ SendMessageW(hwndCtrl, LB_SETCURSEL, nPageActive, 0L);
+ return;
+ }
+
+ hwndFrame = GetDlgItem(hwnd, IDC_FRAME);
+ hMenu = GetMenu(hwnd);
+
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_STATE;
+
+ for(int i = sizeof(idList)/sizeof(int) - 1; i >= 0 ; i--)
+ {
+ HWND hwndBtn = GetDlgItem(hwnd, idList[i]);
+ BOOL bEnable = (IDC_BTN_NEXT == idList[i]) ? ((count - index) > 1) : (0 != index);
+ if (hwndBtn)
+ {
+ if (bEnable != IsWindowEnabled(hwndBtn))
+ {
+ if (IDC_BTN_NEXT == idList[i]) SendMessageW(hwnd, DM_SETDEFID, (WPARAM)((bEnable) ? IDC_BTN_NEXT : IDOK), 0L);
+ EnableWindow(hwndBtn, bEnable);
+ }
+
+ if (hMenu)
+ {
+ mii.fState = (bEnable) ? MFS_ENABLED : MFS_DISABLED;
+ SetMenuItemInfoW(hMenu, (IDC_BTN_NEXT == idList[i]) ? IDM_NAVIGATE_NEXT : IDM_NAVIGATE_BACK, FALSE, &mii);
+ }
+ }
+ }
+
+ if (hwndActive)
+ {
+ DestroyWindow(hwndActive);
+ hwndActive = NULL;
+ nPageActive = (size_t)-1;
+ }
+
+ if (S_OK != pageList[index]->CreateView(hwnd, &hwndActive))
+ hwndActive = WACreateDialog(MAKEINTRESOURCEW(IDD_SETUP_PAGE_ERROR), hwnd, ErrorPageDialog);
+
+ HWND hwndHeader;
+ RECT rc;
+ GetClientRect(hwndFrame, &rc);
+ MapWindowPoints(hwndFrame, hwnd, (POINT*)&rc, 2);
+
+ hwndHeader = GetDlgItem(hwnd, IDC_HEADER);
+ if (hwndHeader && (WS_VISIBLE & GetWindowLongPtrW(hwndHeader, GWL_STYLE)))
+ {
+ RECT rw;
+ GetWindowRect(hwndHeader, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ rc.top = rw.bottom;
+ rc.left = rw.left;
+ }
+
+ SetWindowPos(hwndActive, GetDlgItem(hwnd, IDC_LB_NAVIGATION), rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE);
+
+ if(IsWinXPTheme()) WAEnableThemeDialogTexture(hwndActive, ETDT_ENABLETAB);
+ else
+ {
+ SPTHEME *pTheme = (SPTHEME*)malloc(sizeof(SPTHEME));
+ pTheme->bUnicode = IsWindowUnicode(hwndActive);
+ pTheme->pui = pui;
+ pTheme->fnOldProc = (WNDPROC)SetWindowLongPtrW(hwndActive, GWLP_WNDPROC, (LONG_PTR)PageWndProc);
+ if (!pTheme->fnOldProc || !SetPropW(hwndActive, L"SPTHEME", pTheme))
+ {
+ if (pTheme->fnOldProc) SetWindowLongPtrW(hwndActive, GWLP_WNDPROC, (LONG_PTR)pTheme->fnOldProc);
+ free(pTheme);
+ }
+ }
+ ShowWindow(hwndActive, SW_SHOW);
+ nPageActive = index;
+
+ if (hwndHeader) InvalidateRect(hwndHeader, NULL, FALSE);
+
+ HWND hwndTest = GetNextDlgTabItem(hwnd, GetWindow(hwndActive, GW_HWNDPREV), FALSE);
+ if (hwndTest) SendMessageW(hwnd, WM_NEXTDLGCTL, (WPARAM)hwndTest, TRUE);
+}
+
+void WASetup::OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl)
+{
+ switch(nCtrlID)
+ {
+ case IDOK:
+ if (BN_CLICKED == nEvntID)
+ {
+ if (-1 != nPageActive && S_FALSE != pageList[nPageActive]->Validate())
+ {
+ DestroyWindow(hwnd);
+ PostQuitMessage(IDOK);
+ }
+ }
+ break;
+ case IDCANCEL: if (BN_CLICKED == nEvntID) OnCancel(); break;
+ case IDC_BTN_NEXT: if (BN_CLICKED == nEvntID) OnNext_Clicked(hwndCtrl); break;
+ case IDC_BTN_BACK: if (BN_CLICKED == nEvntID) OnBack_Clicked(hwndCtrl); break;
+
+ case IDC_LB_NAVIGATION:
+ switch(nEvntID)
+ {
+ case LBN_SELCHANGE: OnNavigation_SelChange(hwndCtrl); break;
+ }
+ break;
+
+ case IDM_HELP_ABOUT: WADialogBox(MAKEINTRESOURCEW(IDD_ABOUT), hwnd, AboutDialogProc); break;
+ case IDM_NAVIGATE_BACK: SendMessageW(GetDlgItem(hwnd, IDC_BTN_BACK), BM_CLICK, 0, 0L); break;
+ case IDM_NAVIGATE_NEXT: SendMessageW(GetDlgItem(hwnd, IDC_BTN_NEXT), BM_CLICK, 0, 0L); break;
+ case IDM_FILE_EXIT: OnCancel(); break;
+ case IDM_FILE_SAVECHANGES:
+ if (S_OK != Save(NULL))
+ {
+ WCHAR szTitle[128] = {0}, szText[256] = {0};
+ GetWindowTextW(hwnd, szTitle, sizeof(szTitle)/sizeof(WCHAR));
+ MessageBoxW(hwnd, getStringW(IDS_CHANGES_NOT_SAVED, szText, sizeof(szText)/sizeof(wchar_t)), szTitle, MB_OK | MB_ICONERROR);
+ }
+ break;
+ }
+}
+
+void WASetup::OnDrawHeader(DRAWITEMSTRUCT *pdis)
+{
+ const wchar_t *pszName;
+ RECT ri, re;
+ INT top;
+
+ CopyRect(&ri, &pdis->rcItem);
+ CopyRect(&re, &ri);
+ re.right = ri.left + 1;
+
+ FillRect(pdis->hDC, &re, (HBRUSH)GetStockObject(WHITE_BRUSH));
+
+ ri.left = re.right;
+ SetBrushOrgEx(pdis->hDC, ri.left, ri.top, NULL);
+ FillRect(pdis->hDC, &ri, pui->hbHeader);
+
+ if (nPageActive >= pageList.size() || S_OK != pageList[nPageActive]->GetName(FALSE, &pszName) || !*pszName) pszName = GetUnknownStr();
+
+ SetBkMode(pdis->hDC, TRANSPARENT);
+
+ InflateRect(&ri, -4, -2);
+
+ top = ri.top + (ri.bottom - ri.top - pui->nHdrTxtHeight)/2 - 1;
+ if (top > ri.top) ri.top = top;
+
+ if (ri.left < ri.right)
+ {
+ RECT rn;
+ wchar_t szPageInfo[64] = {0};
+ CopyRect(&rn, &ri);
+ SetTextColor(pdis->hDC, HEADER_PAGENUM_TEXT_COLOR);
+ UINT oldMode = SetTextAlign(pdis->hDC, TA_RIGHT);
+ HFONT hfOld = (pui->hfHeaderPageNum) ? (HFONT)SelectObject(pdis->hDC, pui->hfHeaderPageNum) : NULL;
+ top = ri.top + pui->nHdrTxtHeight - pui->nHdrPageTxtHeight;
+ if (top > rn.top) rn.top = top;
+ rn.right -= 8;
+ rn.left = rn.right - 42;
+ StringCchPrintfW(szPageInfo, sizeof(szPageInfo)/sizeof(wchar_t), L"%d/%d", nPageActive + 1, pageList.size());
+ ExtTextOutW(pdis->hDC, rn.right, rn.top, ETO_CLIPPED, &rn, szPageInfo, lstrlenW(szPageInfo), NULL);
+
+ SetTextAlign(pdis->hDC, oldMode);
+ if (hfOld) SelectObject(pdis->hDC, hfOld);
+ ri.right = rn.left -= 4;
+ }
+
+ if (ri.left < ri.right)
+ {
+ SetTextColor(pdis->hDC, HEADER_TEXT_COLOR);
+ SetTextAlign(pdis->hDC, TA_LEFT);
+ ExtTextOutW(pdis->hDC, ri.left, ri.top, ETO_CLIPPED, &ri, pszName, lstrlenW(pszName), NULL);
+ }
+}
+
+void WASetup::OnDrawNavigationItem(DRAWITEMSTRUCT *pdis)
+{
+ const wchar_t *pszName;
+ RECT ri;
+ HFONT hfOld;
+ wchar_t szTitle[128] = {0};
+ COLORREF rgbText;
+
+ if (pdis->itemID == -1) return;
+
+ CopyRect(&ri, &pdis->rcItem);
+ ri.left += NAVIGATION_PADDING_LEFT;
+ ri.right -= NAVIGATION_PADDING_RIGHT;
+
+ if (ODA_FOCUS == pdis->itemAction)
+ {
+ if (0 == (0x0200/*ODS_NOFOCUSRECT*/ & pdis->itemState))
+ {
+ InflateRect(&ri, -1, -1);
+ DrawFocusRect(pdis->hDC, &ri);
+ }
+ return;
+ }
+
+ if (ODS_SELECTED & pdis->itemState)
+ {
+ HBRUSH hbActive;
+ if (pui->hbNavItemSel)
+ {
+ SetBrushOrgEx(pdis->hDC, ri.left, ri.top, NULL);
+ hbActive = pui->hbNavItemSel;
+ }
+ else
+ {
+ SetBrushOrgEx(pdis->hDC, 0, 0, NULL);
+ hbActive = pui->hbNavBack;
+ }
+ FillRect(pdis->hDC, &ri, hbActive);
+ rgbText = SetTextColor(pdis->hDC, NAVIGATION_SEL_TEXT_COLOR);
+ hfOld = (HFONT)SelectObject(pdis->hDC, pui->hfNavItemSel);
+ }
+ else
+ {
+ if (ODA_SELECT == pdis->itemAction)
+ {
+ SetBrushOrgEx(pdis->hDC, 0, 0, NULL);
+ FillRect(pdis->hDC, &ri, pui->hbNavBack);
+ }
+ rgbText = 0;
+ hfOld = NULL;
+ }
+
+ if (pdis->itemData >= pageList.size() || S_OK != pageList[pdis->itemData]->GetName(TRUE, &pszName) || !*pszName)
+ pszName = GetUnknownStr();
+
+ SetBkMode(pdis->hDC, TRANSPARENT);
+
+ InflateRect(&ri, -4, -2);
+ INT top = ri.top + (ri.bottom - ri.top - pui->nNavTxtHeight)/2 - 1;
+ if (top > ri.top) ri.top = top;
+
+ StringCchPrintfW(szTitle, sizeof(szTitle)/sizeof(wchar_t), L"%d. %s", pdis->itemData + 1, pszName);
+ ExtTextOutW(pdis->hDC, ri.left, ri.top, ETO_CLIPPED, &ri, szTitle, lstrlenW(szTitle), NULL);
+
+ if (ODS_SELECTED & pdis->itemState)
+ {
+ SetTextColor(pdis->hDC, rgbText);
+ if (hfOld) SelectObject(pdis->hDC, hfOld);
+ }
+}
+
+INT_PTR WASetup::OnDrawItem(INT nCtrlID, DRAWITEMSTRUCT *pdis)
+{
+ switch(nCtrlID)
+ {
+ case IDC_HEADER: OnDrawHeader(pdis); return TRUE;
+ case IDC_LB_NAVIGATION: OnDrawNavigationItem(pdis); return TRUE;
+ }
+ return 0;
+}
+
+INT_PTR WASetup::OnMeasureItem(INT nCtrlID, MEASUREITEMSTRUCT *pmis)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_NAVIGATION:
+ pmis->itemHeight = (pui) ? pui->nNavItemHeight : 0;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+INT_PTR WASetup::OnColorListBox(HDC hdc, HWND hwndCtrl)
+{
+ if (hwndCtrl == GetDlgItem(hwnd, IDC_LB_NAVIGATION))
+ {
+
+ SetTextColor(hdc, NAVIGATION_TEXT_COLOR);
+ SetBkColor(hdc, NAVIGATION_BACK_COLOR);
+ return (INT_PTR)pui->hbNavBack;
+ }
+ return NULL;
+}
+
+INT_PTR WASetup::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ INT_PTR result = 0;
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam);
+ case WM_DESTROY: OnDestroy(); break;
+ case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ case WM_DRAWITEM: result = OnDrawItem((INT)wParam, (DRAWITEMSTRUCT*)lParam); break;
+ case WM_MEASUREITEM: result = OnMeasureItem((INT)wParam, (MEASUREITEMSTRUCT*)lParam); break;
+ case WM_CTLCOLORLISTBOX: return OnColorListBox((HDC)wParam, (HWND)lParam);
+ case WM_CHAR:
+ if (0x30 == wParam)
+ {
+ OutputDebugStringA("test\n");
+ return 0;
+ }
+ }
+
+ if (result)
+ {
+ SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (LONG_PTR)result);
+ return TRUE;
+ }
+
+ return 0;
+}
+
+static INT_PTR WINAPI DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WASetup *pInst = (WASetup*)GetPropW(hwndDlg, L"SETUPDLG");
+ if (!pInst && g_pAttachInstance)
+ {
+ pInst = g_pAttachInstance;
+ pInst->hwnd = hwndDlg;
+ SetPropW(hwndDlg, L"SETUPDLG", pInst);
+ g_pAttachInstance = NULL;
+ }
+
+ switch(uMsg)
+ {
+ case WM_DESTROY:
+ if (pInst)
+ {
+ pInst->DialogProc(uMsg, wParam, lParam);
+ RemovePropW(hwndDlg, L"SETUPDLG");
+ pInst = NULL;
+ }
+ break;
+ }
+
+ return (pInst) ? pInst->DialogProc(uMsg, wParam, lParam) : 0;
+}
+
+static INT_PTR WINAPI AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SendDlgItemMessageW(hwndDlg, IDC_PIC_ABOUT, STM_SETIMAGE, IMAGE_BITMAP,
+ (LPARAM)WALoadImage2(L"PNG", MAKEINTRESOURCEW(IDB_ABOUT), FALSE));
+
+ wchar_t buf[2048] = {0}, buf2[2048] = {0};
+ GetWindowTextW(GetDlgItem(hwndDlg,IDC_VER_TEXT),buf,ARRAYSIZE(buf));
+ StringCchPrintfW(buf2,2048,(buf[0] ? buf : L"v%s %s - %s"),AutoWideDup(app_version_string),AutoWideDup(APP_VERSION_PLATFORM),AutoWideDup(app_date));
+ SetWindowTextW(GetDlgItem(hwndDlg,IDC_VER_TEXT),buf2);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ DeleteObject((HBITMAP)SendDlgItemMessageW(hwndDlg, IDC_PIC_ABOUT, STM_GETIMAGE, IMAGE_BITMAP, 0L));
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hwndDlg, 0);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static INT_PTR WINAPI JobStatusDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDC_BTN_SKIP:
+ if (BN_CLICKED == HIWORD(wParam))
+ {
+ ifc_setupjob *pj = (ifc_setupjob*)GetPropW(hwndDlg, L"JOB");
+ if (pj)
+ {
+ HWND hwndStatus = GetDlgItem(hwndDlg, IDC_LBL_STATUS);
+ EnableWindow((HWND)lParam, FALSE);
+ if (hwndStatus) SetWindowTextW(hwndStatus, getStringW(IDS_HTTP_ABORT, NULL, 0));
+ pj->Cancel(hwndStatus);
+ }
+ }
+ break;
+ }
+ case WM_DESTROY:
+ RemovePropW(hwndDlg, L"JOB");
+ }
+
+ return 0;
+}
+
+static INT_PTR WINAPI ErrorPageDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_WINDOWPOSCHANGED:
+ if (SWP_NOSIZE != ((SWP_NOSIZE | SWP_FRAMECHANGED) & ((WINDOWPOS*)lParam)->flags))
+ {
+ HWND messageWindow;
+ messageWindow = GetDlgItem(hwndDlg, IDC_LBL_MESSAGE);
+ if (NULL != messageWindow)
+ {
+ RECT rect;
+ long top;
+
+ GetWindowRect(messageWindow, &rect);
+ MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT*)&rect, 1);
+
+ top = rect.top;
+
+ GetClientRect(hwndDlg, &rect);
+ rect.top = top;
+
+ SetWindowPos(messageWindow, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static LRESULT WINAPI PageWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ SPTHEME *pTheme = (SPTHEME*)GetPropW(hwnd, L"SPTHEME");
+ if (!pTheme || !pTheme->fnOldProc) return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+
+ switch(uMsg)
+ {
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORSTATIC:
+ SetBkColor((HDC)wParam, PAGE_BACK_COLOR);
+ SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT));
+ return (LRESULT)pTheme->pui->hbPage;
+ case WM_DESTROY:
+ {
+ WNDPROC fnOldProc = pTheme->fnOldProc;
+ RemovePropA(hwnd, "SPTHEME");
+ free(pTheme);
+ SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)fnOldProc);
+ return CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam);
+ }
+ }
+
+ return (pTheme->bUnicode) ? CallWindowProcW(pTheme->fnOldProc, hwnd, uMsg, wParam, lParam) :
+ CallWindowProcA(pTheme->fnOldProc, hwnd, uMsg, wParam, lParam);
+}
+
+static DWORD GetHighestFontQuality(void)
+{
+ DWORD fdwQuality;
+ BOOL bSmoothing;
+
+ if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &bSmoothing, 0) && bSmoothing)
+ {
+ OSVERSIONINFO vi = { sizeof(OSVERSIONINFO), };
+ fdwQuality = (GetVersionEx(&vi) && (vi.dwMajorVersion > 5 || (vi.dwMajorVersion == 5 && vi.dwMinorVersion > 0))) ?
+ 5/*CLEARTYPE_QUALITY*/ : ANTIALIASED_QUALITY;
+ }
+ else fdwQuality = DEFAULT_QUALITY;
+
+ return fdwQuality;
+}
+
+static BOOL InitializeUI(UI *pui, HWND hwndCtrl)
+{
+ if (!pui) return FALSE;
+ if (!pui->ref)
+ {
+ HBITMAP hbmp;
+ BITMAP bi;
+ HDC hdc;
+ INT logPx;
+ TEXTMETRIC tm;
+
+ hdc = GetWindowDC(hwndCtrl);
+ logPx = GetDeviceCaps(hdc, LOGPIXELSY);
+
+ pui->hbPage = CreateSolidBrush(PAGE_BACK_COLOR);
+
+ hbmp = (HBITMAP)LoadImageW(hMainInstance, MAKEINTRESOURCEW(IDB_NAVIGATION_STRIP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
+ if (hbmp)
+ {
+ pui->hbNavBack = CreatePatternBrush(hbmp);
+ DeleteObject(hbmp);
+ }
+ else pui->hbNavBack = CreateSolidBrush(NAVIGATION_BACK_COLOR);
+
+ pui->hfNavItem = CreateFontA(-MulDiv(NAVIGATION_FONT_SIZE, logPx, 72), 0, 0, 0, NAVIGATION_FONT_WEIGHT,
+ NAVIGATION_FONT_ITALIC, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ GetHighestFontQuality(), FF_DONTCARE, NAVIGATION_FONT_NAME);
+
+ pui->hfNavItemSel = CreateFontA(-MulDiv(NAVIGATION_SEL_FONT_SIZE, logPx, 72), 0, 0, 0, NAVIGATION_SEL_FONT_WEIGHT,
+ NAVIGATION_SEL_FONT_ITALIC, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ GetHighestFontQuality(), FF_DONTCARE, NAVIGATION_SEL_FONT_NAME);
+
+ pui->hfHeader = CreateFontA(-MulDiv(HEADER_FONT_SIZE, logPx, 72), 0, 0, 0, HEADER_FONT_WEIGHT,
+ HEADER_FONT_ITALIC, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ GetHighestFontQuality(), FF_DONTCARE, HEADER_FONT_NAME);
+
+ pui->hfHeaderPageNum = CreateFontA(-MulDiv(HEADER_PAGENUM_FONT_SIZE, logPx, 72), 0, 0, 0, HEADER_PAGENUM_FONT_WEIGHT,
+ HEADER_PAGENUM_FONT_ITALIC, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ GetHighestFontQuality(), FF_DONTCARE, HEADER_PAGENUM_FONT_NAME);
+
+ pui->nHdrHeight = 36;
+
+ hbmp = (HBITMAP)LoadImageW(hMainInstance, MAKEINTRESOURCEW(IDB_HEADER_STRIP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
+ if (hbmp)
+ {
+ if (GetObject(hbmp, sizeof(BITMAP), &bi)) pui->nHdrHeight = bi.bmHeight;
+ pui->hbHeader = CreatePatternBrush(hbmp);
+ DeleteObject(hbmp);
+ }
+
+ pui->nNavItemHeight = 32;
+// hbmp = (HBITMAP)LoadImageW(hMainInstance, MAKEINTRESOURCEW(IDB_NAVITEM_STRIP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
+// if (hbmp)
+// {
+// if (GetObject(hbmp, sizeof(BITMAP), &bi)) pui->nNavItemHeight = bi.bmHeight;
+// pui->hbNavItemSel = CreatePatternBrush(hbmp);
+// DeleteObject(hbmp);
+// }
+
+ HFONT hfOld = (HFONT)SelectObject(hdc, pui->hfHeader);
+ GetTextMetrics(hdc, &tm);
+ pui->nHdrTxtHeight = tm.tmAscent;
+
+ SelectObject(hdc, pui->hfHeaderPageNum);
+ GetTextMetrics(hdc, &tm);
+ pui->nHdrPageTxtHeight = tm.tmAscent;
+
+ SelectObject(hdc, pui->hfNavItem);
+ GetTextMetrics(hdc, &tm);
+ pui->nNavTxtHeight = tm.tmAscent;
+
+ SelectObject(hdc, pui->hfNavItemSel);
+ GetTextMetrics(hdc, &tm);
+ pui->nNavTxtSelHeight = tm.tmAscent;
+
+ SelectObject(hdc, hfOld);
+ ReleaseDC(hwndCtrl, hdc);
+ }
+ pui->ref++;
+ return TRUE;
+}
+
+static BOOL ReleaseUI(UI *pui)
+{
+ if (!pui) return FALSE;
+ if (0 == pui->ref)
+ {
+ return TRUE;
+ }
+ if (1 == pui->ref)
+ {
+ if (pui->hbPage) DeleteObject(pui->hbPage);
+ if (pui->hbNavBack) DeleteObject(pui->hbNavBack);
+ if (pui->hbHeader) DeleteObject(pui->hbHeader);
+ if (pui->hbNavItemSel) DeleteObject(pui->hbNavItemSel);
+ if (pui->hfNavItem) DeleteObject(pui->hfNavItem);
+ if (pui->hfNavItemSel) DeleteObject(pui->hfNavItemSel);
+ if (pui->hfHeader) DeleteObject(pui->hfHeader);
+ if (pui->hfHeaderPageNum) DeleteObject(pui->hfHeaderPageNum);
+ ZeroMemory(pui, sizeof(UI));
+ return TRUE;
+ }
+ pui->ref--;
+ return TRUE;
+}
+
+static const wchar_t *GetUnknownStr(void)
+{
+ static wchar_t unknown[64] = {0,};
+ return (unknown) ? unknown : getStringW(IDS_UNKNOWN, unknown, sizeof(unknown)/sizeof(wchar_t));
+}
+
+static LRESULT WINAPI FrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC fnOldProc = (WNDPROC)GetPropW(hwnd, L"SKINFRAME");
+ if (!fnOldProc) return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ switch(uMsg)
+ {
+ case WM_DESTROY:
+ RemovePropW(hwnd, L"SKINFRAME");
+ SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)fnOldProc);
+ break;
+ case WM_PAINT:
+ ValidateRect(hwnd, NULL);
+ return 0;
+ case WM_ERASEBKGND: return 1;
+ }
+ return CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam);
+}
+
+static BOOL JobStatus_Advance(HWND hwndStatus)
+{
+ if (bUseMarquee > 0 ) return TRUE;
+ if (!hwndStatus) return FALSE;
+ HWND hwndCtrl = GetDlgItem(hwndStatus, IDC_PROGRESS);
+ if (!hwndCtrl) return FALSE;
+ SendMessageW(hwndCtrl, PBM_STEPIT, 0, 0L);
+ return TRUE;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS WASetup
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(API_SETUP_INSERT_PAGE, InsertPage)
+CB(API_SETUP_REMOVE_PAGE, RemovePage)
+CB(API_SETUP_GET_PAGE_COUNT, GetPageCount)
+CB(API_SETUP_GET_PAGE, GetPage)
+CB(API_SETUP_GET_ACTIVE_INDEX, GetActiveIndex)
+CB(API_SETUP_START, Start)
+CB(API_SETUP_ADD_JOB, AddJob)
+CB(API_SETUP_REMOVE_JOB, RemoveJob)
+CB(API_SETUP_CREATE_STATUSWND, CreateStatusWnd)
+CB(API_SETUP_SAVE, Save)
+CB(API_SETUP_EXECJOBS, ExecJobs)
+CB(API_SETUP_GETWINAMPWND, GetWinampWnd)
+END_DISPATCH
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/setup/setup.h b/Src/Winamp/setup/setup.h
new file mode 100644
index 00000000..8344bad7
--- /dev/null
+++ b/Src/Winamp/setup/setup.h
@@ -0,0 +1,66 @@
+#ifndef NULLSOFT_WINAMP_SETUP_HEADER
+#define NULLSOFT_WINAMP_SETUP_HEADER
+
+#include "./svc_setup.h"
+#include <vector>
+
+typedef struct _UI UI;
+
+class WASetup : svc_setup
+{
+protected:
+ WASetup(void);
+ ~WASetup(void);
+public:
+ static svc_setup *CreateInstance();
+public:
+ int AddRef(void);
+ int Release(void);
+ HRESULT InsertPage(ifc_setuppage *pPage, int*pIndex);
+ HRESULT RemovePage(size_t index);
+ HRESULT GetPageCount(int*pCount);
+ HRESULT GetPage(size_t index, ifc_setuppage **pPage);
+ HRESULT AddJob(ifc_setupjob *pJob);
+ HRESULT RemoveJob(ifc_setupjob *pJob);
+ HRESULT GetActiveIndex(int*pIndex);
+ HRESULT Start(HWND hwndWinamp);
+ HRESULT CreateStatusWnd(HWND *phwndStatus);
+ HRESULT Save(HWND hwndStatus);
+ HRESULT ExecJobs(HWND hwndStatus);
+ HRESULT GetWinampWnd(HWND *phwndWinamp);
+
+protected:
+ INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR OnInitDialog(HWND hwndFocused, LPARAM lParam);
+ void OnDestroy(void);
+ void OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl);
+ void OnCancel(void); // use it if you want prompt user first
+ void OnCancel_Clicked(void);
+ void OnNext_Clicked(HWND hwndCtrl);
+ void OnBack_Clicked(HWND hwndCtrl);
+ void OnNavigation_SelChange(HWND hwndCtrl);
+ INT_PTR OnDrawItem(INT nCtrlID, DRAWITEMSTRUCT *pdis);
+ INT_PTR OnMeasureItem(INT nCtrlID, MEASUREITEMSTRUCT *pmis);
+ void OnDrawHeader(DRAWITEMSTRUCT *pdis);
+ void OnDrawNavigationItem(DRAWITEMSTRUCT *pdis);
+ INT_PTR OnColorListBox(HDC hdc, HWND hwndCtrl);
+
+private:
+ int ref;
+ HWND hwnd;
+ std::vector<ifc_setuppage*> pageList;
+ std::vector<ifc_setupjob*> jobList;
+ HWND hwndActive;
+ size_t nPageActive;
+ UI *pui;
+ RECT rcUI;
+ HWND hWinamp;
+
+protected:
+ friend static INT_PTR WINAPI DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ RECVS_DISPATCH;
+
+};
+
+
+#endif //WINAMP_SETUP_WIZARD_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/setup.rc b/Src/Winamp/setup/setup.rc
new file mode 100644
index 00000000..503c2811
--- /dev/null
+++ b/Src/Winamp/setup/setup.rc
@@ -0,0 +1,446 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "setup_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "setup_resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_SETUP DIALOGEX 0, 0, 369, 214
+STYLE DS_SETFONT | DS_NOIDLEMSG | DS_SETFOREGROUND | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CENTER | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
+CAPTION "Winamp Setup"
+MENU IDR_SETUPMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LISTBOX IDC_FRAME,7,6,355,180,NOT LBS_NOTIFY | LBS_NOREDRAW | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_NODATA | LBS_NOSEL | WS_DISABLED
+ LISTBOX IDC_LB_NAVIGATION,7,6,96,180,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_DISABLED | NOT WS_BORDER | WS_TABSTOP
+ PUSHBUTTON "&Cancel",IDCANCEL,7,194,50,14
+ PUSHBUTTON "&Back",IDC_BTN_BACK,197,194,50,14
+ DEFPUSHBUTTON "&Next",IDC_BTN_NEXT,255,194,50,14
+ PUSHBUTTON "Fini&sh",IDOK,312,194,50,14
+ CONTROL "",IDC_HEADER,"Static",SS_OWNERDRAW,129,8,233,28
+END
+
+IDD_SETUP_PAGE_ASSOC DIALOGEX 0, 0, 241, 152
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Select the file types you want to be associated with Winamp.",IDC_LBL_HEADER,6,6,229,18
+ CONTROL "",IDC_TREE_TYPES,"SysTreeView32",TVS_HASBUTTONS | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,6,24,229,87
+ CONTROL "Show Winamp in the folder context menus in Windows Explorer",IDC_CHK_EXPLORER_MENU,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,115,229,10
+ CONTROL "Enable Winamp Agent",IDC_CHK_AGENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,126,229,9
+ LTEXT "Places a Winamp icon in the notification area.",IDC_LBL_AGENT_DESC,17,136,218,9
+END
+
+#if defined(APSTUDIO_INVOKED) || defined(NOT_USED)
+#if defined(APSTUDIO_INVOKED)
+IDD_SETUP_PAGE_CONNECT$(NOT_USED) DIALOGEX 0, 0, 225, 137
+#else
+IDD_SETUP_PAGE_CONNECT DIALOGEX 0, 0, 225, 137
+#endif
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Select your internet connection type:",IDC_LBL_HEADER,6,6,213,18
+ COMBOBOX IDC_CB_CONNECT,6,24,213,58,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "HTTP Proxy (Optional)",IDC_GRP_PROXY,6,49,213,82
+ EDITTEXT IDC_EDT_SERVER,16,82,193,14,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Server address (Server:Port):",IDC_LBL_SERVER,16,71,193,8
+ CONTROL "Use proxy only for port 80 URLs",IDC_CHK_PORT80,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,101,193,10
+END
+#endif
+
+IDD_SETUP_PAGE_SKIN DIALOGEX 0, 0, 257, 158
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_SYSMENU
+EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Choose the look and feel for your Winamp.",IDC_LBL_HEADER,5,6,246,8
+ LISTBOX IDC_LB_SKIN,5,24,101,126,LBS_SORT | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Preview",IDC_GRP_PREVIEW,114,22,137,128
+ CONTROL "",IDC_PIC_PREVIEW,"Static",SS_BITMAP,122,35,124,43
+ LTEXT "Name:",IDC_LBL_NAME,122,87,28,8
+ EDITTEXT IDC_EDT_NAME,150,87,96,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_TRANSPARENT
+ LTEXT "Type:",IDC_LBL_TYPE,122,98,20,8
+ EDITTEXT IDC_EDT_TYPE,150,98,96,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
+ LTEXT "Author:",IDC_LBL_AUTHOR,122,109,26,8
+ EDITTEXT IDC_EDT_AUTHOR,150,109,96,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
+ LTEXT "Version:",IDC_LBL_VERSION,122,120,27,8
+ EDITTEXT IDC_EDT_VERSION,150,120,96,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
+ PUSHBUTTON "More Info...",IDC_BTN_MOREINFO,194,133,52,13,NOT WS_VISIBLE
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 206, 54
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Winamp Setup - About"
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ CONTROL 108,IDC_PIC_ABOUT,"Static",SS_BITMAP | SS_REALSIZEIMAGE,4,4,35,32,WS_EX_TRANSPARENT
+ LTEXT "Winamp Setup Wizard",IDC_STATIC,50,4,152,8
+ LTEXT "Copyright © 1997-2023 Winamp SA",IDC_STATIC,50,15,152,9,NOT WS_GROUP
+ LTEXT "v%s %s - %s",IDC_VER_TEXT,4,42,144,8
+ DEFPUSHBUTTON "Close",IDOK,152,36,50,14
+END
+
+#if defined(APSTUDIO_INVOKED) || defined(NOT_USED)
+#if defined(APSTUDIO_INVOKED)
+IDD_SETUP_PAGE_LANG$(NOT_USED) DIALOGEX 0, 0, 160, 152
+#else
+IDD_SETUP_PAGE_LANG DIALOGEX 0, 0, 160, 152
+#endif
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Choose one of the available languages:",IDC_LBL_HEADER,6,6,148,18
+ LISTBOX IDC_LB_LANG,6,24,148,122,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+END
+#endif
+
+#if defined(APSTUDIO_INVOKED) || defined(DISABLED)
+#if defined(APSTUDIO_INVOKED)
+IDD_SETUP_PAGE_FEEDBACK$(DISABLED) DIALOGEX 0, 0, 256, 158
+#else
+IDD_SETUP_PAGE_FEEDBACK DIALOGEX 0, 0, 256, 158
+#endif
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Let us know more about you so we can continue to improve Winamp.",IDC_LBL_HEADER,5,6,245,18
+ LTEXT "Email:",IDC_LBL_EMAIL,12,36,102,12
+ EDITTEXT IDC_EDT_EMAIL,114,36,130,12,ES_AUTOHSCROLL
+ LTEXT "Zip code (US) or Country:",IDC_LBL_COUNTRY,12,51,98,12
+ EDITTEXT IDC_EDT_COUNTRY,114,51,130,12,ES_AUTOHSCROLL
+ LTEXT "Gender:",IDC_LBL_GENDER,12,67,98,12
+ COMBOBOX IDC_CB_GENDER,114,66,130,46,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Yes, send me information about Winamp",IDC_CHK_ANNOUNCEMENTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,129,232,10
+ CONTROL "Yes, allow anonymous usage statistics (recommended)",IDC_CHK_STATISTICS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,140,232,10
+END
+#endif
+
+IDD_SETUPSTATUS DIALOGEX 0, 0, 249, 71
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
+CAPTION "Winamp Setup"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LBL_STATUS,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | WS_GROUP,11,12,226,9
+ CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,11,25,226,12
+ PUSHBUTTON "Skip",IDC_BTN_SKIP,181,47,56,14,WS_DISABLED
+END
+
+IDD_SETUP_PAGE_ERROR DIALOGEX 0, 0, 316, 183
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CTEXT "Unable to load setup page",IDC_LBL_MESSAGE,5,37,304,8
+END
+
+IDD_SETUP_PAGE_ASSOC_WIN8 DIALOGEX 0, 0, 257, 152
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Select the file types you want to be associated with Winamp.",IDC_LBL_HEADER,5,6,248,18
+ LTEXT "To associate files with Winamp on this version of Windows, you need to go to 'Set Default Programs' in the Control Panel once Winamp's setup is complete.\n\nNote: This can also be accessed via Winamp's 'File Types' preferences page.",IDC_STATIC,5,24,248,32
+ CONTROL "Launch Winamp for Audio CDs",IDC_CHK_CD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,66,242,9
+ CONTROL "Show Winamp in the folder context menus in Windows Explorer",IDC_CHK_EXPLORER_MENU,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,78,242,10
+ CONTROL "Enable Winamp Agent",IDC_CHK_AGENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,90,242,9
+ LTEXT "Places a Winamp icon in the notification area.",IDC_LBL_AGENT_DESC,22,101,231,9
+ CONTROL "",IDC_TREE_TYPES,"SysTreeView32",TVS_HASBUTTONS | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | NOT WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_TABSTOP,5,144,248,0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_SETUP, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 362
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 208
+ HORZGUIDE, 186
+ END
+
+ IDD_SETUP_PAGE_ASSOC, DIALOG
+ BEGIN
+ LEFTMARGIN, 6
+ RIGHTMARGIN, 235
+ VERTGUIDE, 17
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 144
+ HORZGUIDE, 24
+ END
+
+ "IDD_SETUP_PAGE_CONNECT$(NOT_USED)", DIALOG
+ BEGIN
+ LEFTMARGIN, 6
+ RIGHTMARGIN, 219
+ VERTGUIDE, 16
+ VERTGUIDE, 209
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 131
+ HORZGUIDE, 24
+ HORZGUIDE, 49
+ HORZGUIDE, 111
+ END
+
+ IDD_SETUP_PAGE_SKIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 251
+ VERTGUIDE, 106
+ VERTGUIDE, 114
+ VERTGUIDE, 122
+ VERTGUIDE, 150
+ VERTGUIDE, 246
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 150
+ HORZGUIDE, 24
+ HORZGUIDE, 35
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 202
+ VERTGUIDE, 50
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 50
+ END
+
+ "IDD_SETUP_PAGE_LANG$(NOT_USED)", DIALOG
+ BEGIN
+ LEFTMARGIN, 6
+ RIGHTMARGIN, 154
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 146
+ HORZGUIDE, 24
+ END
+
+ IDD_SETUPSTATUS, DIALOG
+ BEGIN
+ LEFTMARGIN, 11
+ RIGHTMARGIN, 237
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 61
+ END
+
+ IDD_SETUP_PAGE_ERROR, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 309
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_SETUP_PAGE_ASSOC_WIN8, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 253
+ VERTGUIDE, 11
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 144
+ HORZGUIDE, 24
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_SETUPMENU MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Save Changes\tCtrl+S", 40013
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit\tAlt+F4", 40016
+ END
+ POPUP "Na&vigation"
+ BEGIN
+ MENUITEM "&Back\tAlt+B", 40011
+ MENUITEM "&Next\tAlt+N", 40012
+ END
+ POPUP "&Tools", GRAYED
+ BEGIN
+ MENUITEM "Migrate/Import...", 40009
+ MENUITEM "Register Winamp...", 40010
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About\tF1", 40008
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_HEADER_STRIP BITMAP "headerstrip.bmp"
+IDB_NAVITEM_STRIP BITMAP "navitemstrip.bmp"
+IDB_CHECKBOX BITMAP "checkbox.bmp"
+IDB_NAVIGATION_STRIP BITMAP "navstrip.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PNG
+//
+
+IDB_PREVIEW_NO PNG "preview_no.png"
+IDB_PREVIEW_CLASSIC PNG "preview_classic.png"
+IDB_ABOUT PNG "smokingllama.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL_SETUP ACCELERATORS
+BEGIN
+ VK_F1, IDM_HELP_ABOUT, VIRTKEY, NOINVERT
+ "S", IDM_FILE_SAVECHANGES, VIRTKEY, CONTROL, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_SKIN_CURRENT "Current"
+ IDS_SKIN_PROMO1 "Bento Skin"
+ IDS_SKIN_PROMO2 "Bento Skin (Large)"
+ IDS_PAGE_SKIN "Skin"
+ IDS_PAGE_LANGUAGE "Language"
+ IDS_PAGE_CONNECTIVITY "Connectivity"
+ IDS_SAVE_CHANGES_BEFORE_EXIT "Do you want to save changes before exit?"
+ IDS_UNKNOWN "Unknown"
+ IDS_CHANGES_NOT_SAVED "Some settings were not saved."
+ IDS_MODERN "Modern"
+ IDS_CLASSIC "Classic"
+ IDS_QUIT_OK "Are you sure you want to quit Winamp Setup?"
+ IDS_PAGE_ASSOCIATIONS "Associations"
+ IDS_FILETYPE_VIDEO "Video Files"
+ IDS_FILETYPE_AUDIO "Audio Files"
+ IDS_FILETYPE_UNKNOWN "Other Files"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_FILETYPE_PLAYLIST "Playlist Files"
+ IDS_PAGE_FEEDBACK "Feedback"
+ IDS_GENDER_MALE "Male"
+ IDS_GENDER_FEMALE "Female"
+ IDS_GENDER_UNKNOWN "Select gender"
+ IDS_REGISTER_CDPLAYER "Launch Winamp for Audio CDs"
+ IDS_STATUS_SAVING "Saving settings"
+ IDS_STATUS_JOBS "Executing scripts"
+ IDS_STATUS_RUNWA "Starting Winamp"
+ IDS_PAGE_SKIN_LONG "Choose Skin"
+ IDS_REGISTER_AGENT "Enable Winamp Agent"
+ IDS_PAGE_ASSOCIATIONS_LONG "File Associations"
+ IDS_PAGE_FEEDBACK_LONG "User Feedback"
+ IDS_PAGE_INCORRECT_EMAIL_ADDRESS "Incorrect email address."
+ IDS_FILETYPE_AUXILIARY "Winamp Specific Files"
+ IDS_WINAMP_SKIN_MODERN "Winamp Skin (Modern)"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_WINAMP_SKIN_CLASSIC "Winamp Skin (Classic)"
+ IDS_WINAMP_LANG_PACK "Winamp Language Pack"
+ IDS_DOWNLOADSTATUS_INITIALIZING "Initializing..."
+ IDS_DOWNLOADSTATUS_CONNECTING "Connecting..."
+ IDS_DOWNLOADSTATUS_CONNECTED "Connected"
+ IDS_DOWNLOADSTATUS_RECEIVING "Downloading..."
+ IDS_DOWNLOADSTATUS_RECEIVINGPERCENT "Downloading... (%d%% completed)"
+ IDS_DOWNLOADSTATUS_SUCCESS "Success."
+ IDS_DOWNLOADSTATUS_FAILED "Failed."
+ IDS_DOWNLOADSTATUS_ABORTING "Aborting..."
+ IDS_DOWNLOADSTATUS_ABORTED "Aborted."
+ IDS_SETUP_WND_TITLE "Winamp v%s Setup"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Winamp/setup/setup_api.h b/Src/Winamp/setup/setup_api.h
new file mode 100644
index 00000000..8ed8c1b6
--- /dev/null
+++ b/Src/Winamp/setup/setup_api.h
@@ -0,0 +1,24 @@
+#ifndef WINAMP_SETUP_API_HEADER
+#define WINAMP_SETUP_API_HEADER
+
+#include <windows.h>
+
+
+class __declspec(novtable) WASetupAPI
+{
+protected:
+ WASetupAPI(void){};
+ virtual ~WASetupAPI(void) = 0;
+public:
+ virtual INT GetInterfaceVersion(void) = 0;
+ virtual LPCWSTR GetName(BOOL bShort) = 0;
+ virtual HICON GetIcon(BOOL bSmall) = 0;
+ virtual BOOL Initialize(void) = 0;
+ virtual BOOL Finish(BOOL bCancelled) = 0;
+ virtual HWND CreateView(HWND hwndParent) = 0;
+ virtual HWND GetHWND(void) = 0;
+};
+
+
+
+#endif //WINAMP_SETUP_API_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/setup_resource.h b/Src/Winamp/setup/setup_resource.h
new file mode 100644
index 00000000..6e44de7a
--- /dev/null
+++ b/Src/Winamp/setup/setup_resource.h
@@ -0,0 +1,139 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by setup.rc
+//
+#define IDD_SETUP 101
+#define IDB_CHECKBOX 101
+#define IDD_SETUP_PAGE_LANG1 102
+#define IDD_SETUP_PAGE_ASSOC 102
+#define IDD_SETUP_PAGE_CONNECT 103
+#define IDD_SETUP_PAGE_SKIN 104
+#define IDD_ABOUT 105
+#define IDB_HEADERSTRIP 106
+#define IDB_HEADER_STRIP 106
+#define IDD_SETUP_PAGE_LANG 106
+#define IDD_SETUP_PAGE_FEEDBACK 107
+#define IDB_ABOUT 108
+#define IDD_SETUP_PAGE_ERROR 108
+#define IDD_SETUPSTATUS 109
+#define IDB_NAVIGATION_STRIP 110
+#define IDB_NAVITEM_STRIP 111
+#define IDB_PREVIEW_CLASSIC 112
+#define IDR_ACCEL_SETUP 112
+#define IDB_PREVIEW_NO 113
+#define IDD_SETUP_PAGE_ASSOC_WIN8 114
+#define IDR_SETUPMENU 191
+#define IDC_CB_CONNECT 1000
+#define IDC_LBL_MESSAGE 1000
+#define IDC_BTN_NEXT 1001
+#define IDC_EDT_SERVER 1001
+#define IDC_VER_TEXT 1001
+#define IDC_BTN_BACK 1002
+#define IDC_CHK_PORT80 1002
+#define IDC_LB_NAVIGATION 1003
+#define IDC_EDT_EMAIL 1003
+#define IDC_FRAME 1004
+#define IDC_GRP_PROXY 1004
+#define IDC_CHK_ANNOUNCEMENTS 1004
+#define IDC_EDT_TEST 1005
+#define IDC_LBL_SERVER 1005
+#define IDC_BTN_TEST_ME 1006
+#define IDC_TREE_TYPES 1006
+#define IDC_LBL_COUNTRY 1006
+#define IDC_HEADER 1007
+#define IDC_LBL_HEADER 1007
+#define IDC_LBL_GENDER 1008
+#define IDC_LBL_EMAIL 1011
+#define IDC_EDT_COUNTRY 1012
+#define IDC_CHK_STATISTICS 1013
+#define IDC_CHK_FEEDBACK 1014
+#define IDC_GRP_FEEDBACK 1015
+#define IDC_LB_LANG 1016
+#define IDC_CB_GENDER 1016
+#define IDC_LB_SKIN 1017
+#define IDC_LBL_STATUS 1017
+#define IDC_EDT_INFO 1018
+#define IDC_PROGRESS 1018
+#define IDC_PIC_PREVIEW 1020
+#define IDC_LBL_CAPTION 1021
+#define IDC_CHK_AGENT 1021
+#define IDC_EDT_NAME 1022
+#define IDC_LBL_AGENT_DESC 1022
+#define IDC_EDT_TYPE 1023
+#define IDC_CHK_EXPLORER_MENU 1023
+#define IDC_LBL_NAME 1024
+#define IDC_BTN_SKIP 1024
+#define IDC_LBL_TYPE 1025
+#define IDC_GRP_PREVIEW 1026
+#define IDC_LBL_VERSION 1027
+#define IDC_EDT_VERSION 1028
+#define IDC_LBL_TYPE3 1029
+#define IDC_LBL_AUTHOR 1029
+#define IDC_EDT_AUTHOR 1030
+#define IDC_PIC_ABOUT 1032
+#define IDC_BTN_MOREINFO 1033
+#define IDC_CHK_CD 1034
+#define IDS_SKIN_CURRENT 2000
+#define IDS_SKIN_PROMO1 2001
+#define IDS_SKIN_PROMO2 2002
+#define IDS_PAGE_SKIN 2003
+#define IDS_PAGE_LANGUAGE 2004
+#define IDS_PAGE_CONNECTIVITY 2005
+#define IDS_SAVE_CHANGES_BEFORE_EXIT 2006
+#define IDS_UNKNOWN 2007
+#define IDS_CHANGES_NOT_SAVED 2008
+#define IDS_MODERN 2009
+#define IDS_CLASSIC 2010
+#define IDS_QUIT_OK 2011
+#define IDS_PAGE_ASSOCIATIONS 2012
+#define IDS_FILETYPE_VIDEO 2013
+#define IDS_FILETYPE_AUDIO 2014
+#define IDS_FILETYPE_UNKNOWN 2015
+#define IDS_FILETYPE_PLAYLIST 2016
+#define IDS_PAGE_FEEDBACK 2017
+#define IDS_GENDER_MALE 2018
+#define IDS_GENDER_FEMALE 2019
+#define IDS_GENDER_UNKNOWN 2020
+#define IDS_REGISTER_CDPLAYER 2021
+#define IDS_STATUS_SAVING 2022
+#define IDS_STATUS_JOBS 2023
+#define IDS_STATUS_RUNWA 2024
+#define IDS_PAGE_SKIN_LONG 2025
+#define IDS_REGISTER_AGENT 2026
+#define IDS_PAGE_ASSOCIATIONS_LONG 2027
+#define IDS_PAGE_FEEDBACK_LONG 2028
+#define IDS_INCORRECT_EMAIL_ADDRESS 2029
+#define IDS_PAGE_INCORRECT_EMAIL_ADDRESS 2029
+#define IDS_FILETYPE_AUXILIARY 2030
+#define IDS_WINAMP_SKIN_MODERN 2031
+#define IDS_WINAMP_SKIN_CLASSIC 2032
+#define IDS_WINAMP_LANG_PACK 2033
+#define IDS_DOWNLOADSTATUS_INITIALIZING 2034
+#define IDS_DOWNLOADSTATUS_CONNECTING 2035
+#define IDS_DOWNLOADSTATUS_CONNECTED 2036
+#define IDS_DOWNLOADSTATUS_RECEIVING 2037
+#define IDS_DOWNLOADSTATUS_RECEIVINGPERCENT 2038
+#define IDS_DOWNLOADSTATUS_SUCCESS 2039
+#define IDS_DOWNLOADSTATUS_FAILED 2040
+#define IDS_DOWNLOADSTATUS_ABORTING 2041
+#define IDS_DOWNLOADSTATUS_ABORTED 2042
+#define IDS_SETUP_WND_TITLE 2043
+#define ID_CMD_SAVE 40003
+#define IDM_HELP_ABOUT 40008
+#define IDM_TOOLS_MIGRATE 40009
+#define IDM_TOOLS_REGISTERWINAMP 40010
+#define IDM_NAVIGATE_BACK 40011
+#define IDM_NAVIGATE_NEXT 40012
+#define IDM_FILE_SAVECHANGES 40013
+#define IDM_FILE_EXIT 40016
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 121
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Winamp/setup/setupcommon.h b/Src/Winamp/setup/setupcommon.h
new file mode 100644
index 00000000..3073bd4e
--- /dev/null
+++ b/Src/Winamp/setup/setupcommon.h
@@ -0,0 +1,31 @@
+#ifndef NULLOSFT_WINAMP_SETUPCOMMON_HEADER
+#define NULLOSFT_WINAMP_SETUPCOMMON_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+
+#ifndef LONGX86
+#ifdef _WIN64
+ #define LONGX86 LONG_PTR
+#else /*_WIN64*/
+ #define LONGX86 LONG
+#endif /*_WIN64*/
+#endif // LONGX86
+
+#ifdef __cplusplus
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) ::SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#else
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#endif // __cplusplus
+
+#define SENDWAIPC(__ipcMsgId, __param) SENDMSG(hMainWindow, WM_WA_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
+
+#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWLP_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
+#define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
+
+
+#endif // NULLOSFT_WINAMP_SETUPCOMMON_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/setupfactory.cpp b/Src/Winamp/setup/setupfactory.cpp
new file mode 100644
index 00000000..fdb417ef
--- /dev/null
+++ b/Src/Winamp/setup/setupfactory.cpp
@@ -0,0 +1,249 @@
+#include "./setupfactory.h"
+#include <api/service/waservicefactorybase.h>
+#include <api/service/services.h>
+#include "api.h"
+#include "gen.h"
+#include "main.h"
+
+#define GUID_DEFINE
+#include "./setup.h"
+#undef GUID_DEFINE
+
+//#include "./spage_lang.h"
+//#include "./spage_connect.h"
+#include "./spage_skin.h"
+#include "./spage_assoc.h"
+//#include "./spage_feedback.h"
+
+#include "./sjob_register.h"
+#include <shlwapi.h>
+
+class setup_factory : public waServiceFactory
+{
+public:
+ setup_factory();
+ virtual ~setup_factory();
+public:
+ int AddRef();
+ int Release();
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+ void *GetInterface(int global_lock);
+ int SupportNonLockingInterface();
+ int ReleaseInterface(void *ifc);
+ const char *GetTestString();
+ int ServiceNotify(int msg, int param1, int param2);
+
+private:
+ int ref;
+ svc_setup *psvcSetup;
+protected:
+ RECVS_DISPATCH;
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+BOOL Setup_RegisterService(void)
+{
+ setup_factory *psf = new setup_factory();
+ WASABI_API_SVC->service_register(psf);
+ return (0 != psf->Release());
+}
+
+int Setup_RegisterDefault(void)
+{
+ waServiceFactory *psf = WASABI_API_SVC->service_getServiceByGuid(UID_SVC_SETUP);
+ if (!psf) return 0;
+
+ svc_setup *pSvc = (svc_setup*)psf->getInterface();
+ if (pSvc)
+ {
+ int index = 0;
+ ifc_setuppage *pp;
+ ifc_setupjob *pj;
+ // pp = new setup_page_lang();
+ // if (pp) { pSvc->InsertPage(pp, &index); pp->Release(); }
+
+ pp = new setup_page_skin();
+ if (pp) { pSvc->InsertPage(pp, &++index); pp->Release(); }
+
+// pp = new setup_page_connect();
+// if (pp) { pSvc->InsertPage(pp, &++index); pp->Release(); }
+
+ pp = new setup_page_assoc();
+ if (pp) { pSvc->InsertPage(pp, &++index); pp->Release(); }
+
+ // disabled for 5.66
+// pp = new setup_page_feedback();
+// if (pp) { pSvc->InsertPage(pp, &++index); pp->Release(); }
+
+ pj = new setup_job_register();
+ if (pj) { pSvc->AddJob(pj); pj->Release(); }
+
+ pSvc->Release();
+ return 1;
+ }
+
+ return 0;
+}
+
+int Setup_RegisterPlugins(void)
+{
+ wchar_t dirstr[MAX_PATH] = {0};
+ WIN32_FIND_DATAW d = {0};
+ PathCombineW(dirstr, PLUGINDIR, L"GEN_*.DLL");
+
+ HANDLE h = FindFirstFileW(dirstr,&d);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ wchar_t temp[MAX_PATH] = {0};
+ PathCombineW(temp, PLUGINDIR, d.cFileName);
+ HINSTANCE hLib = LoadLibraryW(temp);
+ if (hLib)
+ {
+ winampGeneralPurposePluginGetter pr = (winampGeneralPurposePluginGetter) GetProcAddress(hLib,"winampGetGeneralPurposePlugin");
+ if (pr)
+ {
+ Plugin_RegisterSetup fn = (Plugin_RegisterSetup)GetProcAddress(hLib, "RegisterSetup");
+ if (NULL == fn || FALSE == fn(hLib, WASABI_API_SVC))
+ {
+ winampGeneralPurposePlugin *plugin = pr();
+ if (plugin && (plugin->version == GPPHDR_VER || plugin->version == GPPHDR_VER_U))
+ {
+ char desc[128] = {0};
+ lstrcpynA(desc, plugin->description, sizeof(desc));
+ if (desc[0] && !memcmp(desc, "nullsoft(", 9))
+ {
+ // we'll let this leak for all 3rd party plug-ins as some crash during
+ // setup when we try to unload the plug-in e.g gen_Wake_up_call.dll
+ FreeModule(hLib);
+ }
+ }
+ }
+ }
+ }
+ } while (FindNextFileW(h,&d));
+ FindClose(h);
+ }
+ return 1;
+}
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+
+
+setup_factory::setup_factory() : ref(1), psvcSetup(NULL)
+{
+}
+
+setup_factory::~setup_factory()
+{
+ if (NULL != psvcSetup)
+ {
+ psvcSetup->Release();
+ }
+}
+
+int setup_factory::AddRef(void)
+{
+ return ++ref;
+}
+
+int setup_factory::Release(void)
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+FOURCC setup_factory::GetServiceType()
+{
+ return WaSvc::UNIQUE;
+}
+
+const char *setup_factory::GetServiceName()
+{
+ return "Setup Service";
+}
+
+GUID setup_factory::GetGUID()
+{
+ return UID_SVC_SETUP;
+}
+
+int setup_factory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+const char *setup_factory::GetTestString()
+{
+ return NULL;
+}
+
+int setup_factory::ServiceNotify(int msg, int param1, int param2)
+{
+ switch(msg)
+ {
+ case SvcNotify::ONREGISTERED:
+ AddRef();
+ break;
+ case SvcNotify::ONDEREGISTERED:
+ Release();
+ break;
+ }
+ return 1;
+}
+
+void *setup_factory::GetInterface(int global_lock)
+{
+ if (NULL == psvcSetup)
+ {
+ psvcSetup = WASetup::CreateInstance();
+ if (NULL == psvcSetup)
+ return NULL;
+ }
+
+ psvcSetup->AddRef();
+ return psvcSetup;
+}
+
+int setup_factory::ReleaseInterface(void *ifc)
+{
+ if (ifc == psvcSetup && NULL != psvcSetup)
+ {
+ if (0 == psvcSetup->Release())
+ psvcSetup = NULL;
+ }
+ return 1;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS setup_factory
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
+CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
+CB(WASERVICEFACTORY_GETGUID, GetGUID)
+CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
+CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
+CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
+CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
+CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
+END_DISPATCH
+
diff --git a/Src/Winamp/setup/setupfactory.h b/Src/Winamp/setup/setupfactory.h
new file mode 100644
index 00000000..c3ccba1c
--- /dev/null
+++ b/Src/Winamp/setup/setupfactory.h
@@ -0,0 +1,19 @@
+#ifndef NULLSOFT_WINAMP_SETUP_FACTORY_HEADER
+#define NULLSOFT_WINAMP_SETUP_FACTORY_HEADER
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+int Setup_RegisterService(void);
+int Setup_RegisterDefault(void);
+int Setup_RegisterPlugins(void);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+
+
+
+#endif // NULLSOFT_WINAMP_SETUP_FACTORY_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/sjob_register.cpp b/Src/Winamp/setup/sjob_register.cpp
new file mode 100644
index 00000000..9754b2d4
--- /dev/null
+++ b/Src/Winamp/setup/sjob_register.cpp
@@ -0,0 +1,84 @@
+#include "main.h"
+#include "../nu/AutoChar.h"
+#include "./sjob_register.h"
+#include "./httpgrab.h"
+
+setup_job_register::setup_job_register() : ref(1), hwndHttp(NULL)
+{
+}
+
+setup_job_register::~setup_job_register()
+{
+}
+
+size_t setup_job_register::AddRef()
+{
+ return ++ref;
+}
+
+size_t setup_job_register::Release()
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+HRESULT setup_job_register::Execute(HWND hwndText)
+{
+ if (!isInetAvailable()) return S_OK;
+ if (!config_newverchk2) return S_OK;
+
+ // TODO re-enable at some point as needed
+#if 0
+ char data[8192] = {0};
+ SecureZeroMemory(data, sizeof(data));
+
+ INT s = GetPrivateProfileInt("WinampReg", "RegDataLen", 0, INI_FILEA);
+ if (s> 0)
+ {
+ if (GetPrivateProfileStruct("WinampReg", "RegData2", data, s, INI_FILEA))
+ {
+ wchar_t szEmail[256] = {0};
+ GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_EMAIL), szEmail, sizeof(szEmail));
+ }
+ // if (!*szEmail) return S_OK;
+ }
+
+ HWND hwndHost = BeginGrabHTTPText(hwndText, HTTPGRAB_USEWINDOWTEXT, &hwndHttp);
+ HRESULT hr = (SendMetrics(data, hwndHost)) ? S_OK : S_FALSE;
+ hwndHttp = NULL;
+ EndGrabHTTPText(hwndHost);
+ return hr;
+#else
+ return S_OK;
+#endif
+}
+
+HRESULT setup_job_register::Cancel(HWND hwndText)
+{
+ if (hwndHttp) SendMessageW(hwndHttp, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED),
+ (LPARAM)GetDlgItem(hwndHttp, IDCANCEL));
+ return S_OK;
+}
+
+HRESULT setup_job_register::IsCancelSupported()
+{
+ return S_OK;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS setup_job_register
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(API_SETUPJOB_EXECUTE, Execute)
+CB(API_SETUPJOB_CANCEL, Cancel)
+CB(API_SETUPJOB_ISCANCELSUPPORTED, IsCancelSupported)
+END_DISPATCH
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/setup/sjob_register.h b/Src/Winamp/setup/sjob_register.h
new file mode 100644
index 00000000..b87eb2e9
--- /dev/null
+++ b/Src/Winamp/setup/sjob_register.h
@@ -0,0 +1,28 @@
+#ifndef WINAMP_REGISTER_SETUP_JOB_HEADER
+#define WINAMP_REGISTER_SETUP_JOB_HEADER
+
+#include "./ifc_setupjob.h"
+
+class setup_job_register: public ifc_setupjob
+{
+
+public:
+ setup_job_register();
+ virtual ~setup_job_register();
+
+public:
+ size_t AddRef();
+ size_t Release();
+ HRESULT Execute(HWND hwndText);
+ HRESULT Cancel(HWND hwndText);
+ HRESULT IsCancelSupported();
+private:
+ size_t ref;
+ HWND hwndHttp;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
+#endif //WINAMP_REGISTER_SETUP_JOB_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/skininfo.cpp b/Src/Winamp/setup/skininfo.cpp
new file mode 100644
index 00000000..906d6e2b
--- /dev/null
+++ b/Src/Winamp/setup/skininfo.cpp
@@ -0,0 +1,330 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include "./skininfo.h"
+#include "./loadimage.h"
+#include "./langutil.h"
+#include "./setup_resource.h"
+#include "./api.h"
+#include <../xml/obj_xml.h>
+#include <api/service/waServiceFactory.h>
+#include "../xml/ifc_xmlreadercallbacki.h"
+#include "minizip/unzip.h"
+#include "../nu/AutoChar.h"
+
+#define ZIP_BUFFER_SIZE 2048
+
+static wchar_t szClassic[64] = {0, };
+#define CLASSIC_NAME() ((!*szClassic) ? getStringW(IDS_CLASSIC_SKIN_NAME, szClassic, sizeof(szClassic)/sizeof(wchar_t)) : szClassic)
+
+static BOOL ExtractCurrentFile(unzFile f, LPCWSTR pszPath);
+static INT ZipProcessSkinInfo(unzFile f, LPCWSTR pszTemp, SKININFO *psi, LPSTR szSearch, INT cchSearch); // returns length of search
+
+class SkinXMLCallback : public ifc_xmlreadercallbackI
+{
+public:
+ SkinXMLCallback(SKININFO *psi, LPCWSTR pszSkinXML, LPWSTR pszImage, INT cchImage) // if pszIamge != NULL iamge path will be returned instead of loading image
+ {
+ this->psi = psi;
+ this->pszImage = pszImage;
+ this->cchImage = cchImage;
+ if (this->pszImage) *this->pszImage = 0x00;
+ StringCchCopyW(szPath, sizeof(szPath)/sizeof(wchar_t), pszSkinXML);
+ PathRemoveFileSpecW(szPath);
+ };
+ void xmlReaderOnCharacterDataCallback(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *s);
+ void xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+
+protected:
+ SKININFO *psi;
+ wchar_t szPath[MAX_PATH*2];
+ LPWSTR pszImage;
+ INT cchImage;
+};
+
+static BOOL LoadXMLFile(obj_xml *parser, LPCWSTR pszFileName)
+{
+ HANDLE hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
+ if (INVALID_HANDLE_VALUE == hFile) return FALSE;
+
+ BOOL br (TRUE);
+ DWORD bytesRead=0;
+ do
+ {
+ BYTE buffer[1024] = {0};
+ bytesRead=0;
+ if (ReadFile(hFile, buffer, 1024, &bytesRead, NULL) && bytesRead)
+ {
+ if (parser->xmlreader_feed(buffer, bytesRead)!=API_XML_SUCCESS) { br = FALSE; break; }
+ }
+ else
+ {
+ if (parser->xmlreader_feed(0, 0) != API_XML_SUCCESS) { br = FALSE; break; }
+ bytesRead=0;
+ }
+ } while (bytesRead);
+
+ CloseHandle(hFile);
+ return br;
+}
+
+static BOOL ReadSkinInfo(LPCWSTR pszSkinXML, SKININFO *psi, LPWSTR pszImage, INT cchImage)
+{
+ waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
+ if (parserFactory)
+ {
+ obj_xml *parser = (obj_xml *)parserFactory->getInterface();
+ if (parser)
+ {
+ SkinXMLCallback cb(psi, pszSkinXML, pszImage, cchImage);
+ parser->xmlreader_registerCallback(L"WinampAbstractionLayer", &cb);
+ parser->xmlreader_registerCallback(L"WinampAbstractionLayer\fSkinInfo\f*", &cb);
+ parser->xmlreader_registerCallback(L"WasabiXML", &cb);
+ parser->xmlreader_registerCallback(L"WasabiXML\fSkinInfo\f*", &cb);
+ parser->xmlreader_registerCallback(L"SkinInfo*", &cb);
+
+ parser->xmlreader_open();
+ LoadXMLFile(parser, pszSkinXML);
+ parser->xmlreader_unregisterCallback(&cb);
+ parser->xmlreader_close();
+ parserFactory->releaseInterface(parser);
+ }
+ }
+
+ return TRUE;
+}
+
+void SkinXMLCallback::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, L"WinampAbstractionLayer", -1, xmltag, -1) ||
+ CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, L"WasabiXML", -1, xmltag, -1))
+ {
+ const wchar_t *version = params->getItemValue(L"version");
+ if (version) StringCchCopyW(psi->szWasabiVer, SI_VERMAX, version);
+ else psi->szWasabiVer[0] = 0x00;
+ }
+}
+
+void SkinXMLCallback::xmlReaderOnCharacterDataCallback(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *s)
+{
+ static const wchar_t *tags[] = { L"name", L"version", L"comment", L"author", L"email", L"homepage", L"screenshot" };
+ int cch, i, count = sizeof(tags)/sizeof(wchar_t*);
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ LPWSTR p;
+
+ for (i = 0; i < count; i++)
+ {
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, tags[i], -1, xmltag, -1)) break;
+ }
+
+ switch(i)
+ {
+ case 0: p = psi->szName; cch = SI_NAMEMAX; break;
+ case 1: p = psi->szVersion; cch = SI_VERMAX; break;
+ case 2: p = (SIF_COMMENT & psi->fMask) ? psi->pszComment : NULL; cch = psi->cchComment; break;
+ case 3: p = psi->szAuthor; cch = SI_AUTHORMAX; break;
+ case 4: p = psi->szEmail; cch = SI_EMAILMAX; break;
+ case 5: p = psi->szHomePage; cch = SI_HOMEPAGEMAX; break;
+ case 6:
+ if ((SIF_PREVIEW & psi->fMask) && *s)
+ {
+ if (pszImage) StringCchCopyW(pszImage, cchImage, s);
+ else
+ {
+ wchar_t szPic[MAX_PATH*2] = {0};
+ psi->hPreview = WALoadImage(NULL, NULL, (PathIsRootW(s)) ? s : PathCombineW(szPic, szPath, s), FALSE);
+ }
+ }
+ return;
+ default: return;
+ }
+
+ if (p) StringCchCopyW(p, cch, s);
+}
+
+BOOL GetSkinInfo(LPCWSTR pszSkinPath, SKININFO *psi)
+{
+ wchar_t szBuffer[MAX_PATH*2] = {0};
+ if (!psi || sizeof(SKININFO) != psi->cbSize) return FALSE;
+ psi->type = SKIN_TYPE_UNKNOWN;
+
+ if (SIF_COMMENT & psi->fMask)
+ {
+ if (!psi->pszComment || !psi->cchComment) return FALSE;
+ psi->pszComment[0] = 0x00;
+ }
+ if (SIF_PREVIEW & psi->fMask) psi->hPreview = NULL;
+
+ if (!pszSkinPath || !*pszSkinPath || CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
+ pszSkinPath, -1, CLASSIC_NAME(), -1))
+ {
+ // default classic
+ psi->type = SKIN_TYPE_CLASSIC;
+ StringCchCopyW(psi->szName, SI_NAMEMAX, CLASSIC_NAME());
+
+ if (SIF_COMMENT & psi->fMask) StringCchCopyW(psi->pszComment, psi->cchComment, L"Winamp base skin v5.5");
+ if (SIF_PREVIEW & psi->fMask)
+ psi->hPreview = WALoadImage2(L"PNG", MAKEINTRESOURCEW(IDB_PREVIEW_CLASSIC), FALSE);
+ StringCchCopyW(psi->szAuthor, SI_AUTHORMAX, L"Steve Gedikian");
+ StringCchCopyW(psi->szVersion, SI_VERMAX, L"2.0");
+ return TRUE;
+ }
+ if (PathIsDirectoryW(pszSkinPath))
+ {
+ if (PathFileExistsW(PathCombineW(szBuffer, pszSkinPath, L"skin.xml")))
+ {
+ psi->type = SKIN_TYPE_MODERN;
+ ReadSkinInfo(szBuffer, psi, NULL, 0);
+ }
+ else if (PathFileExistsW(PathCombineW(szBuffer, pszSkinPath, L"main.bmp")))
+ {
+ psi->type = SKIN_TYPE_CLASSIC;
+ ReadSkinInfo(PathCombineW(szBuffer, pszSkinPath, L"skininfo.xml"), psi, NULL, 0);
+ }
+ }
+ else
+ {
+ int len, start, lenSearch;
+ DWORD lcid;
+ wchar_t szTemp[MAX_PATH] = {0};
+ char filename[MAX_PATH] = {0}, search[MAX_PATH] = {0};
+ unzFile f;
+
+ if (!GetTempPathW(MAX_PATH, szBuffer) || !GetTempFileNameW(szBuffer, L"WAS", 0, szTemp)) return FALSE;
+
+ f = unzOpen(AutoChar(pszSkinPath));
+ if (!f) return FALSE;
+
+ lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ search[0] = 1;
+ lenSearch = 0;
+ start = 0;
+ do
+ {
+ int pos = -1, nr = unzGoToFirstFile(f);
+ while (UNZ_OK == nr && *search)
+ {
+ pos++;
+ if (start && pos == start) { start = 0; break; }
+ if (UNZ_OK == unzGetCurrentFileInfo(f, NULL, filename, sizeof(filename), NULL, 0, NULL, 0) && *filename)
+ {
+ len = lstrlenA(filename);
+ if (!len || filename[len - 1] == '/') // empty or folder
+ {
+ nr = unzGoToNextFile(f);
+ continue;
+ }
+ if (SKIN_TYPE_UNKNOWN == psi->type)
+ {
+ if ((len == 8 || (len > 8 && '/' == filename[len - 8 - 1])) &&
+ CSTR_EQUAL == CompareStringA(lcid, NORM_IGNORECASE, "main.bmp", -1, (filename + (len - 8)), -1))
+ {
+ psi->type = SKIN_TYPE_CLASSIC;
+ StringCchCopyA(search, MAX_PATH, "skininfo.xml");
+ lenSearch = lstrlenA(search);
+ start = pos;
+ }
+ else if ((len == 8 || (len > 8 && '/' == filename[len - 8 - 1])) &&
+ CSTR_EQUAL == CompareStringA(lcid, NORM_IGNORECASE, "skin.xml", -1, (filename + (len - 8)), -1))
+ {
+ psi->type = SKIN_TYPE_MODERN;
+ lenSearch = ZipProcessSkinInfo(f, szTemp, psi, search, MAX_PATH);
+ if (lenSearch) start = pos;
+ }
+ }
+ else if ((len == lenSearch || (len > lenSearch && '/' == filename[len - lenSearch - 1])) &&
+ CSTR_EQUAL == CompareStringA(lcid, NORM_IGNORECASE, search, -1, (filename + (len - lenSearch)), -1))
+ {
+ if (CSTR_EQUAL == CompareStringA(lcid, NORM_IGNORECASE, search, -1, "skininfo.xml", -1))
+ {
+ lenSearch = ZipProcessSkinInfo(f, szTemp, psi, search, MAX_PATH);
+ if (lenSearch) start = pos;
+ }
+ else // image
+ {
+ if (ExtractCurrentFile(f, szTemp)) psi->hPreview = WALoadImage(NULL, NULL, szTemp, FALSE);
+ else psi->hPreview = NULL;
+ *search = 0x00;
+ }
+ }
+ }
+ nr = unzGoToNextFile(f);
+ }
+ } while(search && *search && start);
+ unzClose(f);
+
+ // delete tmp file
+ DeleteFileW(szTemp);
+ }
+
+ return TRUE;
+}
+
+static BOOL ExtractCurrentFile(unzFile f, LPCWSTR pszPath)
+{
+ HANDLE hFile;
+ OVERLAPPED asyncIO;
+ static BOOL isNT = -1;
+ BOOL bSuccess(TRUE);
+
+ int l(1), pos(0), bufNum(0);
+ char buf[ZIP_BUFFER_SIZE*2] = {0};
+
+ if (UNZ_OK != unzOpenCurrentFile(f)) return FALSE;
+
+ if (-1 == isNT) isNT = (GetVersion() < 0x80000000);
+ ZeroMemory(&asyncIO, sizeof(OVERLAPPED));
+ if (isNT) asyncIO.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
+
+ hFile = CreateFileW(pszPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | ((isNT) ? FILE_FLAG_OVERLAPPED : 0), NULL);
+ if (INVALID_HANDLE_VALUE == hFile) { bSuccess = FALSE; hFile = NULL; }
+
+ while (bSuccess && l > 0)
+ {
+ DWORD written = 0;
+ bufNum = !bufNum;
+ l = unzReadCurrentFile(f, buf+ZIP_BUFFER_SIZE*bufNum, ZIP_BUFFER_SIZE);
+ if (l < 0) bSuccess = FALSE;
+ if (isNT)
+ {
+ WaitForSingleObject(asyncIO.hEvent, INFINITE);
+ if (l > 0)
+ {
+ asyncIO.Offset = pos;
+ if (!WriteFile(hFile, buf+ZIP_BUFFER_SIZE*bufNum, l, NULL, &asyncIO) && ERROR_IO_PENDING != GetLastError())
+ {
+ bSuccess = FALSE;
+ }
+ pos += l;
+ }
+ }
+ else
+ {
+ if (l > 0)
+ {
+ if (!WriteFile(hFile, buf+ZIP_BUFFER_SIZE*bufNum, l, &written, NULL)) bSuccess = FALSE;
+ }
+ }
+ }
+
+ if (hFile) CloseHandle(hFile);
+ if (asyncIO.hEvent) CloseHandle(asyncIO.hEvent);
+ unzCloseCurrentFile(f);
+ return bSuccess;
+}
+
+static INT ZipProcessSkinInfo(unzFile f, LPCWSTR pszTemp, SKININFO *psi, LPSTR szSearch, INT cchSearch) // returns length of search
+{
+ *szSearch = 0x00;
+ if (ExtractCurrentFile(f, pszTemp))
+ {
+ wchar_t szImage[MAX_PATH] = {0};
+ if (ReadSkinInfo(pszTemp, psi, szImage, MAX_PATH) && *szImage)
+ {
+ if(!PathIsRelativeW(szImage)) psi->hPreview = WALoadImage(NULL, NULL, szImage, FALSE);
+ else StringCchCopyA(szSearch, cchSearch, AutoChar(szImage));
+ }
+ }
+ return lstrlenA(szSearch);
+} \ No newline at end of file
diff --git a/Src/Winamp/setup/skininfo.h b/Src/Winamp/setup/skininfo.h
new file mode 100644
index 00000000..b96494db
--- /dev/null
+++ b/Src/Winamp/setup/skininfo.h
@@ -0,0 +1,38 @@
+#ifndef WINAMP_SKININFO_HEADER
+#define WINAMP_SKININFO_HEADER
+
+#include <windows.h>
+
+#define SIF_COMMENT 0x01
+#define SIF_PREVIEW 0x02
+
+#define SKIN_TYPE_UNKNOWN 0
+#define SKIN_TYPE_CLASSIC 1
+#define SKIN_TYPE_MODERN 2
+
+#define SI_NAMEMAX 32
+#define SI_VERMAX 16
+#define SI_AUTHORMAX 32
+#define SI_EMAILMAX 32
+#define SI_HOMEPAGEMAX 64
+
+typedef struct _SKININFO
+{
+ INT cbSize; // sizeof(SKININFO)
+ UINT fMask; // SIF_DESCRIPTION | SIF_PREVIEW
+ int type; // classic/modern
+ wchar_t szName[SI_NAMEMAX];
+ wchar_t szVersion[SI_VERMAX];
+ wchar_t szAuthor[SI_AUTHORMAX];
+ wchar_t szEmail[SI_EMAILMAX];
+ wchar_t szHomePage[SI_HOMEPAGEMAX];
+ wchar_t szWasabiVer[SI_VERMAX];
+ wchar_t *pszComment;
+ int cchComment;
+ HBITMAP hPreview; // preiew bitmap;
+}SKININFO;
+
+
+BOOL GetSkinInfo(LPCWSTR pszSkinPath, SKININFO *psi);
+
+#endif //WINAMP_SKININFO_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/smokingllama.png b/Src/Winamp/setup/smokingllama.png
new file mode 100644
index 00000000..e63b4c28
--- /dev/null
+++ b/Src/Winamp/setup/smokingllama.png
Binary files differ
diff --git a/Src/Winamp/setup/spage_assoc.cpp b/Src/Winamp/setup/spage_assoc.cpp
new file mode 100644
index 00000000..937284d6
--- /dev/null
+++ b/Src/Winamp/setup/spage_assoc.cpp
@@ -0,0 +1,1069 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include "api.h"
+#include "./spage_assoc.h"
+#include "./setup_resource.h"
+#include "../nu/ns_wc.h"
+#include "../nu/AutoWide.h"
+#include "./langutil.h"
+#include "./setupcommon.h"
+#include "../playlist/svc_playlisthandler.h"
+#include <api/service/waservicefactorybase.h>
+#include "../Agave/URIHandler/svc_urihandler.h"
+#include <api/service/waservicefactory.h>
+#include <commctrl.h>
+
+#define MF_SELECTED 0x0001
+#define MF_TYPE_MASK 0xFF00
+#define MF_TYPE_REREAD 0xFF
+#define MF_TYPE_UNKNOWN 0x00
+#define MF_TYPE_AUDIO 0x01
+#define MF_TYPE_VIDEO 0x02
+#define MF_TYPE_PLAYLIST 0x03
+#define MF_TYPE_AUXILIARY 0x04
+
+#define ID_REGISTERCD ((TYPE_CATEGORIES_NUM) + 1)
+#define ID_REGISTERAGENT ((TYPE_CATEGORIES_NUM) + 2)
+
+#define SET_TYPE(_val, _type) ((_val) = ((_val) & ~MF_TYPE_MASK) | ((_type) << 8))
+#define GET_TYPE(_val) ((_val) >> 8)
+#define IS_NEEDREREAD(_val) GET_TYPE((_val), MF_TYPE_REREAD)
+#define IS_SELECTED(_val) (MF_SELECTED & (_val))
+#define INITMETA( _type, _selected) ((WORD)(((_type) << 8) | ((_selected) ? MF_SELECTED : 0x0000)))
+
+static wchar_t szAuxExt[] = L"wsz\0wal\0wlz\0";
+
+static LRESULT WINAPI TreeViewProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static BOOL IsAgentScheduled(void)
+{
+ HKEY hKey = NULL;
+ BOOL bActive(FALSE);
+ WCHAR szAgent[MAX_PATH*2] = {0};
+ DWORD cb = sizeof(szAgent);
+
+ if (ERROR_SUCCESS != RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &hKey))
+ return FALSE;
+ if (ERROR_SUCCESS != RegQueryValueExW(hKey, L"WinampAgent", NULL, NULL, (BYTE*)szAgent, &cb))
+ szAgent[0] = 0x00;
+ RegCloseKey(hKey);
+
+ if (*szAgent)
+ {
+ WCHAR szPath[MAX_PATH*2] = {0};
+ GetModuleFileNameW(NULL, szPath, sizeof(szPath)/sizeof(wchar_t));
+ PathUnquoteSpacesW(szAgent);
+ PathRemoveFileSpecW(szAgent);
+ PathRemoveFileSpecW(szPath);
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ bActive = (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, szPath, -1, szAgent, -1));
+ }
+
+ return bActive;
+}
+
+static BOOL IsAgentExist(void)
+{
+ wchar_t szAgent[MAX_PATH] = {0};
+ if (0 == GetModuleFileNameW(hMainInstance, szAgent, sizeof(szAgent)/sizeof(wchar_t)))
+ return FALSE;
+
+ PathRemoveFileSpecW(szAgent);
+ if (NULL == PathCombineW(szAgent, szAgent, L"winampa.exe"))
+ return FALSE;
+
+ return (FALSE != PathFileExistsW(szAgent));
+}
+
+static BOOL RefreshIcons(void)
+{
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
+ return TRUE;
+}
+
+static void RegisterProtocols()
+{
+ if (config_no_registry)
+ return;
+
+ wchar_t winampexe[MAX_PATH] = {0};
+ GetModuleFileNameW(hMainInstance, winampexe, MAX_PATH);
+
+ WCHAR szApplication[256] = {0};
+ INT r = MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, NULL, 0);
+ if (r > ARRAYSIZE(szApplication) || 0 == r)
+ return;
+ if (0 == MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, szApplication, ARRAYSIZE(szApplication)))
+ return;
+
+ if (NULL != WASABI_API_SVC)
+ {
+ for(size_t i =0;;i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(svc_urihandler::getServiceType(), i);
+ if (NULL == sf) break;
+
+ svc_urihandler *handler = (svc_urihandler *)sf->getInterface();
+ if (NULL != handler)
+ {
+ WCHAR szName[128] = {0}, szDesc[256] = {0};
+ for (size_t k = 0; ;k++)
+ {
+ INT ret = handler->EnumProtocols(k, szName, ARRAYSIZE(szName), szDesc, ARRAYSIZE(szDesc));
+ if (0 != ret)
+ break;
+
+ if (0 == handler->RegisterProtocol(szName, winampexe))
+ {
+ IFileTypeRegistrar *registrar = 0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->RegisterMediaPlayerProtocol(szName, szApplication);
+ registrar->Release();
+ }
+ }
+ }
+ sf->releaseInterface(handler);
+ }
+ }
+ }
+}
+
+setup_page_assoc::setup_page_assoc() : ref(1), hwnd(NULL), pszTypes(NULL), pMeta(NULL), bRegCD(FALSE), bAgent(FALSE), bExplorerMenu(TRUE)
+{
+ ZeroMemory(expanded, sizeof(expanded));
+ ZeroMemory(szTopExt, sizeof(szTopExt));
+ ZeroMemory(szCaretExt, sizeof(szCaretExt));
+}
+
+setup_page_assoc::~setup_page_assoc()
+{
+ if (pszTypes)
+ {
+ free(pszTypes);
+ pszTypes = NULL;
+ }
+ if (pMeta)
+ {
+ free(pMeta);
+ pMeta = NULL;
+ }
+}
+
+size_t setup_page_assoc::AddRef()
+{
+ return ++ref;
+}
+
+size_t setup_page_assoc::Release()
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+HRESULT setup_page_assoc::GetName(bool bShort, const wchar_t **pszName)
+{
+ if (bShort)
+ {
+ static wchar_t szShortName[32] = {0};
+ *pszName = (*szShortName) ? szShortName : getStringW(IDS_PAGE_ASSOCIATIONS, szShortName, sizeof(szShortName)/sizeof(wchar_t));
+ }
+ else
+ {
+ static wchar_t szLongName[64] = {0};
+ *pszName = (*szLongName) ? szLongName : getStringW(IDS_PAGE_ASSOCIATIONS_LONG, szLongName, sizeof(szLongName)/sizeof(wchar_t));
+ }
+ return S_OK;
+}
+
+HRESULT setup_page_assoc::Save(HWND hwndText)
+{
+ HRESULT hr(S_OK);
+ WORD *pm;
+ wchar_t ext_list[16384] = {0}, *p = 0, *pe = ext_list;
+ BOOL bFirst(TRUE);
+ size_t len = ARRAYSIZE(ext_list);
+
+ // make sure that we honour the agent setting even if no settings changed
+ // this allows the agent to be restarted correctly after a normal upgrade
+ if (bAgent && IsAgentExist())
+ config_agent_add();
+ else
+ config_agent_remove();
+
+ // temporary: always enumerate and register protocols
+ RegisterProtocols();
+
+ if (S_FALSE == IsDirty()) return S_OK;
+
+ if (!pszTypes) return S_FALSE;
+
+ config_setup_filetypes(0);
+
+ for(pm = pMeta, p = pszTypes; *p != 0; p += lstrlenW(p) + 1, pm++)
+ {
+ config_register_capability(p, 0);
+ config_register(p, IS_SELECTED(*pm));
+ if (IS_SELECTED(*pm) && (S_OK == hr) && GET_TYPE(*pm) != MF_TYPE_AUXILIARY)
+ {
+ if (!len) { hr = S_FALSE; continue; }
+ if (!bFirst)
+ {
+ pe[0] = L':';
+ pe++;
+ len--;
+ }
+ else bFirst = FALSE;
+ if (S_OK != StringCchCopyExW(pe, len, p, &pe, &len, STRSAFE_IGNORE_NULLS)) hr = S_FALSE;
+ }
+ }
+ if (S_OK == hr) _w_sW("config_extlist", ext_list);
+
+ config_regcdplayer(bRegCD, 0);
+ (bExplorerMenu) ? config_adddircontext(0) : config_removedircontext(0);
+
+ config_registermediaplayer(1);
+
+ WritePrivateProfileStringW(L"Jump To File Extra", L"newIconLib", L"refresh", INI_FILE);
+ RefreshIcons();
+
+ return hr;
+}
+
+static BOOL IsFirstSetup()
+{
+ wchar_t szVer[512] = {0};
+ if (0 == GetPrivateProfileIntW(L"WinampReg", L"IsFirstInst", 1, INI_FILE)) return FALSE;
+
+ GetPrivateProfileStringW(L"Winamp", L"config_extlist", L"", szVer, 512, INI_FILE);
+ if (*szVer) return FALSE;
+
+ GetPrivateProfileStringW(L"WinampReg", L"WAVer", L"", szVer, 512, INI_FILE);
+ return (!*szVer || CSTR_EQUAL != CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
+ NORM_IGNORECASE, szVer, -1, AutoWide(APP_VERSION), -1));
+}
+
+static wchar_t *BuildExtensionString(WORD **ppMeta, BOOL bFirstSetup)
+{
+ INT cWA(0), cPL(0), cAux(0), lWA(0), lPL(0), lAux(0);
+ wchar_t *pszType, *pWAExt = in_getextlistW(), *pPLExt, *p;
+
+ if (pWAExt)
+ {
+ for(p = pWAExt; *p != 0; cWA++, p += lstrlenW(p) + 1);
+ lWA = (INT)(p - pWAExt);
+ }
+
+ if (playlistManager)
+ {
+ size_t playlistEnum = 0;
+ const wchar_t *playlistExt=0;
+ while (NULL != (playlistExt = playlistManager->EnumExtension(playlistEnum++))) { lPL += (lstrlenW(playlistExt) + 1); cPL++; }
+ lPL += 2;
+ }
+
+ for(p = szAuxExt; *p != 0; cAux++, p += lstrlenW(p) + 1);
+ lAux = (INT)(p - szAuxExt);
+
+ pszType = (wchar_t*)calloc((lWA + lPL + lAux + 1), sizeof(wchar_t));
+ if (ppMeta)
+ {
+ *ppMeta = (WORD*)calloc((cWA + cPL + cAux), sizeof(WORD));
+ }
+
+ if (pszType)
+ {
+ if (pWAExt) CopyMemory(pszType, pWAExt, lWA*sizeof(wchar_t));
+ pPLExt = pszType + lWA;
+ p = pPLExt;
+ if (playlistManager)
+ {
+ size_t playlistEnum=0;
+ const wchar_t *playlistExt=0;
+ while (lPL > 0 && NULL != (playlistExt = playlistManager->EnumExtension(playlistEnum++)))
+ {
+ int c = lstrlenW(playlistExt) + 1;
+ lstrcpynW(p, playlistExt, c);
+ if (c)
+ {
+ p += c;
+ lPL -= c;
+ }
+ }
+ if (lPL > 1) *p = 0x00;
+ }
+ CopyMemory(p, szAuxExt, lAux*sizeof(wchar_t));
+ *(p+lAux)=0;
+ }
+
+ if(ppMeta && *ppMeta)
+ {
+ int i;
+ WORD *pm = *ppMeta;
+ p = pszType;
+ for (i = 0; i < cWA; i++, pm++, p += lstrlenW(p) + 1) *pm = INITMETA(MF_TYPE_REREAD, ((!bFirstSetup) ? config_isregistered(p) : 1));
+ for (i = 0; i < cPL; i++, pm++, p += lstrlenW(p) + 1) *pm = INITMETA(MF_TYPE_PLAYLIST, ((!bFirstSetup) ? config_isregistered(p) : 1));
+ for (i = 0; i < cAux; i++, pm++, p += lstrlenW(p) + 1) *pm = INITMETA(MF_TYPE_AUXILIARY, ((!bFirstSetup) ? config_isregistered(p) : 1));
+ }
+
+ if (pWAExt) GlobalFree(pWAExt);
+
+ return pszType;
+}
+
+static BOOL GetPLExtensionName(LPCWSTR pszExt, LPWSTR pszDest, INT cchDest)
+{
+ BOOL result(FALSE);
+ int n(0);
+ waServiceFactory *sf = 0;
+ LPCWSTR ext;
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ while (NULL != (sf = WASABI_API_SVC->service_enumService(WaSvc::PLAYLISTHANDLER, n++)))
+ {
+ svc_playlisthandler * handler = static_cast<svc_playlisthandler *>(sf->getInterface());
+ if (handler)
+ {
+ int k(0);
+ while (NULL != (ext = handler->EnumerateExtensions(k++)))
+ {
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, ext, -1))
+ {
+ result = (S_OK == StringCchCopyW(pszDest, cchDest, handler->GetName()));
+ if (result && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"M3U8", -1)) // ugly...
+ result = (S_OK == StringCchCatW(pszDest, cchDest, L" (Unicode)"));
+ break;
+ }
+ }
+ sf->releaseInterface(handler);
+ }
+ }
+ return result;
+}
+
+static BOOL GetAuxExtensionName(LPCWSTR pszExt, LPWSTR pszDest, INT cchDest)
+{
+ BOOL result(FALSE);
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"wal", -1))
+ result = (S_OK == StringCchCopyW(pszDest, cchDest, getStringW(IDS_WINAMP_SKIN_MODERN, NULL, 0)));
+ else if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"wsz", -1))
+ result = (S_OK == StringCchCopyW(pszDest, cchDest, getStringW(IDS_WINAMP_SKIN_CLASSIC, NULL, 0)));
+ else if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"wlz", -1))
+ result = (S_OK == StringCchCopyW(pszDest, cchDest, getStringW(IDS_WINAMP_LANG_PACK, NULL, 0)));
+ return result;
+}
+
+static BOOL GetExtensionName(LPCWSTR pszFile, INT type, LPWSTR pszDest, INT cchDest)
+{
+ switch(type)
+ {
+ case MF_TYPE_AUDIO:
+ case MF_TYPE_VIDEO:
+ return in_get_extended_fileinfoW(pszFile, L"family", pszDest, cchDest);
+ case MF_TYPE_PLAYLIST:
+ {
+ const wchar_t *pszExt = PathFindExtensionW(pszFile);
+ return (L'.' == *pszExt && 0x00 != *(++pszExt)) ? GetPLExtensionName(pszExt, pszDest, cchDest) : FALSE;
+ }
+ case MF_TYPE_AUXILIARY:
+ {
+ const wchar_t *pszExt = PathFindExtensionW(pszFile);
+ return (L'.' == *pszExt && 0x00 != *(++pszExt)) ? GetAuxExtensionName(pszExt, pszDest, cchDest) : FALSE;
+ }
+ }
+ return FALSE;
+}
+
+HRESULT setup_page_assoc::Revert(void)
+{
+ HRESULT hr(S_OK);
+
+ if (pszTypes)
+ {
+ free(pszTypes);
+ pszTypes = NULL;
+ }
+
+ if (pMeta)
+ {
+ free(pMeta);
+ pMeta = NULL;
+ }
+
+ BOOL firstSetup = IsFirstSetup();
+ pszTypes = BuildExtensionString(&pMeta, firstSetup);
+
+ ZeroMemory(expanded, sizeof(expanded));
+ ZeroMemory(szTopExt, sizeof(szTopExt));
+ ZeroMemory(szCaretExt, sizeof(szCaretExt));
+
+ bRegCD = (firstSetup) ? TRUE : config_iscdplayer();
+ bAgent = (FALSE != IsAgentExist()) ? ((firstSetup) ? FALSE : IsAgentScheduled()) : FALSE;
+ bExplorerMenu = (firstSetup) ? TRUE : config_isdircontext();
+
+ if (hwnd) UpdateUI();
+ return hr;
+}
+
+HRESULT setup_page_assoc::IsDirty(void)
+{
+ if (IsFirstSetup()) return S_OK;
+
+ HRESULT hr(S_FALSE);
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ wchar_t *pszOrigTypes = BuildExtensionString(NULL, TRUE), *p;
+ if ((!pszOrigTypes && pszTypes) || (pszOrigTypes && !pszTypes))
+ {
+ if (pszOrigTypes) free(pszOrigTypes);
+ return S_OK;
+ }
+ else if (!pszOrigTypes && !pszTypes) return S_FALSE;
+
+ INT cr = CompareStringW(lcid, NORM_IGNORECASE, pszTypes, -1, pszOrigTypes, -1);
+ if (0 == cr) hr = E_UNEXPECTED;
+ else if (CSTR_EQUAL == cr)
+ {
+ WORD *pm;
+ for(pm = pMeta, p = pszTypes; *p != 0; p += lstrlenW(p) + 1, pm++)
+ {
+ if ((MF_SELECTED & *pm) != (BYTE)config_isregistered(p)) { hr = S_OK; break; }
+ }
+ }
+ else hr = S_OK;
+
+ if (pszOrigTypes) free(pszOrigTypes);
+
+ if (S_FALSE == hr && bRegCD != config_iscdplayer()) hr = S_OK;
+ if (S_FALSE == hr && bAgent != (IsAgentExist() && IsAgentScheduled())) hr = S_OK;
+ if (S_FALSE == hr && bExplorerMenu != config_isdircontext()) hr = S_OK;
+
+ return hr;
+}
+
+HRESULT setup_page_assoc::Validate(void)
+{
+ return S_OK;
+}
+
+HRESULT setup_page_assoc::CreateView(HWND hwndParent, HWND *phwnd)
+{
+ *phwnd = WACreateDialogParam(MAKEINTRESOURCEW((!IsWin8() ? IDD_SETUP_PAGE_ASSOC : IDD_SETUP_PAGE_ASSOC_WIN8)), hwndParent, ::DialogProc, (LPARAM)this);
+ return S_OK;
+}
+
+void setup_page_assoc::UpdateUI(void)
+{
+ TVINSERTSTRUCTW is = {0};
+ WORD *pm;
+ HTREEITEM hBranch[TYPE_CATEGORIES_NUM], hFirst(NULL), hCaret(NULL), hItem;
+ INT sBranch[TYPE_CATEGORIES_NUM] = {0};
+ INT ids[TYPE_CATEGORIES_NUM] = {IDS_FILETYPE_UNKNOWN, IDS_FILETYPE_AUDIO, IDS_FILETYPE_VIDEO, IDS_FILETYPE_PLAYLIST, IDS_FILETYPE_AUXILIARY};
+ INT i;
+
+ wchar_t szText[MAX_PATH] = {0}, buf[MAX_PATH] = {0}, buf2[MAX_PATH] = {0}, *p, *test;
+ if (!hwnd || !IsWindow(hwnd)) return;
+
+ DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ HWND hwndTree = GetDlgItem(hwnd,IDC_TREE_TYPES);
+ SendMessageW(hwndTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
+ if (!pszTypes) return;
+
+ for (i = 0; i < ARRAYSIZE(hBranch); i++)
+ {
+ hBranch[i] = NULL;
+ sBranch[i] = -1;
+ }
+
+ INT len = ARRAYSIZE(buf);
+ StringCchCopyW(buf, len, L"test.");
+ test = buf + lstrlenW(buf);
+ len -= (INT)(test - buf);
+
+ SendMessageW(hwndTree, WM_SETREDRAW, FALSE, 0L);
+
+ is.hInsertAfter = TVI_LAST;
+ is.item.mask = TVIF_STATE | TVIF_CHILDREN | TVIF_TEXT | TVIF_PARAM;
+ is.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED;
+ for(i = 0, pm = pMeta, p = pszTypes; *p != 0 && *(p+1) != 0; pm++, p += lstrlenW(p) + 1, i++)
+ {
+ StringCchCopyW(test, len, p);
+ OutputDebugStringW(test);
+ OutputDebugStringW(L"\r\n");
+ if (MF_TYPE_REREAD == GET_TYPE(*pm))
+ {
+ if (!in_get_extended_fileinfoW(buf, L"type", buf2, MAX_PATH))
+ ZeroMemory(buf2, sizeof(buf2));
+
+ *pm = *pm & 0x00FF;
+ switch(buf2[0])
+ {
+ case L'0': SET_TYPE(*pm, MF_TYPE_AUDIO); break;
+ case L'1': SET_TYPE(*pm, MF_TYPE_VIDEO); break;
+ }
+ }
+
+ INT index = GET_TYPE(*pm);
+ if (!hBranch[index])
+ {
+ is.hInsertAfter = TVI_SORT;
+ is.hParent = TVI_ROOT;
+ is.item.cChildren = 1;
+ is.item.state = INDEXTOSTATEIMAGEMASK(1) | ((expanded[index]) ? TVIS_EXPANDED : 0);
+ is.item.pszText = getStringW(ids[index], NULL, 0);
+ is.item.lParam = -(index + 1);
+ hBranch[index] = (HTREEITEM)SendMessageW(hwndTree, TVM_INSERTITEMW, 0, (LPARAM)&is);
+ is.item.cChildren = 0;
+ is.hInsertAfter = TVI_LAST;
+
+ wchar_t t[32] = {0};
+ StringCchPrintfW(t, ARRAYSIZE(t), L"#%d", index + 1);
+ if (!hFirst && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szTopExt, -1)) hFirst = hBranch[index];
+ if (!hCaret && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szCaretExt, -1)) hCaret = hBranch[index];
+ }
+
+ is.hParent = hBranch[index];
+
+ if (MF_SELECTED & *pm)
+ {
+ if (-1 == sBranch[index]) sBranch[index] = 1;
+ else if (0 == sBranch[index]) sBranch[index] = 2;
+ }
+ else
+ {
+ if (-1 == sBranch[index]) sBranch[index] = 0;
+ else if (1 == sBranch[index]) sBranch[index] = 2;
+ }
+
+ lstrcpynW(szText, p, MAX_PATH);
+ INT count = lstrlenW(szText);
+ CharUpperW(szText);
+ wchar_t szName[MAX_PATH] = {0};
+ if (GetExtensionName(buf, GET_TYPE(*pm), szName, MAX_PATH))
+ {
+ if (count) StringCchCatW(szText, MAX_PATH, L"\t");
+ StringCchCatW(szText, MAX_PATH, szName);
+ }
+
+ is.item.pszText = szText;
+ is.item.lParam = (LPARAM)i;
+ is.item.state = INDEXTOSTATEIMAGEMASK((MF_SELECTED & *pm)?2:1);
+
+ hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_INSERTITEMW, 0, (LPARAM)&is);
+
+ if (hItem)
+ {
+ if (!hFirst && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, p, -1, szTopExt, -1)) hFirst = hItem;
+ if (!hCaret && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, p, -1, szCaretExt, -1)) hCaret = hItem;
+ }
+ }
+
+ // insert cd
+ is.hParent = TVI_ROOT;
+ is.item.state = INDEXTOSTATEIMAGEMASK(bRegCD + 1);
+ is.item.pszText = getStringW(IDS_REGISTER_CDPLAYER, NULL, 0);
+ is.item.lParam = -ID_REGISTERCD;
+ hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_INSERTITEMW, 0, (LPARAM)&is);
+ if (!hFirst || !hCaret)
+ {
+ wchar_t t[32] = {0};
+ StringCchPrintfW(t, ARRAYSIZE(t), L"#%d", ID_REGISTERCD);
+ if (!hFirst && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szTopExt, -1)) hFirst = hItem;
+ if (!hCaret && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szCaretExt, -1)) hCaret = hItem;
+ }
+
+ // agent
+ BOOL bAgentExist = IsAgentExist();
+ HWND hwndCtrl = GetDlgItem(hwnd, IDC_CHK_AGENT);
+ if (hwndCtrl) EnableWindow(hwndCtrl, bAgentExist);
+ hwndCtrl = GetDlgItem(hwnd, IDC_LBL_AGENT_DESC);
+ if (hwndCtrl) EnableWindow(hwndCtrl, bAgentExist);
+
+ CheckDlgButton(hwnd, IDC_CHK_AGENT, (bAgent && bAgentExist) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwnd, IDC_CHK_CD, (bRegCD) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwnd, IDC_CHK_EXPLORER_MENU, (bExplorerMenu) ? BST_CHECKED : BST_UNCHECKED);
+
+ is.item.mask = TVIF_STATE;
+ is.item.stateMask = TVIS_STATEIMAGEMASK;
+
+ for (int i = 0; i < sizeof(hBranch)/sizeof(HTREEITEM); i++)
+ {
+ if (!hBranch[i]) continue;
+ is.item.hItem = hBranch[i];
+ is.item.state = INDEXTOSTATEIMAGEMASK(sBranch[i] + 1);
+ SendMessageW(hwndTree, TVM_SETITEM, 0, (LPARAM)&is.item);
+ SendMessageW(hwndTree, TVM_SORTCHILDREN, FALSE, (LPARAM)hBranch[i]);
+ }
+
+ if (hCaret) PostMessageW(hwndTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hCaret);
+ if (hFirst) PostMessageW(hwndTree, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)hFirst);
+
+ SendMessageW(hwndTree, WM_SETREDRAW, TRUE, 0L);
+}
+
+INT setup_page_assoc::TreeView_OnCustomDraw(NMTVCUSTOMDRAW *ptvcd)
+{
+ switch(ptvcd->nmcd.dwDrawStage)
+ {
+ case CDDS_PREPAINT:
+ return CDRF_DODEFAULT | CDRF_NOTIFYITEMDRAW;
+ case CDDS_ITEMPREPAINT:
+ return CDRF_DODEFAULT | CDRF_NOTIFYPOSTPAINT;
+ case CDDS_ITEMPOSTPAINT:
+ {
+ RECT rt;
+ WCHAR szText[256] = {0};
+ TVITEMW item = {0};
+
+ item.hItem = (HTREEITEM)ptvcd->nmcd.dwItemSpec;
+ item.mask = TVIF_TEXT | TVIF_STATE;
+ item.stateMask = TVIS_SELECTED;
+ item.pszText = szText;
+ item.cchTextMax = 256;
+ SendMessageW(ptvcd->nmcd.hdr.hwndFrom, TVM_GETITEMW, 0, (LPARAM)&item);
+ *(DWORD_PTR*)&rt = ptvcd->nmcd.dwItemSpec;
+ SendMessageW(ptvcd->nmcd.hdr.hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rt);
+ SetTextColor(ptvcd->nmcd.hdc, ptvcd->clrText);
+ SetBkColor(ptvcd->nmcd.hdc, ptvcd->clrTextBk);
+
+ DrawTextW(ptvcd->nmcd.hdc, item.pszText, -1, &rt, DT_EXPANDTABS | DT_NOPREFIX | DT_SINGLELINE | DT_CALCRECT);
+ rt.right += 8;
+ rt.top = ptvcd->nmcd.rc.top;
+ rt.bottom = ptvcd->nmcd.rc.bottom;
+
+ ExtTextOutW(ptvcd->nmcd.hdc, 0, 0, ETO_OPAQUE, &rt, L"", 0, NULL);
+ rt.left += 4;
+ DrawTextW(ptvcd->nmcd.hdc, item.pszText, -1, &rt, DT_EXPANDTABS | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER);
+
+ if ((TVIS_SELECTED & item.state) && ptvcd->nmcd.hdr.hwndFrom == GetFocus())
+ {
+ if (0 == (0x01/*UISF_HIDEFOCUS*/ & SendMessageW(ptvcd->nmcd.hdr.hwndFrom, 0x0129/*WM_QUERYUISTATE*/, 0, 0L)))
+ {
+ rt.left -= 4;
+ SetTextColor(ptvcd->nmcd.hdc, GetSysColor(COLOR_WINDOWTEXT));
+ SetBkColor(ptvcd->nmcd.hdc, GetSysColor(COLOR_WINDOW));
+ DrawFocusRect(ptvcd->nmcd.hdc, &rt);
+ }
+ }
+ }
+ break;
+ }
+ return CDRF_DODEFAULT;
+}
+
+BOOL setup_page_assoc::TreeView_OnClick(NMHDR *pnmh)
+{
+ TVHITTESTINFO ht;
+ GetCursorPos(&ht.pt);
+ MapWindowPoints(HWND_DESKTOP, pnmh->hwndFrom, &ht.pt, 1);
+ if(NULL != SendMessageW(pnmh->hwndFrom, TVM_HITTEST, 0, (LPARAM)&ht))
+ {
+ if ((TVHT_ONITEM | TVHT_ONITEMRIGHT) & ht.flags)
+ {
+ TreeView_OnItemStateClick(pnmh->hwndFrom, ht.hItem);
+ if (TVHT_ONITEMSTATEICON & ht.flags) return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOL setup_page_assoc::TreeView_OnKeyDown(NMTVKEYDOWN *ptvkd)
+{
+ switch(ptvkd->wVKey)
+ {
+ case VK_SPACE:
+ {
+ HTREEITEM hItem = (HTREEITEM)(HTREEITEM)SendMessageW(ptvkd->hdr.hwndFrom, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, 0L);
+ if (hItem) TreeView_OnItemStateClick(ptvkd->hdr.hwndFrom, hItem);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void setup_page_assoc::TreeView_OnItemStateClick(HWND hwndTree, HTREEITEM hItem)
+{
+ HTREEITEM hParent = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_PARENT, (LPARAM)hItem);
+ HTREEITEM hChild = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)hItem);
+ TVITEMW item = {0};
+ item.hItem = hItem;
+ item.mask = TVIF_STATE | TVIF_PARAM;
+ item.stateMask = TVIS_STATEIMAGEMASK;
+
+ if (!SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) return;
+ INT state = ((item.state>>12) - 1);
+ INT param = (INT)item.lParam;
+
+ SendMessageW(hwndTree, WM_SETREDRAW, FALSE, 0L);
+
+ state = (2 == state) ? 1 : !state;
+
+ item.mask = TVIF_STATE;
+ item.state = INDEXTOSTATEIMAGEMASK(state + 1);
+ SendMessageW(hwndTree, TVM_SETITEMW, 0, (LPARAM)&item);
+
+ if (!hChild)
+ {
+ INT count = 1, selcount = state;
+
+ item.hItem = hItem;
+ while(NULL != (item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_PREVIOUS, (LPARAM)item.hItem)))
+ {
+ count++;
+ if (!SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) continue;
+ if (2 == (item.state>>12)) selcount++;
+ }
+ item.hItem = hItem;
+ while(NULL != (item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)item.hItem)))
+ {
+ count++;
+ if (!SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) continue;
+ if (2 == (item.state>>12)) selcount++;
+ }
+
+ item.hItem = hParent;
+ item.state = INDEXTOSTATEIMAGEMASK(((!selcount) ? 1 : ((selcount == count) ? 2 :3)));
+ SendMessageW(hwndTree, TVM_SETITEMW, 0, (LPARAM)&item);
+ if (param >= 0) pMeta[param] = (pMeta[param] & ~MF_SELECTED) | ((state) ? MF_SELECTED : 0);
+ else
+ {
+ switch(-param)
+ {
+ case ID_REGISTERCD: bRegCD = state; break;
+ }
+ }
+ }
+ else
+ {
+ item.hItem = hChild;
+ while(item.hItem)
+ {
+ item.mask = TVIF_PARAM;
+ if (SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item) && item.lParam >= 0) pMeta[item.lParam] = (pMeta[item.lParam] & ~MF_SELECTED) | ((state) ? MF_SELECTED : 0);
+
+ item.mask = TVIF_STATE;
+ item.state = INDEXTOSTATEIMAGEMASK(state + 1);
+ SendMessageW(hwndTree, TVM_SETITEMW, 0, (LPARAM)&item);
+ item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)item.hItem);
+ }
+ }
+ UpdateWindow(hwnd);
+ SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
+ SendMessageW(hwndTree, WM_SETREDRAW, TRUE, 0L);
+ SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
+ InvalidateRect(hwndTree, NULL, FALSE);
+}
+
+INT_PTR setup_page_assoc::OnInitDialog(HWND hwndFocus, LPARAM lParam)
+{
+ HWND hwndTree = GetDlgItem(hwnd, IDC_TREE_TYPES);
+ if (hwndTree)
+ {
+ HIMAGELIST himl = ImageList_LoadImage(hMainInstance, MAKEINTRESOURCE(IDB_CHECKBOX), 16, 1, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_LOADTRANSPARENT);
+ if (himl) himl = (HIMAGELIST) SendMessageW(hwndTree, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl);
+ if (himl) ImageList_Destroy(himl);
+
+ WNDPROC fnOldProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwndTree, GWLP_WNDPROC, (LONGX86)(LONG_PTR)TreeViewProc);
+ if (fnOldProc) SetPropW(hwndTree, L"TVPROC", fnOldProc);
+ }
+ UpdateUI();
+ return 0;
+}
+
+void setup_page_assoc::OnDestroy(void)
+{
+ HWND hwndTree = GetDlgItem(hwnd, IDC_TREE_TYPES);
+ if (hwndTree)
+ {
+ TVITEMW item = {0};
+ HIMAGELIST himl;
+ INT index1(-1), index2(-1);
+ wchar_t *p;
+
+ ZeroMemory(expanded, sizeof(expanded));
+ ZeroMemory(szTopExt, sizeof(szTopExt));
+ ZeroMemory(szCaretExt, sizeof(szCaretExt));
+
+ item.mask = TVIF_PARAM | TVIF_STATE;
+ item.stateMask = TVIS_EXPANDED;
+ item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_ROOT, 0L);
+ while(item.hItem)
+ {
+ if (SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item))
+ {
+ INT param = (INT)-item.lParam;
+ if (param < TYPE_CATEGORIES_NUM) expanded[param] = (BYTE)(TVIS_EXPANDED & item.state);
+ }
+ item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)item.hItem);
+ }
+ item.mask = TVIF_PARAM;
+ item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_FIRSTVISIBLE, 0L);
+ if (item.hItem && SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) index1 = (INT)item.lParam;
+ item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, 0L);
+ if (item.hItem && SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) index2 = (INT)item.lParam;
+
+ if (index1 < 0) StringCchPrintfW(szTopExt, ARRAYSIZE(szTopExt), L"#%d", -index1);
+ if (index2 < 0) StringCchPrintfW(szCaretExt, ARRAYSIZE(szCaretExt), L"#%d", -index2);
+
+ if (index1 >= 0 || index2 >= 0)
+ {
+ INT i;
+ for(i = 0, p = pszTypes; *p != 0; p += lstrlenW(p) + 1, i++)
+ {
+ if (index1 == i)
+ {
+ StringCchCopyW(szTopExt, ARRAYSIZE(szTopExt), p);
+ if (index2 < 0) break;
+ index1 = -1;
+ }
+ if (index2 == i)
+ {
+ StringCchCopyW(szCaretExt, ARRAYSIZE(szCaretExt), p);
+ if (index1 < 0) break;
+ index2 = -1;
+ }
+ }
+ }
+ himl = (HIMAGELIST) SendMessageW(hwndTree, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)NULL);
+ if (himl) ImageList_Destroy(himl);
+ }
+}
+
+void setup_page_assoc::OnSize(UINT nType, INT cx, INT cy)
+{
+ RECT rw;
+ INT h, r;
+ h = cy;
+ r = cx;
+
+ HWND hwndCtrl = GetDlgItem(hwnd, IDC_LBL_HEADER);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ SetWindowPos(hwndCtrl, NULL, 0, 0, cx - rw.left*2, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
+ }
+
+ if (IsWin8())
+ {
+ // hide the treeview (as needed to process things nicely but needs to be hidden on Windows 8 and higher as they work differently)
+ hwndCtrl = GetDlgItem(hwnd, IDC_TREE_TYPES);
+ if (hwndCtrl)
+ {
+ SetWindowPos(hwndCtrl, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_HIDEWINDOW);
+ }
+ return;
+ }
+
+ hwndCtrl = GetDlgItem(hwnd, IDC_CHK_EXPLORER_MENU);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ h = cy - (((rw.bottom - rw.top)*3) + 6);
+ r = max(0, (cx - (rw.right - rw.left))/2) + (rw.right - rw.left);
+ SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12,
+ h, rw.right - rw.left + 26,
+ rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER);
+
+ }
+ hwndCtrl = GetDlgItem(hwnd, IDC_CHK_AGENT);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12,
+ h + (rw.bottom - rw.top) + 2,
+ rw.right - rw.left + 26,
+ rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ hwndCtrl = GetDlgItem(hwnd, IDC_LBL_AGENT_DESC);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12,
+ h + (rw.bottom - rw.top)*2 + 2,
+ rw.right - rw.left + 26,
+ rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ hwndCtrl = GetDlgItem(hwnd, IDC_TREE_TYPES);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12,
+ rw.top, rw.right - rw.left + 26,
+ h - rw.top - 4, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+}
+
+void setup_page_assoc::OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl)
+{
+ switch(nCtrlID)
+ {
+ case IDC_CHK_EXPLORER_MENU:
+ {
+ switch (nEvntID)
+ {
+ case BN_CLICKED:
+ bExplorerMenu = (BST_CHECKED == (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L)));
+ break;
+ }
+ break;
+ }
+ case IDC_CHK_AGENT:
+ {
+ switch (nEvntID)
+ {
+ case BN_CLICKED:
+ bAgent = (BST_CHECKED == (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L)));
+ break;
+ }
+ break;
+ }
+ case IDC_CHK_CD:
+ {
+ switch (nEvntID)
+ {
+ case BN_CLICKED:
+ bRegCD = (BST_CHECKED == (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L)));
+ break;
+ }
+ break;
+ }
+ }
+}
+
+BOOL setup_page_assoc::OnNotify(INT nCtrlID, NMHDR *pnmh, LRESULT *pResult)
+{
+ switch(nCtrlID)
+ {
+ case IDC_TREE_TYPES:
+ switch(pnmh->code)
+ {
+ case NM_CUSTOMDRAW: *pResult = TreeView_OnCustomDraw((NMTVCUSTOMDRAW*)pnmh); return TRUE;
+ case NM_CLICK: *pResult = TreeView_OnClick(pnmh); return TRUE;
+ case TVN_KEYDOWN: *pResult = TreeView_OnKeyDown((NMTVKEYDOWN*)pnmh); return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+INT_PTR setup_page_assoc::PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam);
+ case WM_DESTROY: OnDestroy(); break;
+ case WM_SIZE: OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam)); break;
+ case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ case WM_NOTIFY:
+ {
+ LRESULT result = 0;
+ if (OnNotify((INT)wParam, (NMHDR*)lParam, &result))
+ {
+ SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (LONGX86)(LONG_PTR)result);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ setup_page_assoc *pInst = (setup_page_assoc*)GetPropW(hwnd, L"SETUPPAGE");
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ pInst = (setup_page_assoc*)lParam;
+ if (pInst)
+ {
+ pInst->hwnd = hwnd;
+ SetPropW(hwnd, L"SETUPPAGE", pInst);
+ }
+ break;
+
+ case WM_DESTROY:
+ if (pInst)
+ {
+ pInst->PageDlgProc(uMsg, wParam, lParam);
+ RemovePropW(hwnd, L"SETUPPAGE");
+ pInst = NULL;
+ }
+ break;
+ }
+
+ return (pInst) ? pInst->PageDlgProc(uMsg, wParam, lParam) : 0;
+}
+
+static void TreeViewCheckItems(HWND hwnd, TVITEMW *pItem)
+{
+ while (pItem->hItem)
+ {
+ SendMessageW(hwnd, TVM_SETITEMW, 0, (LPARAM)pItem);
+ HTREEITEM hChild = (HTREEITEM)SendMessageW(hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)pItem->hItem);
+ if (hChild)
+ {
+ HTREEITEM hTemp = pItem->hItem;
+ pItem->hItem = hChild;
+ TreeViewCheckItems(hwnd, pItem);
+ pItem->hItem = hTemp;
+ }
+ pItem->hItem = (HTREEITEM)SendMessageW(hwnd, TVM_GETNEXTITEM , TVGN_NEXT, (LPARAM)pItem->hItem);
+ }
+}
+
+static LRESULT WINAPI TreeViewProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC fnOldProc = (WNDPROC)GetPropW(hwnd, L"TVPROC");
+ if (!fnOldProc) return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ switch(uMsg)
+ {
+ case WM_DESTROY:
+ RemovePropW(hwnd, L"TVPROC");
+ SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)fnOldProc);
+ break;
+
+ case WM_CHAR:
+ if (0x01/*(CTRL_A)*/ == wParam)
+ {
+ TVITEMW item = {0};
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.stateMask = TVIS_STATEIMAGEMASK;
+ item.state = INDEXTOSTATEIMAGEMASK(2);
+ item.hItem = (HTREEITEM)SendMessageW(hwnd, TVM_GETNEXTITEM , TVGN_ROOT, 0L);
+ SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
+ TreeViewCheckItems(hwnd, &item);
+ SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS setup_page_assoc
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(API_SETUPPAGE_GET_NAME, GetName)
+CB(API_SETUPPAGE_CREATEVIEW, CreateView)
+CB(API_SETUPPAGE_SAVE, Save)
+CB(API_SETUPPAGE_REVERT, Revert)
+CB(API_SETUPPAGE_ISDIRTY, IsDirty)
+CB(API_SETUPPAGE_VALIDATE, Validate)
+END_DISPATCH
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_assoc.h b/Src/Winamp/setup/spage_assoc.h
new file mode 100644
index 00000000..f18270b8
--- /dev/null
+++ b/Src/Winamp/setup/spage_assoc.h
@@ -0,0 +1,57 @@
+#ifndef WINAMP_ASSOCIATIONS_SETUP_PAGE_HEADER
+#define WINAMP_ASSOCIATIONS_SETUP_PAGE_HEADER
+
+#include "./ifc_setuppage.h"
+#include <commctrl.h>
+
+#define TYPE_CATEGORIES_NUM 5
+
+class setup_page_assoc : public ifc_setuppage
+{
+public:
+ setup_page_assoc();
+ virtual ~setup_page_assoc();
+
+public:
+ size_t AddRef();
+ size_t Release();
+ HRESULT GetName(bool bShort, const wchar_t **pszName);
+ HRESULT Save(HWND hwndText);
+ HRESULT CreateView(HWND hwndParent, HWND *phwnd);
+ HRESULT Revert(void);
+ HRESULT IsDirty(void);
+ HRESULT Validate(void);
+
+protected:
+ INT_PTR PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR OnInitDialog(HWND hwndFocus, LPARAM lParam);
+ void OnDestroy(void);
+ void OnSize(UINT nType, INT cx, INT cy);
+ void OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl);
+ BOOL OnNotify(INT nCtrlID, NMHDR *pnmh, LRESULT *pResult);
+
+ BOOL TreeView_OnClick(NMHDR *pnmh);
+ void TreeView_OnItemStateClick(HWND hwndTree, HTREEITEM hItem);
+ BOOL TreeView_OnKeyDown(NMTVKEYDOWN *ptvkd);
+ INT TreeView_OnCustomDraw(NMTVCUSTOMDRAW *ptvcd);
+
+ void UpdateUI(void);
+
+private:
+ size_t ref;
+ HWND hwnd;
+ wchar_t *pszTypes;
+ WORD *pMeta;
+ BYTE expanded[TYPE_CATEGORIES_NUM];
+ wchar_t szTopExt[32];
+ wchar_t szCaretExt[32];
+ BOOL bRegCD;
+ BOOL bAgent;
+ BOOL bExplorerMenu;
+
+protected:
+ friend static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ RECVS_DISPATCH;
+};
+
+#endif //WINAMP_ASSOCIATIONS_SETUP_PAGE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_connect.cpp b/Src/Winamp/setup/spage_connect.cpp
new file mode 100644
index 00000000..af0e84cc
--- /dev/null
+++ b/Src/Winamp/setup/spage_connect.cpp
@@ -0,0 +1,313 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include "./spage_connect.h"
+#include "./setup_resource.h"
+#include "../nu/ns_wc.h"
+#include "./langutil.h"
+
+setup_page_connect::setup_page_connect() : ref(1), hwnd(NULL)
+{
+ inetMode = 0;
+ bPort80 = FALSE;
+ szProxy[MAX_PATH] = 0x00;
+}
+setup_page_connect::~setup_page_connect()
+{
+}
+
+size_t setup_page_connect::AddRef()
+{
+ return ++ref;
+}
+
+size_t setup_page_connect::Release()
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+HRESULT setup_page_connect::GetName(bool bShort, const wchar_t **pszName)
+{
+ static wchar_t szName[64] = {0,};
+ *pszName = (*szName) ? szName : getStringW(IDS_PAGE_CONNECTIVITY, szName, sizeof(szName)/sizeof(wchar_t));
+ return S_OK;
+}
+
+HRESULT setup_page_connect::Save(HWND hwndText)
+{
+ HRESULT hr(S_OK);
+ INT count;
+ wchar_t app[MAX_PATH] = {0}, *p;
+
+ if (S_FALSE == IsDirty()) return S_OK;
+
+ count = MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, app, sizeof(app)/sizeof(wchar_t));
+ if (!count) hr = S_FALSE;
+ if (S_FALSE == hr) return hr;
+
+ if (config_inet_mode != inetMode)
+ {
+ wchar_t szText[MAX_PATH] = {0};
+ config_inet_mode = (char)inetMode;
+ WritePrivateProfileStringW(app, L"inet_mode", _itow(inetMode, szText, 10), INI_FILE);
+ }
+
+ if (2 == inetMode) szProxy[0] = 0x00;
+ if (0 == *szProxy) config_proxy[0] = 0x00;
+ else
+ {
+ count = WideCharToMultiByteSZ(CP_ACP, 0, szProxy, -1, config_proxy, sizeof(config_proxy)/sizeof(char), NULL, NULL);
+ if (!count) hr = S_FALSE;
+ }
+ if (!WritePrivateProfileStringW(app, L"Proxy", szProxy, INI_FILE)) hr = S_FALSE;
+ if (bPort80 && 0x00 == *szProxy) bPort80 = FALSE;
+ p = (bPort80) ? L"1" : L"";
+ if (!WritePrivateProfileStringW(app, L"proxyonly80", p, INI_FILE)) hr = S_FALSE;
+ WritePrivateProfileStringW(app, L"proxy80", p, INI_FILE); // old
+
+ if (hwnd) UpdateUI();
+ return hr;
+}
+
+HRESULT setup_page_connect::Revert(void)
+{
+ HRESULT hr(S_OK);
+ INT count;
+ wchar_t app[MAX_PATH] = {0};
+
+ count = MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, app, sizeof(app)/sizeof(wchar_t));
+ if (!count) hr = S_FALSE;
+
+ if (config_inet_mode==3) isInetAvailable(); // autodetect
+ inetMode = config_inet_mode;
+
+ if (*config_proxy && 2 != inetMode)
+ {
+ count = MultiByteToWideCharSZ(CP_ACP, 0, config_proxy, -1, szProxy, sizeof(szProxy)/sizeof(wchar_t));
+ if (!count) hr = S_FALSE;
+ }
+ else szProxy[0] = 0x00;
+
+ bPort80 = (0x00 != *szProxy && 0 != GetPrivateProfileIntW(app, L"proxyonly80", 0, INI_FILE));
+
+ if (hwnd) UpdateUI();
+
+ return hr;
+}
+
+HRESULT setup_page_connect::IsDirty(void)
+{
+ INT res;
+ wchar_t app[MAX_PATH] = {0};
+ char szTest[MAX_PATH] = {0};
+
+ if (inetMode != config_inet_mode) return S_OK;
+
+ if (2 == inetMode || 0 == *szProxy) szTest[0] = 0x00;
+ else
+ {
+ res = WideCharToMultiByteSZ(CP_ACP, 0, szProxy, -1, szTest, sizeof(szTest)/sizeof(char), NULL, NULL);
+ if (!res) return E_OUTOFMEMORY;
+ }
+
+ res = CompareStringA(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
+ NORM_IGNORECASE, szTest, -1, config_proxy, -1);
+ if (0 == res) return E_UNEXPECTED;
+ if (CSTR_EQUAL != res) return S_OK;
+
+ res = MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, app, sizeof(app)/sizeof(wchar_t));
+ if (!res) return E_OUTOFMEMORY;
+
+ return ((bPort80 && 0x00 != *szProxy) != ( 0 != GetPrivateProfileIntW(app, L"proxyonly80", 0, INI_FILE))) ? S_OK : S_FALSE;
+}
+
+HRESULT setup_page_connect::Validate(void)
+{
+ return S_OK;
+}
+
+HRESULT setup_page_connect::CreateView(HWND hwndParent, HWND *phwnd)
+{
+ *phwnd = WACreateDialogParam(MAKEINTRESOURCEW(IDD_SETUP_PAGE_CONNECT), hwndParent, ::DialogProc, (LPARAM)this);
+ return S_OK;
+}
+
+void setup_page_connect::UpdateUI(void)
+{
+ int count;
+
+ if (!hwnd || !IsWindow(hwnd)) return;
+
+ CheckDlgButton(hwnd, IDC_CHK_PORT80, (bPort80) ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemTextW(hwnd, IDC_EDT_SERVER, szProxy);
+
+ HWND hwndCB = GetDlgItem(hwnd, IDC_CB_CONNECT);
+ if (!hwndCB || !IsWindow(hwndCB)) return;
+
+ count = (INT)SendMessageW(hwndCB, CB_GETCOUNT, 0, 0L);
+ if (count > 0)
+ {
+ int index;
+ for (index = 0; index < count && inetMode != (INT)SendMessageW(hwndCB, CB_GETITEMDATA, index, 0L); index++);
+ if (index == count)
+ {
+ inetMode = (INT)SendMessageW(hwndCB, CB_GETITEMDATA, 0, 0L);
+ index = 0;
+ }
+ SendMessageW(hwndCB, CB_SETCURSEL, index, 0L);
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_CB_CONNECT, CBN_SELCHANGE), (LPARAM)hwndCB);
+ }
+}
+
+void setup_page_connect::ComboBox_OnSelChange(HWND hwndCtrl)
+{
+ INT proxyList[] = { IDC_GRP_PROXY, IDC_LBL_SERVER, IDC_EDT_SERVER, IDC_CHK_PORT80, };
+ INT index;
+
+ index = (INT)SendMessageW(hwndCtrl, CB_GETCURSEL, 0, 0L);
+ if (CB_ERR == index) return;
+
+ inetMode = (INT)SendMessageW(hwndCtrl, CB_GETITEMDATA, index, 0L);
+
+ for (int i = 0; i < sizeof(proxyList)/sizeof(INT); i++)
+ {
+ HWND hwndItem = GetDlgItem(hwnd, proxyList[i]);
+ if (IsWindow(hwndItem)) ShowWindow(hwndItem, (2 != inetMode) ? SW_SHOWNA : SW_HIDE);
+ }
+}
+
+INT_PTR setup_page_connect::OnInitDialog(HWND hwndFocus, LPARAM lParam)
+{
+ UINT connID[] = { IDS_INST_INET1, IDS_INST_INET2, IDS_INST_INET3, };
+ HWND hwndCB = GetDlgItem(hwnd, IDC_CB_CONNECT);
+
+ CheckDlgButton(hwnd, IDC_CHK_PORT80, (bPort80) ? BST_CHECKED : BST_UNCHECKED);
+ //SendDlgItemMessageW(hwnd, IDC_EDT_SERVER, EM_LIMITTEXT, sizeof(szProxy)/sizeof(wchar_t), 0);
+ SetDlgItemTextW(hwnd, IDC_EDT_SERVER, szProxy);
+
+ if (inetMode < 0) inetMode = 0;
+ else if (inetMode >= sizeof(connID)/sizeof(INT)) inetMode = sizeof(connID)/sizeof(INT) - 1;
+
+ for(int i = 0; i < sizeof(connID)/sizeof(INT); i++)
+ {
+ INT index = (INT)SendMessageW(hwndCB, CB_ADDSTRING,0, (LPARAM)getStringW(connID[i], NULL, 0));
+ if (CB_ERR != index) SendMessageW(hwndCB, CB_SETITEMDATA, index, (LPARAM)i);
+ if (inetMode == i) SendMessageW(hwndCB, CB_SETCURSEL, index, 0L);
+ }
+
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_CB_CONNECT, CBN_SELCHANGE), (LPARAM)hwndCB);
+
+ return 0;
+}
+
+void setup_page_connect::OnSize(UINT nType, INT cx, INT cy)
+{
+ INT ctrlList[] = { IDC_CB_CONNECT, IDC_GRP_PROXY, IDC_LBL_SERVER, IDC_EDT_SERVER, IDC_CHK_PORT80, };
+ RECT rw;
+ HDWP hdwp = BeginDeferWindowPos(sizeof(ctrlList)/sizeof(INT));
+ if (!hdwp) return;
+
+ for (int i = 0; i < sizeof(ctrlList)/sizeof(INT); i++)
+ {
+ HWND hwndCtrl = GetDlgItem(hwnd, ctrlList[i]);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ hdwp = DeferWindowPos(hdwp, hwndCtrl, NULL, max(0, (cx - (rw.right - rw.left))/2), rw.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
+ }
+ }
+ if (hdwp) EndDeferWindowPos(hdwp);
+}
+
+void setup_page_connect::OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl)
+{
+ switch(nCtrlID)
+ {
+ case IDC_CB_CONNECT:
+ switch(nEvntID)
+ {
+ case CBN_SELCHANGE: ComboBox_OnSelChange(hwndCtrl); break;
+ }
+ break;
+ case IDC_EDT_SERVER:
+ switch(nEvntID)
+ {
+ case EN_CHANGE:
+ GetWindowTextW(hwndCtrl, szProxy, sizeof(szProxy)/sizeof(wchar_t));
+ EnableWindow(GetDlgItem(hwnd, IDC_CHK_PORT80), 0x00 != *szProxy);
+ if(0x00 == *szProxy)
+ {
+ CheckDlgButton(hwnd, IDC_CHK_PORT80, BST_UNCHECKED);
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_CHK_PORT80, BN_CLICKED), (LPARAM)GetDlgItem(hwnd, IDC_CHK_PORT80));
+ }
+ break;
+ }
+ break;
+ case IDC_CHK_PORT80:
+ switch(nEvntID)
+ {
+ case BN_CLICKED: bPort80 = (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L)); break;
+ }
+ break;
+ }
+}
+
+INT_PTR setup_page_connect::PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam);
+ case WM_DESTROY: break;
+ case WM_SIZE: OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam)); break;
+ case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ }
+ return 0;
+}
+
+static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ setup_page_connect *pInst = (setup_page_connect*)GetPropW(hwnd, L"SETUPPAGE");
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ pInst = (setup_page_connect*)lParam;
+ if (pInst)
+ {
+ pInst->hwnd = hwnd;
+ SetPropW(hwnd, L"SETUPPAGE", pInst);
+ }
+ break;
+ case WM_DESTROY:
+ if (pInst)
+ {
+ pInst->PageDlgProc(uMsg, wParam, lParam);
+ RemovePropW(hwnd, L"SETUPPAGE");
+ pInst = NULL;
+ }
+ break;
+ }
+ return (pInst) ? pInst->PageDlgProc(uMsg, wParam, lParam) : 0;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS setup_page_connect
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(API_SETUPPAGE_GET_NAME, GetName)
+CB(API_SETUPPAGE_CREATEVIEW, CreateView)
+CB(API_SETUPPAGE_SAVE, Save)
+CB(API_SETUPPAGE_REVERT, Revert)
+CB(API_SETUPPAGE_ISDIRTY, IsDirty)
+CB(API_SETUPPAGE_VALIDATE, Validate)
+END_DISPATCH
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_connect.h b/Src/Winamp/setup/spage_connect.h
new file mode 100644
index 00000000..c4af10d7
--- /dev/null
+++ b/Src/Winamp/setup/spage_connect.h
@@ -0,0 +1,45 @@
+#ifndef WINAMP_CONNECTIOVITY_SETUP_PAGE_HEADER
+#define WINAMP_CONNECTIOVITY_SETUP_PAGE_HEADER
+
+#include "./ifc_setuppage.h"
+
+class setup_page_connect : public ifc_setuppage
+{
+
+public:
+ setup_page_connect();
+ virtual ~setup_page_connect();
+
+public:
+ size_t AddRef();
+ size_t Release();
+ HRESULT GetName(bool bShort, const wchar_t **pszName);
+ HRESULT Save(HWND hwndText);
+ HRESULT CreateView(HWND hwndParent, HWND *phwnd);
+ HRESULT Revert(void);
+ HRESULT IsDirty(void);
+ HRESULT Validate(void);
+protected:
+ INT_PTR PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR OnInitDialog(HWND hwndFocus, LPARAM lParam);
+ void OnSize(UINT nType, INT cx, INT cy);
+ void OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl);
+
+ void ComboBox_OnSelChange(HWND hwndCtrl);
+
+ void UpdateUI(void);
+
+private:
+ size_t ref;
+ HWND hwnd;
+ INT inetMode;
+ BOOL bPort80;
+ WCHAR szProxy[MAX_PATH];
+
+protected:
+ friend static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ RECVS_DISPATCH;
+};
+
+
+#endif //WINAMP_CONNECTIOVITY_SETUP_PAGE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_feedback.cpp b/Src/Winamp/setup/spage_feedback.cpp
new file mode 100644
index 00000000..4a2515e4
--- /dev/null
+++ b/Src/Winamp/setup/spage_feedback.cpp
@@ -0,0 +1,392 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include "./spage_feedback.h"
+#include "./setup_resource.h"
+#include "../nu/ns_wc.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+#include "./langutil.h"
+
+
+#define FF_ALLOWFEEDBACK 0x0001
+#define FF_ANNOUNCEMENTS 0x0010
+#define FF_STATISTICS 0x0020
+
+#define GENDER_UNKNOWN 0
+#define GENDER_MALE 1
+#define GENDER_FEMALE 2
+
+setup_page_feedback::setup_page_feedback() : ref(1), hwnd(NULL)
+{
+ szEmail[0] = 0x00;
+ szCountry[0] = 0x00;
+ gender = GENDER_UNKNOWN;
+ flags = FF_ALLOWFEEDBACK | FF_ANNOUNCEMENTS | FF_STATISTICS;
+}
+
+setup_page_feedback::~setup_page_feedback()
+{
+}
+
+size_t setup_page_feedback::AddRef()
+{
+ return ++ref;
+}
+
+size_t setup_page_feedback::Release()
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+HRESULT setup_page_feedback::GetName(bool bShort, const wchar_t **pszName)
+{
+ if (bShort)
+ {
+ static wchar_t szShortName[32] = {0};
+ *pszName = (*szShortName) ? szShortName : getStringW(IDS_PAGE_FEEDBACK, szShortName, sizeof(szShortName)/sizeof(wchar_t));
+ }
+ else
+ {
+ static wchar_t szLongName[64] = {0};
+ *pszName = (*szLongName) ? szLongName : getStringW(IDS_PAGE_FEEDBACK_LONG, szLongName, sizeof(szLongName)/sizeof(wchar_t));
+ }
+ return S_OK;
+}
+
+HRESULT setup_page_feedback::Save(HWND hwndText)
+{
+ HRESULT hr(S_OK);
+
+ int r, s;
+ char data[8192] = {0};
+ char str[32] = {0};
+
+ if (FF_ALLOWFEEDBACK & flags)
+ {
+ s = GetPrivateProfileIntW(L"WinampReg", L"RegDataLen", 0, INI_FILE);
+ if (s > 0) GetPrivateProfileStructA("WinampReg", "RegData2", data, s, INI_FILEA);
+ if (!SetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_EMAIL), szEmail, -1)) hr = E_UNEXPECTED;
+ if (!SetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_COUNTRY), szCountry, lstrlenW(szCountry)*sizeof(wchar_t))) hr = E_UNEXPECTED;
+ if (!SetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_GENDER), &gender, sizeof(gender))) hr = E_UNEXPECTED;
+ r = (FF_ANNOUNCEMENTS == (FF_ANNOUNCEMENTS & flags));
+ if (!SetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_ANNOUNCEMENTS), &r, sizeof(r))) hr = E_UNEXPECTED;
+ config_newverchk2 = (FF_STATISTICS == (FF_STATISTICS & flags));
+ }
+ else config_newverchk2 = 0;
+
+ WritePrivateProfileStringW(AutoWide(app_name), L"newverchk2", (config_newverchk2) ? L"1" : L"0", INI_FILE);
+
+ s = GetMetricsSize(data);
+
+ StringCchPrintfA(str, 32, "%d", s);
+ WritePrivateProfileStringA("WinampReg", "RegDataLen", (s) ? str : NULL, INI_FILEA);
+ WritePrivateProfileStructA("WinampReg", "RegData2", (s) ? data : NULL, s, INI_FILEA);
+
+ if (hwnd) UpdateUI();
+ return hr;
+}
+
+HRESULT setup_page_feedback::Revert(void)
+{
+ HRESULT hr(S_OK);
+ char data[8192] = {0, };
+ DWORD sendinfo;
+
+ flags = FF_ALLOWFEEDBACK;
+
+ if (config_newverchk2) flags |= FF_STATISTICS;
+
+ int s = GetPrivateProfileIntW(L"WinampReg", L"RegDataLen", 0, INI_FILE);
+ if (s > 0) GetPrivateProfileStructA("WinampReg", "RegData2", data, s, INI_FILEA);
+
+ GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_EMAIL), szEmail, sizeof(szEmail));
+ GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_COUNTRY), szCountry, sizeof(szCountry));
+ GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_GENDER), &gender, sizeof(gender));
+ GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_ANNOUNCEMENTS), &sendinfo, sizeof(sendinfo));
+ if (sendinfo) flags |= FF_ANNOUNCEMENTS;
+ if (hwnd) UpdateUI();
+ return hr;
+}
+
+HRESULT setup_page_feedback::IsDirty(void)
+{
+ char data[8192] = {0};
+ wchar_t szTest[256] = {0};
+ int r;
+ DWORD lcid;
+
+ lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ if (0 != (FF_STATISTICS & flags) != !!config_newverchk2) return S_OK;
+
+ int s = GetPrivateProfileIntW(L"WinampReg", L"RegDataLen", 0, INI_FILE);
+ if (s > 0) GetPrivateProfileStructA("WinampReg", "RegData2", data, s, INI_FILEA);
+
+ if (!GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_EMAIL), szTest, sizeof(szTest))) return E_UNEXPECTED;
+ r = CompareStringW(lcid, NORM_IGNORECASE, szTest, -1, szEmail, -1);
+ if (0 == r) return E_UNEXPECTED;
+ if (CSTR_EQUAL != r) return S_OK;
+
+ if (!GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_COUNTRY), szTest, sizeof(szTest))) return E_UNEXPECTED;
+ r = CompareStringW(lcid, NORM_IGNORECASE, szTest, -1, szCountry, -1);
+ if (0 == r) return E_UNEXPECTED;
+ if (CSTR_EQUAL != r) return S_OK;
+ r = 0;
+ if (!GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_GENDER), &r, sizeof(r))) return E_UNEXPECTED;
+ if (r != gender) return S_OK;
+ r = 0;
+ if (!GetMetricsValueW(data, MAKEINTRESOURCEA(METRICS_ANNOUNCEMENTS), &r, sizeof(r))) return E_UNEXPECTED;
+ if (r != (FF_ANNOUNCEMENTS == (FF_ANNOUNCEMENTS & flags))) return S_OK;
+
+ return S_FALSE;
+}
+
+HRESULT setup_page_feedback::Validate(void)
+{
+ wchar_t *p;
+
+ if (0 == (FF_ALLOWFEEDBACK & flags) || !*szEmail) return S_OK;
+ for (p = szEmail; *p != 0x00 && *p != L'@'; p = CharNextW(p));
+
+ if (L'@' != *p || 0x00 == *CharNextW(p))
+ {
+ WCHAR szTitle[128] = {0};
+ HWND hwndTop, hwndTest;
+ hwndTop = hwnd;
+ while(NULL != (hwndTest = GetParent(hwndTop))) hwndTop = hwndTest;
+ GetWindowTextW(hwndTop, szTitle, sizeof(szTitle)/sizeof(WCHAR));
+ if (hwndTop)
+ {
+ MessageBoxW(hwndTop, getStringW(IDS_PAGE_INCORRECT_EMAIL_ADDRESS, NULL, 0),
+ szTitle, MB_OK | MB_ICONERROR);
+ return S_FALSE;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT setup_page_feedback::CreateView(HWND hwndParent, HWND *phwnd)
+{
+ *phwnd = WACreateDialogParam(MAKEINTRESOURCEW(IDD_SETUP_PAGE_FEEDBACK), hwndParent, ::DialogProc, (LPARAM)this);
+ return S_OK;
+}
+
+void setup_page_feedback::UpdateUI(void)
+{
+
+ HWND hwndCB;
+ if (!hwnd || !IsWindow(hwnd)) return;
+
+ CheckDlgButton(hwnd, IDC_CHK_ANNOUNCEMENTS, (FF_ANNOUNCEMENTS & flags) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwnd, IDC_CHK_STATISTICS, (FF_STATISTICS & flags) ? BST_CHECKED : BST_UNCHECKED);
+
+ SetDlgItemTextW(hwnd, IDC_EDT_EMAIL, szEmail);
+ SetDlgItemTextW(hwnd, IDC_EDT_COUNTRY, szCountry);
+
+ hwndCB = GetDlgItem(hwnd, IDC_CB_GENDER);
+ if (hwndCB)
+ {
+ INT count = (INT)SendMessageW(hwndCB, CB_GETCOUNT, 0, 0L);
+ if (count > 0)
+ {
+ INT i;
+ for (i = 0; i < count && gender != (INT)SendMessageW(hwndCB, CB_GETITEMDATA, i, 0L); i++);
+ if (i != count) SendMessageW(hwndCB, CB_SETCURSEL, i, 0L);
+ }
+ }
+}
+
+
+void setup_page_feedback::ComboBox_OnSelChange(HWND hwndCtrl)
+{
+ INT index;
+ index = (INT)SendMessageW(hwndCtrl, CB_GETCURSEL, 0, 0L);
+ if (CB_ERR == index) return;
+ gender = (INT)SendMessageW(hwndCtrl, CB_GETITEMDATA, index, 0L);
+}
+
+INT_PTR setup_page_feedback::OnInitDialog(HWND hwndFocus, LPARAM lParam)
+{
+ HWND hwndCB;
+
+ SendDlgItemMessageW(hwnd, IDC_EDT_EMAIL, EM_LIMITTEXT, sizeof(szEmail)/sizeof(wchar_t), 0);
+ SendDlgItemMessageW(hwnd, IDC_EDT_COUNTRY, EM_LIMITTEXT, sizeof(szCountry)/sizeof(wchar_t), 0);
+
+ hwndCB = GetDlgItem(hwnd, IDC_CB_GENDER);
+ if (hwndCB)
+ {
+ UINT genderStrID[] = {IDS_GENDER_UNKNOWN, IDS_GENDER_FEMALE, IDS_GENDER_MALE, };
+ INT genderVal[] = {GENDER_UNKNOWN, GENDER_FEMALE, GENDER_MALE, };
+ for(int i = 0; i < sizeof(genderStrID)/sizeof(UINT); i++)
+ {
+ INT index = (INT)SendMessageW(hwndCB, CB_ADDSTRING,0, (LPARAM)getStringW(genderStrID[i], NULL, 0));
+ if (CB_ERR != index) SendMessageW(hwndCB, CB_SETITEMDATA, index, (LPARAM)genderVal[i]);
+ }
+ }
+
+ UpdateUI();
+ return 0;
+}
+
+void setup_page_feedback::OnSize(UINT nType, INT cx, INT cy)
+{
+ INT ctrlList[] = { IDC_LBL_HEADER, IDC_CHK_ANNOUNCEMENTS, IDC_CHK_STATISTICS,
+ IDC_EDT_EMAIL, IDC_EDT_COUNTRY, IDC_CB_GENDER, };
+ HWND hwndCtrl;
+ HDWP hdwp;
+ RECT rw;
+ INT width, ox;
+
+ hwndCtrl = GetDlgItem(hwnd, IDC_LBL_EMAIL);
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ ox = rw.left;
+
+ hdwp = BeginDeferWindowPos(sizeof(ctrlList)/sizeof(INT));
+ if (!hdwp) return;
+
+ for (int i = 0; i < sizeof(ctrlList)/sizeof(INT); i++)
+ {
+ hwndCtrl = GetDlgItem(hwnd, ctrlList[i]);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ switch(ctrlList[i])
+ {
+ case IDC_EDT_EMAIL:
+ case IDC_EDT_COUNTRY:
+ case IDC_CB_GENDER:
+ width = cx - rw.left - ox;
+ break;
+ default:
+ width = cx - rw.left*2;
+ break;
+ }
+ hdwp = DeferWindowPos(hdwp, hwndCtrl, NULL, 0, 0, width, rw.bottom - rw.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
+ }
+ }
+ if (hdwp) EndDeferWindowPos(hdwp);
+}
+
+
+void setup_page_feedback::OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl)
+{
+ switch(nCtrlID)
+ {
+ case IDC_EDT_EMAIL:
+ switch(nEvntID)
+ {
+ case EN_CHANGE:
+ {
+ GetWindowTextW(hwndCtrl, szEmail, sizeof(szEmail)/sizeof(wchar_t));
+ HWND hwndChk = GetDlgItem(hwnd, IDC_CHK_ANNOUNCEMENTS);
+ if (IsWindow(hwndChk))
+ {
+ BOOL bEnabled = IsWindowEnabled(hwndChk);
+ if (bEnabled != (0x00 != *szEmail))
+ {
+ CheckDlgButton(hwnd, IDC_CHK_ANNOUNCEMENTS, (0x00 != *szEmail) ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwnd, IDC_CHK_ANNOUNCEMENTS), 0x00 != *szEmail);
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_CHK_ANNOUNCEMENTS, BN_CLICKED), (LPARAM)GetDlgItem(hwnd, IDC_CHK_ANNOUNCEMENTS));
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case IDC_EDT_COUNTRY:
+ switch(nEvntID)
+ {
+ case EN_CHANGE:
+ GetWindowTextW(hwndCtrl, szCountry, sizeof(szCountry)/sizeof(wchar_t));
+ break;
+ }
+ break;
+ case IDC_CHK_ANNOUNCEMENTS:
+ switch(nEvntID)
+ {
+ case BN_CLICKED:
+ if (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L)) flags |= FF_ANNOUNCEMENTS;
+ else flags &= ~FF_ANNOUNCEMENTS;
+ break;
+ }
+ break;
+ case IDC_CHK_STATISTICS:
+ switch(nEvntID)
+ {
+ case BN_CLICKED:
+ if (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L)) flags |= FF_STATISTICS;
+ else flags &= ~FF_STATISTICS;
+ break;
+ }
+ break;
+ case IDC_CB_GENDER:
+ switch(nEvntID)
+ {
+ case CBN_SELCHANGE: ComboBox_OnSelChange(hwndCtrl); break;
+ }
+ break;
+ }
+}
+
+INT_PTR setup_page_feedback::PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam);
+ case WM_DESTROY: break;
+ case WM_SIZE: OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam)); break;
+ case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ }
+ return 0;
+}
+
+static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ setup_page_feedback *pInst = (setup_page_feedback*)GetPropW(hwnd, L"SETUPPAGE");
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ pInst = (setup_page_feedback*)lParam;
+ if (pInst)
+ {
+ pInst->hwnd = hwnd;
+ SetPropW(hwnd, L"SETUPPAGE", pInst);
+ }
+ break;
+ case WM_DESTROY:
+ if (pInst)
+ {
+ pInst->PageDlgProc(uMsg, wParam, lParam);
+ RemovePropW(hwnd, L"SETUPPAGE");
+ pInst = NULL;
+ }
+ break;
+ }
+
+ return (pInst) ? pInst->PageDlgProc(uMsg, wParam, lParam) : 0;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS setup_page_feedback
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(API_SETUPPAGE_GET_NAME, GetName)
+CB(API_SETUPPAGE_CREATEVIEW, CreateView)
+CB(API_SETUPPAGE_SAVE, Save)
+CB(API_SETUPPAGE_REVERT, Revert)
+CB(API_SETUPPAGE_ISDIRTY, IsDirty)
+CB(API_SETUPPAGE_VALIDATE, Validate)
+END_DISPATCH
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_feedback.h b/Src/Winamp/setup/spage_feedback.h
new file mode 100644
index 00000000..1ce53c13
--- /dev/null
+++ b/Src/Winamp/setup/spage_feedback.h
@@ -0,0 +1,45 @@
+#ifndef WINAMP_FEEDBACK_SETUP_PAGE_HEADER
+#define WINAMP_FEEDBACK_SETUP_PAGE_HEADER
+
+#include "./ifc_setuppage.h"
+
+class setup_page_feedback : public ifc_setuppage
+{
+
+public:
+ setup_page_feedback();
+ virtual ~setup_page_feedback();
+
+public:
+ size_t AddRef();
+ size_t Release();
+ HRESULT GetName(bool bShort, const wchar_t **pszName);
+ HRESULT Save(HWND hwndText);
+ HRESULT CreateView(HWND hwndParent, HWND *phwnd);
+ HRESULT Revert(void);
+ HRESULT IsDirty(void);
+ HRESULT Validate(void);
+protected:
+ INT_PTR PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR OnInitDialog(HWND hwndFocus, LPARAM lParam);
+ void OnSize(UINT nType, INT cx, INT cy);
+ void OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl);
+
+ void ComboBox_OnSelChange(HWND hwndCtrl);
+ void UpdateUI(void);
+
+private:
+ size_t ref;
+ HWND hwnd;
+ WCHAR szEmail[MAX_PATH];
+ WCHAR szCountry[MAX_PATH];
+ INT gender;
+ DWORD flags;
+
+protected:
+ friend static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ RECVS_DISPATCH;
+};
+
+
+#endif //WINAMP_FEEDBACK_SETUP_PAGE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_lang.cpp b/Src/Winamp/setup/spage_lang.cpp
new file mode 100644
index 00000000..83282311
--- /dev/null
+++ b/Src/Winamp/setup/spage_lang.cpp
@@ -0,0 +1,293 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include "./spage_lang.h"
+#include "./setup_resource.h"
+#include "../nu/ns_wc.h"
+#include "./langutil.h"
+
+typedef struct _LANGREC
+{
+ LPWSTR pszFileName;
+ INT nType;
+} LANGREC;
+
+
+static BOOL CALLBACK AddLangToListBox(ENUMLANG *pel, LPVOID pUser);
+static INT ListBox_FindLangFileIndex(HWND hwndLB, LPCWSTR pszLangPath);
+static LPCWSTR ListBox_GetSelectedLang(HWND hwndLB, LPWSTR pszLangPath, INT cchLen);
+
+
+setup_page_lang::setup_page_lang() : ref(1), hwnd(NULL)
+{
+ *szSelectionPath = 0x00;
+}
+setup_page_lang::~setup_page_lang()
+{
+}
+
+size_t setup_page_lang::AddRef()
+{
+ return ++ref;
+}
+
+size_t setup_page_lang::Release()
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+HRESULT setup_page_lang::GetName(bool bShort, const wchar_t **pszName)
+{
+ static wchar_t szName[64] = {0};
+ *pszName = (*szName) ? szName : getStringW(IDS_PAGE_LANGUAGE, szName, sizeof(szName)/sizeof(wchar_t));
+ return S_OK;
+}
+
+HRESULT setup_page_lang::Save(HWND hwndText)
+{
+ if (S_FALSE == IsDirty()) return S_OK;
+
+ if (!*szSelectionPath) *config_langpack = 0x00;
+ else
+ {
+ StringCbCopyW(config_langpack, sizeof(config_langpack), szSelectionPath);
+ }
+ config_save_langpack_var();
+ return S_OK;
+}
+
+HRESULT setup_page_lang::Revert(void)
+{
+ HRESULT hr(S_OK);
+
+ if (*config_langpack)
+ {
+ StringCbCopyW(config_langpack, sizeof(szSelectionPath), config_langpack);
+ }
+ else szSelectionPath[0] = 0x00;
+
+ if (hwnd)
+ {
+ HWND hwndLB = GetDlgItem(hwnd, IDC_LB_LANG);
+ INT index = ListBox_FindLangFileIndex(hwndLB, szSelectionPath);
+ if (LB_ERR == index && *szSelectionPath) index = ListBox_FindLangFileIndex(hwndLB, NULL); // find default embeded lang
+ SendMessageW(hwndLB, LB_SETCURSEL, (LB_ERR != index) ? index : 0, 0L);
+ }
+ return hr;
+}
+
+HRESULT setup_page_lang::IsDirty(void)
+{
+ INT cr;
+
+ cr = ComparePath(config_langpack, szSelectionPath, LANGDIR);
+ if (!cr) return E_UNEXPECTED;
+
+ return (CSTR_EQUAL != cr) ? S_OK : S_FALSE;
+}
+
+HRESULT setup_page_lang::Validate(void)
+{
+ return S_OK;
+}
+
+HRESULT setup_page_lang::CreateView(HWND hwndParent, HWND *phwnd)
+{
+ *phwnd = WACreateDialogParam(MAKEINTRESOURCEW(IDD_SETUP_PAGE_LANG), hwndParent, ::DialogProc, (LPARAM)this);
+ return S_OK;
+}
+
+void setup_page_lang::ListBox_OnSelChange(HWND hwndCtrl)
+{
+ ListBox_GetSelectedLang(hwndCtrl, szSelectionPath, sizeof(szSelectionPath)/sizeof(wchar_t));
+}
+
+void setup_page_lang::ListBox_OnItemDelete(DELETEITEMSTRUCT *pdis)
+{
+ LANGREC *pr = (LANGREC*)pdis->itemData;
+ if (pr)
+ {
+ if (pr->pszFileName) free(pr->pszFileName);
+ free(pr);
+ }
+}
+
+INT_PTR setup_page_lang::OnInitDialog(HWND hwndFocus, LPARAM lParam)
+{
+ INT index;
+ HWND hwndLB;
+ hwndLB = GetDlgItem(hwnd, IDC_LB_LANG);
+ EnumerateLanguages(AddLangToListBox, hwndLB);
+ index = ListBox_FindLangFileIndex(hwndLB, szSelectionPath);
+ if (LB_ERR == index && *szSelectionPath) index = ListBox_FindLangFileIndex(hwndLB, NULL); // find default embeded lang
+ SendMessageW(hwndLB, LB_SETCURSEL, (LB_ERR != index) ? index : 0, 0L);
+
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_LB_LANG, LBN_SELCHANGE), (LPARAM)hwndLB);
+ return 0;
+}
+
+void setup_page_lang::OnSize(UINT nType, INT cx, INT cy)
+{
+ HWND hwndCtrl;
+ RECT rw;
+
+ hwndCtrl = GetDlgItem(hwnd, IDC_LBL_HEADER);
+ if (hwndCtrl)
+ {
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ SetWindowPos(hwndCtrl, NULL, 0, 0, cx - rw.left*2, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
+ }
+ hwndCtrl = GetDlgItem(hwnd, IDC_LB_LANG);
+ if (hwndCtrl)
+ {
+
+ GetWindowRect(hwndCtrl, &rw);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
+ SetWindowPos(hwndCtrl, NULL, max(0, (cx - (rw.right - rw.left))/2), rw.top, rw.right - rw.left, cy - rw.top - 16, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+}
+
+void setup_page_lang::OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_LANG:
+ switch(nEvntID)
+ {
+ case LBN_SELCHANGE: ListBox_OnSelChange(hwndCtrl); break;
+ }
+ break;
+ }
+}
+
+INT_PTR setup_page_lang::OnDeleteItem(INT nCtrlID, DELETEITEMSTRUCT *pdis)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_LANG: ListBox_OnItemDelete(pdis); return TRUE;
+ }
+ return 0;
+}
+
+INT_PTR setup_page_lang::PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam);
+ case WM_DESTROY: break;
+ case WM_SIZE: OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam)); break;
+ case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ }
+ return 0;
+}
+
+static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ setup_page_lang *pInst = (setup_page_lang*)GetPropW(hwnd, L"SETUPPAGE");
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ pInst = (setup_page_lang*)lParam;
+ if (pInst)
+ {
+ pInst->hwnd = hwnd;
+ SetPropW(hwnd, L"SETUPPAGE", pInst);
+ }
+ break;
+ case WM_DESTROY:
+ if (pInst)
+ {
+ pInst->PageDlgProc(uMsg, wParam, lParam);
+ RemovePropW(hwnd, L"SETUPPAGE");
+ pInst = NULL;
+ }
+ break;
+ }
+
+ return (pInst) ? pInst->PageDlgProc(uMsg, wParam, lParam) : 0;
+}
+
+static BOOL CALLBACK AddLangToListBox(ENUMLANG *pel, LPVOID pUser)
+{
+ INT index;
+ LANGREC *pr;
+ HWND hwndLB = (HWND)pUser;
+ if (!hwndLB) return FALSE;
+
+ pr = (LANGREC*)calloc(1, sizeof(LANGREC));
+ if (!pr) return FALSE;
+ pr->nType = pel->nType;
+ if (pel->pszFileName) pr->pszFileName = _wcsdup(pel->pszFileName);
+
+ index = (INT)SendMessageW(hwndLB, LB_ADDSTRING, 0, (LPARAM)pel->pszName);
+ if (LB_ERR != index) SendMessageW(hwndLB, LB_SETITEMDATA, index, (LPARAM)pr);
+ else
+ {
+ if (pr->pszFileName) free(pr->pszFileName);
+ free(pr);
+ }
+ return TRUE;
+}
+
+static INT ListBox_FindLangFileIndex(HWND hwndLB, LPCWSTR pszLangPath)
+{
+ int index, count;
+
+ if (!hwndLB) return LB_ERR;
+
+ index = LB_ERR;
+
+ count = (INT)SendMessageW(hwndLB, LB_GETCOUNT, 0, 0L);
+ for (index = 0; index < count; index++)
+ {
+ LANGREC *pr = (LANGREC*) SendMessageW(hwndLB, LB_GETITEMDATA, index, 0L);
+ if (!pr || LB_ERR == (INT)(INT_PTR)pr) continue;
+ if (!pszLangPath || !*pszLangPath)
+ {
+ if (LANG_FILETYPE_EMBED == pr->nType && (!pr->pszFileName || !*pr->pszFileName)) break;
+ }
+ else
+ {
+ if (CSTR_EQUAL == ComparePath(pszLangPath, pr->pszFileName, LANGDIR)) break;
+ }
+ }
+ return (count == index) ? LB_ERR : index;
+}
+
+static LPCWSTR ListBox_GetSelectedLang(HWND hwndLB, LPWSTR pszLangPath, INT cchLen)
+{
+ INT index;
+ LANGREC *pr;
+ if (!hwndLB || !pszLangPath) return NULL;
+ index = (INT)SendMessageW(hwndLB, LB_GETCURSEL, 0, 0L);
+ if (LB_ERR == index) return NULL;
+ pr = (LANGREC*)SendMessageW(hwndLB, LB_GETITEMDATA, index, 0L);
+ if (!pr || LB_ERR == (INT)(INT_PTR)pr) return NULL;
+
+ if (!pr->pszFileName || !*pr->pszFileName) pszLangPath[0] = 0x00;
+ else if (S_OK != StringCchCopyW(pszLangPath, cchLen, pr->pszFileName)) return NULL;
+ return pszLangPath;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS setup_page_lang
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(API_SETUPPAGE_GET_NAME, GetName)
+CB(API_SETUPPAGE_CREATEVIEW, CreateView)
+CB(API_SETUPPAGE_SAVE, Save)
+CB(API_SETUPPAGE_REVERT, Revert)
+CB(API_SETUPPAGE_ISDIRTY, IsDirty)
+CB(API_SETUPPAGE_VALIDATE, Validate)
+END_DISPATCH
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_lang.h b/Src/Winamp/setup/spage_lang.h
new file mode 100644
index 00000000..f3848ab7
--- /dev/null
+++ b/Src/Winamp/setup/spage_lang.h
@@ -0,0 +1,42 @@
+#ifndef WINAMP_LANGUAGE_SETUP_PAGE_HEADER
+#define WINAMP_LANGUAGE_SETUP_PAGE_HEADER
+
+#include "./ifc_setuppage.h"
+
+class setup_page_lang : public ifc_setuppage
+{
+
+public:
+ setup_page_lang();
+ virtual ~setup_page_lang();
+
+public:
+ size_t AddRef();
+ size_t Release();
+ HRESULT GetName(bool bShort, const wchar_t **pszName);
+ HRESULT Save(HWND hwndText);
+ HRESULT CreateView(HWND hwndParent, HWND *phwnd);
+ HRESULT Revert(void);
+ HRESULT IsDirty(void);
+ HRESULT Validate(void);
+protected:
+ INT_PTR PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR OnInitDialog(HWND hwndFocus, LPARAM lParam);
+ void OnSize(UINT nType, INT cx, INT cy);
+ void OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl);
+ INT_PTR OnDeleteItem(INT nCtrlID, DELETEITEMSTRUCT *pdis);
+ void ListBox_OnItemDelete(DELETEITEMSTRUCT *pdis);
+ void ListBox_OnSelChange(HWND hwndCtrl);
+
+private:
+ size_t ref;
+ HWND hwnd;
+ wchar_t szSelectionPath[MAX_PATH];
+
+protected:
+ friend static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ RECVS_DISPATCH;
+};
+
+
+#endif //WINAMP_LANGUAGE_SETUP_PAGE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_skin.cpp b/Src/Winamp/setup/spage_skin.cpp
new file mode 100644
index 00000000..d50f3998
--- /dev/null
+++ b/Src/Winamp/setup/spage_skin.cpp
@@ -0,0 +1,646 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "main.h"
+#include "./spage_skin.h"
+#include "./setup_resource.h"
+#include "./skininfo.h"
+#include "../nu/ns_wc.h"
+#include "../nu/AutoWide.h"
+#include "./loadimage.h"
+#include "./langutil.h"
+#include "./setupcommon.h"
+
+typedef struct _SKINLINK
+{
+ LPCWSTR pszName;
+ LPCWSTR pszTarget;
+} SKINLINK;
+
+typedef struct _SKINREC
+{
+ LPWSTR pszName;
+ LPWSTR pszFileName;
+ INT nType;
+ BOOL bLink; // if bLink == TRUE than nType index in links
+} SKINREC;
+
+#define CURRENT_SKIN_ID 1
+#define SEPARATOR_DATA 0xEFFF
+
+#define LINK_FONT_ITALIC FALSE
+#define LINK_FONT_WEIGHT FW_MEDIUM
+//#define LINK_TEXT_COLOR RGB(0, 50, 193)
+//#define LINK_TEXT_HIGHLITECOLOR RGB(16, 64, 212)
+
+#define PREVIEW_WIDTH 178
+#define PREVIEW_HEIGHT 75
+
+static SKINLINK links[] =
+{
+ { MAKEINTRESOURCEW(IDS_SKIN_PROMO1), BENTO_SKIN_NAME },
+ { MAKEINTRESOURCEW(IDS_SKIN_PROMO2), BIG_BENTO_SKIN_NAME },
+ { MAKEINTRESOURCEW(IDS_SKIN_CURRENT), MAKEINTRESOURCEW(CURRENT_SKIN_ID) },
+};
+
+static wchar_t szClassic[64] = {0, };
+
+#define CLASSIC_NAME() ((!*szClassic) ? getStringW(IDS_CLASSIC_SKIN_NAME, szClassic, sizeof(szClassic)/sizeof(wchar_t)) : szClassic)
+
+static BOOL CALLBACK AddSkinToListBox(ENUMSKIN *pes, LPVOID pUser);
+static LRESULT WINAPI ListBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LPCWSTR ResolveLink(SKINREC *pr);
+static INT ListBox_FindSkinFileIndex(HWND hwndLB, LPCWSTR pszSkinPath, BOOL bSearchLinks);
+
+setup_page_skin::setup_page_skin() : ref(1), hwnd(NULL), hfLink(NULL), idxSelected(-1)
+{
+ *szSelectionPath = 0x00;
+}
+
+setup_page_skin::~setup_page_skin()
+{
+}
+
+size_t setup_page_skin::AddRef()
+{
+ return ++ref;
+}
+
+size_t setup_page_skin::Release()
+{
+ if (1 == ref)
+ {
+ delete(this);
+ return 0;
+ }
+ return --ref;
+}
+
+HRESULT setup_page_skin::GetName(bool bShort, const wchar_t **pszName)
+{
+ if (bShort)
+ {
+ static wchar_t szShortName[32] = {0};
+ *pszName = (*szShortName) ? szShortName : getStringW(IDS_PAGE_SKIN, szShortName, sizeof(szShortName)/sizeof(wchar_t));
+ }
+ else
+ {
+ static wchar_t szLongName[64] = {0};
+ *pszName = (*szLongName) ? szLongName : getStringW(IDS_PAGE_SKIN_LONG, szLongName, sizeof(szLongName)/sizeof(wchar_t));
+ }
+ return S_OK;
+}
+
+HRESULT setup_page_skin::Save(HWND hwndText)
+{
+ if (S_FALSE == IsDirty()) return S_OK;
+
+ if (!*szSelectionPath) *config_skin = 0x00;
+ else if (S_OK != StringCchCopyW(config_skin, sizeof(config_skin)/sizeof(wchar_t), szSelectionPath)) return S_FALSE;
+
+ _w_sW("skin", config_skin);
+ if (hwnd)
+ {
+ HWND hwndLB = GetDlgItem(hwnd, IDC_LB_SKIN);
+ INT index = ListBox_FindSkinFileIndex(hwndLB, szSelectionPath, TRUE);
+ if (LB_ERR == index && *szSelectionPath) index = ListBox_FindSkinFileIndex(hwndLB, NULL, TRUE); // find default embeded skin
+ SendMessageW(hwndLB, LB_SETCURSEL, (LB_ERR != index) ? index : 0, 0L);
+ }
+ return S_OK;//(count) ? S_OK : S_FALSE;
+}
+
+static BOOL IsForceBento()
+{
+ wchar_t szVer[128] = {0};
+ if (GetPrivateProfileIntW(L"WinampReg", L"IsFirstInst", 0, INI_FILE)) return TRUE;
+ GetPrivateProfileStringW(L"WinampReg", L"WAVer", L"", szVer, 128, INI_FILE);
+ return (!*szVer || CSTR_LESS_THAN == CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
+ NORM_IGNORECASE, szVer, -1, AutoWide(APP_VERSION), -1));
+}
+
+HRESULT setup_page_skin::Revert(void)
+{
+ HRESULT hr(S_OK);
+
+ if (NULL != config_skin && !IsForceBento()) StringCchCopyW(szSelectionPath, sizeof(szSelectionPath)/sizeof(wchar_t), config_skin);
+ else StringCchCopyW(szSelectionPath, sizeof(szSelectionPath)/sizeof(wchar_t), L"Bento");
+
+ if (hwnd)
+ {
+ HWND hwndLB = GetDlgItem(hwnd, IDC_LB_SKIN);
+ INT index = ListBox_FindSkinFileIndex(hwndLB, szSelectionPath, TRUE);
+ if (LB_ERR == index && *szSelectionPath) index = ListBox_FindSkinFileIndex(hwndLB, NULL, TRUE); // find default embeded skin
+ SendMessageW(hwndLB, LB_SETCURSEL, (LB_ERR != index) ? index : 0, 0L);
+ }
+ return hr;
+}
+
+HRESULT setup_page_skin::IsDirty(void)
+{
+ INT cr;
+
+ if (IsForceBento()) return S_OK;
+
+ cr = ComparePath(config_skin, szSelectionPath, SKINDIR);
+ if (!cr) return E_UNEXPECTED;
+ return (CSTR_EQUAL != cr) ? S_OK : S_FALSE;
+}
+
+HRESULT setup_page_skin::Validate(void)
+{
+ return S_OK;
+}
+
+HRESULT setup_page_skin::CreateView(HWND hwndParent, HWND *phwnd)
+{
+ *phwnd = WACreateDialogParam(MAKEINTRESOURCEW(IDD_SETUP_PAGE_SKIN), hwndParent, ::DialogProc, (LPARAM)this);
+ return S_OK;
+}
+
+void setup_page_skin::ListBox_OnSelChange(HWND hwndCtrl)
+{
+ SKININFO si = {0};
+ SKINREC *pr;
+ WCHAR szText[MAX_PATH*2] = {0};
+ INT typeID, index;
+
+ index = (INT)SendMessageW(hwndCtrl, LB_GETCURSEL, 0, 0L);
+ if (idxSelected == index) return;
+
+ pr = (SKINREC*)SendMessageW(hwndCtrl, LB_GETITEMDATA, index, 0L);
+ if (pr && LB_ERR != (INT)(INT_PTR)pr && pr->bLink) // resolve link
+ {
+ index = ListBox_FindSkinFileIndex(hwndCtrl, ResolveLink(pr), FALSE);
+ pr = (LB_ERR != index) ? (SKINREC*)SendMessageW(hwndCtrl, LB_GETITEMDATA, index, 0L) : NULL;
+ }
+ if (!pr || LB_ERR == (INT)(INT_PTR)pr) { SendMessageW(hwndCtrl, LB_SETCURSEL, idxSelected, 0L); return; }
+ idxSelected = index;
+
+ if (!pr->pszFileName || !*pr->pszFileName) szSelectionPath[0] = 0x00;
+ else StringCchCopyW(szSelectionPath, sizeof(szSelectionPath)/sizeof(wchar_t), pr->pszFileName);
+
+ ZeroMemory(&si, sizeof(SKININFO));
+ si.cbSize = sizeof(SKININFO);
+ si.fMask = SIF_PREVIEW;
+ StringCchCopyW(si.szName, SI_NAMEMAX, pr->pszName);
+
+ GetSkinInfo(BuildFullPath(SKINDIR, szSelectionPath, szText, sizeof(szText)/sizeof(wchar_t)), &si);
+
+ switch(si.type)
+ {
+ case SKIN_TYPE_MODERN: typeID = IDS_MODERN; break;
+ case SKIN_TYPE_CLASSIC: typeID = IDS_CLASSIC; break;
+ default: typeID = IDS_UNKNOWN; break;
+ }
+
+ SetDlgItemTextW(hwnd, IDC_EDT_NAME, si.szName);
+ SetDlgItemTextW(hwnd, IDC_EDT_TYPE, getStringW(typeID, NULL, 0));
+ SetDlgItemTextW(hwnd, IDC_EDT_AUTHOR, si.szAuthor);
+ SetDlgItemTextW(hwnd, IDC_EDT_VERSION, si.szVersion);
+ if (!si.hPreview) si.hPreview = WALoadImage2(L"PNG", MAKEINTRESOURCEW(IDB_PREVIEW_NO), FALSE);
+ if (si.hPreview)
+ {
+ HBRUSH hb = (HBRUSH)SendMessageW(hwnd, WM_CTLCOLORSTATIC, NULL, (LPARAM)GetDlgItem(hwnd, IDC_PIC_PREVIEW));
+ WABlendOnColor(si.hPreview, RGB(137,145,156));
+ si.hPreview = WAResizeImage(si.hPreview, PREVIEW_WIDTH, PREVIEW_HEIGHT, hb);
+ if (!si.hPreview) si.hPreview = WALoadImage2(L"PNG", MAKEINTRESOURCEW(IDB_PREVIEW_NO), FALSE);
+ }
+
+ HBITMAP hPrev = (HBITMAP)SendDlgItemMessageW(hwnd, IDC_PIC_PREVIEW, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)si.hPreview);
+ if (hPrev) DeleteObject(hPrev);
+}
+
+void setup_page_skin::ListBox_OnItemDelete(DELETEITEMSTRUCT *pdis)
+{
+ SKINREC *pr = (SKINREC*)pdis->itemData;
+ if (pr)
+ {
+ if (pr->pszName) free(pr->pszName);
+ if (pr->pszFileName) free(pr->pszFileName);
+ free(pr);
+ }
+}
+
+void setup_page_skin::ListBox_OnDrawItem(DRAWITEMSTRUCT *pdis)
+{
+ RECT ri;
+ SKINREC *pr = (SKINREC*)pdis->itemData;
+ static UINT trackFocus = 0x0000FFFF;
+
+ if (pdis->itemID == -1) return;
+
+ CopyRect(&ri, &pdis->rcItem);
+ switch(pdis->itemAction)
+ {
+ case ODA_FOCUS:
+ if (0 == (0x0200/*ODS_NOFOCUSRECT*/ & pdis->itemState) && pr)
+ {
+ if (LOWORD(trackFocus) != pdis->itemID || HIWORD(trackFocus) != (ODS_FOCUS & pdis->itemState) ? 0x0001: 0x0000)
+ DrawFocusRect(pdis->hDC, &ri);
+ trackFocus = pdis->itemID | ((ODS_FOCUS & pdis->itemState) ? 0x00010000 : 0x00000000);
+ }
+ else trackFocus = pdis->itemID;
+ return;
+
+ case ODA_SELECT:
+ if (0 == (ODS_SELECTED & pdis->itemState) && pr)
+ ExtTextOutW(pdis->hDC, 0, 0, ETO_OPAQUE, &ri, L"", 0, NULL);
+ break;
+ }
+
+ if ((ODS_SELECTED & pdis->itemState) && pr)
+ {
+ COLORREF rgb = SetBkColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
+ ExtTextOutW(pdis->hDC, 0, 0, ETO_OPAQUE, &ri, L"", 0, NULL);
+ SetBkColor(pdis->hDC, rgb);
+ }
+
+ if (pr)
+ {
+ if (pr->pszName)
+ {
+ HFONT hfOld;
+ COLORREF rgb(0);
+
+ if (pr->bLink)
+ {
+ if (!hfLink)
+ {
+ LOGFONTW lf = {0};
+ if (GetObject(GetCurrentObject(pdis->hDC, OBJ_FONT), sizeof(LOGFONTW), &lf))
+ {
+ lf.lfItalic = LINK_FONT_ITALIC;
+ lf.lfWeight = LINK_FONT_WEIGHT;
+ hfLink = CreateFontIndirectW(&lf);
+ }
+ }
+ hfOld = (HFONT)SelectObject(pdis->hDC, hfLink);
+ rgb = SetTextColor(pdis->hDC, GetSysColor((ODS_SELECTED & pdis->itemState) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
+ }
+ else
+ {
+ hfOld = NULL;
+ rgb = SetTextColor(pdis->hDC, GetSysColor((ODS_SELECTED & pdis->itemState) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
+ }
+
+ ri.left += 2;
+ COLORREF oldrgb = SetBkColor(pdis->hDC, GetSysColor((ODS_SELECTED & pdis->itemState) ? COLOR_HIGHLIGHT : COLOR_WINDOW));
+ DrawTextW(pdis->hDC, pr->pszName, -1, &ri, DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_WORD_ELLIPSIS);
+ SetBkColor(pdis->hDC, oldrgb);
+ if (pr->bLink && hfOld) SelectObject(pdis->hDC, hfOld);
+ SetTextColor(pdis->hDC, rgb);
+ }
+ }
+ else
+ {
+ HPEN hPen, hPenOld;
+ hPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT));
+ hPenOld = (HPEN)SelectObject(pdis->hDC, hPen);
+ MoveToEx(pdis->hDC, ri.left + 1, ri.top + (ri.bottom - ri.top)/2, NULL);
+ LineTo(pdis->hDC, ri.right - 1, ri.top + (ri.bottom - ri.top)/2);
+ SelectObject(pdis->hDC, hPenOld);
+ }
+}
+
+INT_PTR setup_page_skin::ListBox_OnItemCompare(COMPAREITEMSTRUCT *pcis)
+{ SKINREC *pr1, *pr2;
+ INT cr;
+
+ pr1 = (SKINREC*)pcis->itemData1;
+ pr2 = (SKINREC*)pcis->itemData2;
+ if (pr1 == pr2) return 0;
+ if (!pr1) return (pr2->bLink) ? 1 : -1;
+ if (!pr2) return (pr1->bLink) ? -1 : 1;
+ if (pr1->bLink) return (pr2->bLink) ? (pcis->itemID1 - pcis->itemID2) : -1;
+ if (pr2->bLink) return (pr1->bLink) ? (pcis->itemID1 - pcis->itemID2) : 1;
+ cr = CompareStringW(pcis->dwLocaleId, NORM_IGNORECASE, pr1->pszName, -1, pr2->pszName, -1);
+ if (CSTR_EQUAL == cr)
+ {
+ INT t1, t2;
+ t1 = (SKIN_FILETYPE_WAL == pr1->nType) ? SKIN_FILETYPE_ZIP : ((SKIN_FILETYPE_ZIP == pr1->nType) ? SKIN_FILETYPE_WAL : pr1->nType);
+ t2 = (SKIN_FILETYPE_WAL == pr2->nType) ? SKIN_FILETYPE_ZIP : ((SKIN_FILETYPE_ZIP == pr2->nType) ? SKIN_FILETYPE_WAL : pr2->nType);
+ return t1 - t2;
+ }
+ return cr - 2;
+}
+
+INT_PTR setup_page_skin::ListBox_OnVKeyToItem(HWND hwndLB, WORD vKey, INT index)
+{
+ switch(vKey)
+ {
+ case VK_UP:
+ case VK_LEFT:
+ if (NULL == SendMessageW(hwndLB, LB_GETITEMDATA, index - 1, 0L)) return index - 2;
+ break;
+ case VK_DOWN:
+ case VK_RIGHT:
+ if (NULL == SendMessageW(hwndLB, LB_GETITEMDATA, index + 1, 0L)) return index + 2;
+ break;
+ case VK_NEXT:
+ case VK_PRIOR:
+ {
+ RECT rc;
+ INT page, count;
+ GetClientRect(hwndLB, &rc);
+ page = (rc.bottom - rc.top)/(INT)SendMessageW(hwndLB, LB_GETITEMHEIGHT, 0, 0L) - 1;
+ count = (INT)SendMessageW(hwndLB, LB_GETCOUNT, 0, 0L);
+ index = (VK_NEXT == vKey) ? min(index + page, count) : max(0, index - page);
+ if (NULL == SendMessageW(hwndLB, LB_GETITEMDATA, index, 0L)) return index + ((VK_NEXT == vKey) ? 1 : -1);
+ break;
+ }
+ }
+ return -1;
+}
+
+INT_PTR setup_page_skin::ListBox_OnCharToItem(HWND hwndLB, WORD vKey, INT index)
+{
+ return -2;
+}
+
+INT_PTR setup_page_skin::OnInitDialog(HWND hwndFocus, LPARAM lParam)
+{
+ HWND hwndLB, hwndGrp;
+ int count, linksCount(0), index;
+ wchar_t szBuffer[MAX_PATH] = {0};
+
+ idxSelected = -1;
+
+ hwndGrp = GetDlgItem(hwnd, IDC_GRP_PREVIEW);
+ SetWindowLongPtrW(hwndGrp, GWL_STYLE, GetWindowLongPtrW(hwndGrp, GWL_STYLE) | WS_CLIPSIBLINGS);
+
+ hwndLB = GetDlgItem(hwnd, IDC_LB_SKIN);
+ EnumerateSkins(AddSkinToListBox, hwndLB);
+
+ count = sizeof(links)/sizeof(SKINLINK);
+
+ for (int i = count - 1; i >= 0; i--)
+ {
+ SKINREC *pr = (SKINREC*)calloc(1, sizeof(SKINREC));
+ if (pr)
+ {
+ LPCWSTR pszName = links[i].pszName;
+ if (IS_INTRESOURCE(pszName)) pszName = getStringW((INT)(INT_PTR)pszName, szBuffer, sizeof(szBuffer)/sizeof(wchar_t));
+ pr->pszName = _wcsdup(pszName);
+ pr->bLink = TRUE;
+ pr->nType = i;
+
+ if(LB_ERR != ListBox_FindSkinFileIndex(hwndLB, ResolveLink(pr), FALSE) &&
+ LB_ERR != SendMessageW(hwndLB, LB_INSERTSTRING, 0, (LPARAM)pr))
+ {
+ linksCount++;
+ }
+ else
+ {
+ if (pr)
+ {
+ if (pr->pszName) free(pr->pszName);
+ free(pr);
+ }
+ }
+ }
+ }
+
+ if (linksCount) SendMessageW(hwndLB, LB_INSERTSTRING, linksCount, (LPARAM)NULL);
+
+ WNDPROC fnOldProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwndLB, GWLP_WNDPROC, (LONGX86)(LONG_PTR)ListBoxProc);
+ if (fnOldProc) SetPropW(hwndLB, L"SKINLB", fnOldProc);
+
+ index = ListBox_FindSkinFileIndex(hwndLB, szSelectionPath, TRUE);
+ if (LB_ERR == index && *szSelectionPath) index = ListBox_FindSkinFileIndex(hwndLB, NULL, TRUE); // find default embeded lang
+ SendMessageW(hwndLB, LB_SETCURSEL, (LB_ERR != index) ? index : 0, 0L);
+
+ PostMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_LB_SKIN, LBN_SELCHANGE), (LPARAM)hwndLB);
+ return 0;
+}
+
+void setup_page_skin::OnDestroy(void)
+{
+ if (hfLink) { DeleteObject(hfLink); hfLink = NULL; }
+}
+
+void setup_page_skin::OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_SKIN:
+ switch(nEvntID)
+ {
+ case LBN_SELCHANGE: ListBox_OnSelChange(hwndCtrl); break;
+ }
+ break;
+ }
+}
+
+INT_PTR setup_page_skin::OnColorStatic(HDC hdc, HWND hwndCtrl)
+{
+ INT ctrlID = GetDlgCtrlID(hwndCtrl);
+ switch(ctrlID)
+ {
+ case IDC_LBL_NAME:
+ case IDC_LBL_TYPE:
+ case IDC_LBL_AUTHOR:
+ case IDC_LBL_VERSION:
+ SetTextColor(hdc, RGB(0, 70, 213));
+ break;
+ }
+ return NULL;
+}
+
+INT_PTR setup_page_skin::OnDrawItem(INT nCtrlID, DRAWITEMSTRUCT *pdis)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_SKIN: ListBox_OnDrawItem(pdis); return TRUE;
+ }
+ return 0;
+}
+
+INT_PTR setup_page_skin::OnMeasureItem(INT nCtrlID, MEASUREITEMSTRUCT *pmis)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_SKIN:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+INT_PTR setup_page_skin::OnDeleteItem(INT nCtrlID, DELETEITEMSTRUCT *pdis)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_SKIN: ListBox_OnItemDelete(pdis); return TRUE;
+ }
+ return 0;
+}
+
+INT_PTR setup_page_skin::OnCompareItem(INT nCtrlID, COMPAREITEMSTRUCT *pcis)
+{
+ switch(nCtrlID)
+ {
+ case IDC_LB_SKIN: return ListBox_OnItemCompare(pcis);
+ }
+ return 0;
+}
+
+INT_PTR setup_page_skin::OnVKeyToItem(WORD vKey, INT index, HWND hwndCtrl)
+{
+ switch(GetDlgCtrlID(hwndCtrl))
+ {
+ case IDC_LB_SKIN: return ListBox_OnVKeyToItem(hwndCtrl, vKey, index);
+ }
+ return -1;
+}
+
+INT_PTR setup_page_skin::OnCharToItem(WORD vKey, INT index, HWND hwndCtrl)
+{
+ switch(GetDlgCtrlID(hwndCtrl))
+ {
+ case IDC_LB_SKIN: return ListBox_OnCharToItem(hwndCtrl, vKey, index);
+ }
+ return -1;
+}
+
+INT_PTR setup_page_skin::PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam);
+ case WM_DESTROY: OnDestroy(); break;
+ case WM_CTLCOLORSTATIC: return OnColorStatic((HDC)wParam, (HWND)lParam);
+ case WM_DRAWITEM: MSGRESULT(hwnd, OnDrawItem((INT)wParam, (DRAWITEMSTRUCT*)lParam));
+ case WM_MEASUREITEM: MSGRESULT(hwnd, OnMeasureItem((INT)wParam, (MEASUREITEMSTRUCT*)lParam));
+ case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ case WM_DELETEITEM: MSGRESULT(hwnd, OnDeleteItem((INT)wParam, (DELETEITEMSTRUCT*)lParam));
+ case WM_COMPAREITEM: return OnCompareItem((INT)wParam, (COMPAREITEMSTRUCT*)lParam);
+ case WM_VKEYTOITEM: return OnVKeyToItem(LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
+ case WM_CHARTOITEM: return OnCharToItem(LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
+ }
+ return 0;
+}
+
+static BOOL CALLBACK AddSkinToListBox(ENUMSKIN *pes, LPVOID pUser)
+{
+ HWND hwndLB = (HWND)pUser;
+ if (!hwndLB) return FALSE;
+
+ SKINREC *pr = (SKINREC*)calloc(1, sizeof(SKINREC));
+ if (!pr) return FALSE;
+ pr->nType = pes->nType;
+ if (pes->pszName) pr->pszName = _wcsdup(pes->pszName);
+ if (pes->pszFileName) pr->pszFileName = _wcsdup(pes->pszFileName);
+
+ if (LB_ERR == SendMessageW(hwndLB, LB_ADDSTRING, 0, (LPARAM)pr))
+ {
+ if (pr->pszName) free(pr->pszName);
+ if (pr->pszFileName) free(pr->pszFileName);
+ free(pr);
+ }
+ return TRUE;
+}
+
+static LPCWSTR ResolveLink(SKINREC *pr)
+{
+ if (!pr) return NULL;
+ if (!pr->bLink) return pr->pszFileName;
+ if (pr->nType < 0 || pr->nType >= sizeof(links)/sizeof(SKINLINK)) return NULL;
+ if(CURRENT_SKIN_ID == (INT)(INT_PTR)links[pr->nType].pszTarget) return config_skin;
+ if (IS_INTRESOURCE(links[pr->nType].pszTarget)) return getStringW((INT)(INT_PTR)links[pr->nType].pszTarget, NULL, 0);
+ return links[pr->nType].pszTarget;
+}
+
+static INT ListBox_FindSkinFileIndex(HWND hwndLB, LPCWSTR pszSkinPath, BOOL bSearchLinks)
+{
+ int index, count;
+ SKINREC *pr;
+ LPCWSTR pszFileName;
+
+ if (!hwndLB) return LB_ERR;
+
+ index = LB_ERR;
+
+ count = (INT)SendMessageW(hwndLB, LB_GETCOUNT, 0, 0L);
+ for (index = 0; index < count; index++)
+ {
+ pr = (SKINREC*) SendMessageW(hwndLB, LB_GETITEMDATA, index, 0L);
+ if (!pr || LB_ERR == (INT)(INT_PTR)pr) continue;
+
+ if (pr->bLink)
+ {
+ if(bSearchLinks) pszFileName = ResolveLink(pr);
+ else continue;
+ }
+ else pszFileName = pr->pszFileName;
+
+ if (!pszSkinPath || !*pszSkinPath)
+ {
+ if (!pszFileName || !*pszFileName) break;
+ }
+ else
+ {
+ if (pszFileName && CSTR_EQUAL == ComparePath(pszSkinPath, pszFileName, SKINDIR)) break;
+ }
+ }
+ return (count == index) ? LB_ERR : index;
+}
+
+static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ setup_page_skin *pInst = (setup_page_skin*)GetPropW(hwnd, L"SETUPPAGE");
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ pInst = (setup_page_skin*)lParam;
+ if (pInst)
+ {
+ pInst->hwnd = hwnd;
+ SetPropW(hwnd, L"SETUPPAGE", pInst);
+ }
+ break;
+ case WM_DESTROY:
+ if (pInst)
+ {
+ pInst->PageDlgProc(uMsg, wParam, lParam);
+ RemovePropW(hwnd, L"SETUPPAGE");
+ pInst = NULL;
+ }
+ break;
+ }
+ return (pInst) ? pInst->PageDlgProc(uMsg, wParam, lParam) : 0;
+}
+
+static LRESULT WINAPI ListBoxProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ WNDPROC fnOldProc = (WNDPROC) GetPropW( hwnd, L"SKINLB" );
+ if ( !fnOldProc ) return DefWindowProcW( hwnd, uMsg, wParam, lParam );
+ switch ( uMsg )
+ {
+ case WM_DESTROY:
+ RemovePropW( hwnd, L"SKINLB" );
+ SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR) fnOldProc );
+ break;
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ if ( SendMessageW( hwnd, LB_GETITEMDATA, LOWORD( SendMessageW( hwnd, LB_ITEMFROMPOINT, 0, lParam ) ), 0L ) == NULL )
+ return 0;
+ break;
+ }
+
+ return CallWindowProcW( fnOldProc, hwnd, uMsg, wParam, lParam );
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS setup_page_skin
+START_DISPATCH
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(API_SETUPPAGE_GET_NAME, GetName)
+CB(API_SETUPPAGE_CREATEVIEW, CreateView)
+CB(API_SETUPPAGE_SAVE, Save)
+CB(API_SETUPPAGE_REVERT, Revert)
+CB(API_SETUPPAGE_ISDIRTY, IsDirty)
+CB(API_SETUPPAGE_VALIDATE, Validate)
+END_DISPATCH
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/setup/spage_skin.h b/Src/Winamp/setup/spage_skin.h
new file mode 100644
index 00000000..3a380731
--- /dev/null
+++ b/Src/Winamp/setup/spage_skin.h
@@ -0,0 +1,52 @@
+#ifndef WINAMP_SKIN_SETUP_PAGE_HEADER
+#define WINAMP_SKIN_SETUP_PAGE_HEADER
+
+#include "./ifc_setuppage.h"
+
+class setup_page_skin : public ifc_setuppage
+{
+public:
+ setup_page_skin();
+ virtual ~setup_page_skin();
+
+public:
+ size_t AddRef();
+ size_t Release();
+ HRESULT GetName(bool bShort, const wchar_t **pszName);
+ HRESULT Save(HWND hwndText);
+ HRESULT CreateView(HWND hwndParent, HWND *phwnd);
+ HRESULT Revert(void);
+ HRESULT IsDirty(void);
+ HRESULT Validate(void);
+protected:
+ INT_PTR PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR OnInitDialog(HWND hwndFocus, LPARAM lParam);
+ void OnDestroy(void);
+ INT_PTR OnColorStatic(HDC hdc, HWND hwndCtrl);
+ INT_PTR OnDrawItem(INT nCtrlID, DRAWITEMSTRUCT *pdis);
+ INT_PTR OnMeasureItem(INT nCtrlID, MEASUREITEMSTRUCT *pmis);
+ void OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl);
+ INT_PTR OnDeleteItem(INT nCtrlID, DELETEITEMSTRUCT *pdis);
+ INT_PTR OnCompareItem(INT nCtrlID, COMPAREITEMSTRUCT *pcis);
+ INT_PTR OnVKeyToItem(WORD vKey, INT index, HWND hwndCtrl);
+ INT_PTR OnCharToItem(WORD vKey, INT index, HWND hwndCtrl);
+
+ void ListBox_OnDrawItem(DRAWITEMSTRUCT *pdis);
+ void ListBox_OnSelChange(HWND hwndCtrl);
+ void ListBox_OnItemDelete(DELETEITEMSTRUCT *pdis);
+ INT_PTR ListBox_OnItemCompare(COMPAREITEMSTRUCT *pcis);
+ INT_PTR ListBox_OnVKeyToItem(HWND hwndLB, WORD vKey, INT index);
+ INT_PTR ListBox_OnCharToItem(HWND hwndLB, WORD vKey, INT index);
+
+private:
+ size_t ref;
+ HWND hwnd;
+ HFONT hfLink;
+ int idxSelected; // internal crap
+ wchar_t szSelectionPath[MAX_PATH];
+protected:
+ friend static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ RECVS_DISPATCH;
+};
+
+#endif //WINAMP_SKIN_SETUP_PAGE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/setup/svc_setup.h b/Src/Winamp/setup/svc_setup.h
new file mode 100644
index 00000000..d4cd8106
--- /dev/null
+++ b/Src/Winamp/setup/svc_setup.h
@@ -0,0 +1,123 @@
+#ifndef NULLSOFT_WINAMP_SETUP_SERVICE_HEADER
+#define NULLSOFT_WINAMP_SETUP_SERVICE_HEADER
+
+#include <bfc/dispatch.h>
+#include "./ifc_setuppage.h"
+#include "./ifc_setupjob.h"
+
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+class api_service;
+typedef BOOL (__cdecl *Plugin_RegisterSetup)(HINSTANCE /*hInstance*/, api_service* /*serviceApi*/);
+
+class __declspec(novtable) svc_setup : public Dispatchable
+{
+protected:
+ svc_setup(void) {};
+ ~svc_setup(void) {};
+public:
+ HRESULT InsertPage(ifc_setuppage *pPage, int* pIndex);
+ HRESULT RemovePage(int index);
+ HRESULT GetPageCount(int* pCount);
+ HRESULT GetPage(int index, ifc_setuppage **pPage);
+ HRESULT GetActiveIndex(int*pIndex);
+ HRESULT Start(HWND hwndWinamp);
+ HRESULT AddJob(ifc_setupjob *pJob);
+ HRESULT RemoveJob(ifc_setupjob *pJob);
+ HRESULT CreateStatusWnd(HWND *phwndStatus);
+ HRESULT Save(HWND hwndStatus);
+ HRESULT ExecJobs(HWND hwndStatus);
+ HRESULT GetWinampWnd(HWND *phwndWinamp); // this call will return S_OK only after setup->Start()
+
+public:
+ DISPATCH_CODES
+ {
+ API_SETUP_INSERT_PAGE = 10,
+ API_SETUP_REMOVE_PAGE = 20,
+ API_SETUP_GET_PAGE_COUNT= 30,
+ API_SETUP_GET_PAGE= 40,
+ API_SETUP_GET_ACTIVE_INDEX = 50,
+ API_SETUP_START = 60,
+ API_SETUP_ADD_JOB = 70,
+ API_SETUP_REMOVE_JOB = 80,
+ API_SETUP_CREATE_STATUSWND = 90,
+ API_SETUP_SAVE = 100,
+ API_SETUP_EXECJOBS = 110,
+ API_SETUP_GETWINAMPWND = 120,
+
+ };
+};
+
+inline HRESULT svc_setup::InsertPage(ifc_setuppage *pPage, int* pIndex)
+{
+ return _call(API_SETUP_INSERT_PAGE, E_NOTIMPL, pPage, pIndex);
+}
+
+inline HRESULT svc_setup::RemovePage(int index)
+{
+ return _call(API_SETUP_REMOVE_PAGE, E_NOTIMPL, index);
+}
+
+inline HRESULT svc_setup::GetPageCount(int* pCount)
+{
+ return _call(API_SETUP_GET_PAGE_COUNT, E_NOTIMPL, pCount);
+}
+
+inline HRESULT svc_setup::GetPage(int index, ifc_setuppage **pPage)
+{
+ return _call(API_SETUP_GET_PAGE, E_NOTIMPL, index, pPage);
+}
+inline HRESULT svc_setup::GetActiveIndex(int*pIndex)
+{
+ return _call(API_SETUP_GET_ACTIVE_INDEX, E_NOTIMPL, pIndex);
+}
+inline HRESULT svc_setup::Start(HWND hwndWinamp)
+{
+ return _call(API_SETUP_START, E_NOTIMPL, hwndWinamp);
+}
+
+inline HRESULT svc_setup::AddJob(ifc_setupjob *pJob)
+{
+ return _call(API_SETUP_ADD_JOB, E_NOTIMPL, pJob);
+}
+
+inline HRESULT svc_setup::RemoveJob(ifc_setupjob *pJob)
+{
+ return _call(API_SETUP_REMOVE_JOB, E_NOTIMPL, pJob);
+}
+
+inline HRESULT svc_setup::CreateStatusWnd(HWND *phwndStatus)
+{
+ return _call(API_SETUP_CREATE_STATUSWND, E_NOTIMPL, phwndStatus);
+}
+
+inline HRESULT svc_setup::Save(HWND hwndStatus)
+{
+ return _call(API_SETUP_SAVE, E_NOTIMPL, hwndStatus);
+}
+
+inline HRESULT svc_setup::ExecJobs(HWND hwndStatus)
+{
+ return _call(API_SETUP_EXECJOBS, E_NOTIMPL, hwndStatus);
+}
+
+inline HRESULT svc_setup::GetWinampWnd(HWND *phwndWinamp)
+{
+ return _call(API_SETUP_GETWINAMPWND, E_NOTIMPL, phwndWinamp);
+}
+
+
+
+// {A7281DEB-9DA8-4ee9-93A8-2E0B8F5F1805}
+static const GUID UID_SVC_SETUP = { 0xa7281deb, 0x9da8, 0x4ee9, { 0x93, 0xa8, 0x2e, 0xb, 0x8f, 0x5f, 0x18, 0x5 } };
+
+
+#endif //NULLSOFT_WINAMP_SETUP_SERVICE_HEADER
diff --git a/Src/Winamp/setup/wa_classic_preview.png b/Src/Winamp/setup/wa_classic_preview.png
new file mode 100644
index 00000000..7a02a1da
--- /dev/null
+++ b/Src/Winamp/setup/wa_classic_preview.png
Binary files differ
diff --git a/Src/Winamp/skinWindow.cpp b/Src/Winamp/skinWindow.cpp
new file mode 100644
index 00000000..8a4ddc12
--- /dev/null
+++ b/Src/Winamp/skinWindow.cpp
@@ -0,0 +1,1311 @@
+#include <windowsx.h>
+
+#include "main.h"
+#include "./api.h"
+#include "./wa_dlg.h"
+#include "./skinWindow.h"
+#include "./skinWindowIPC.h"
+#include "./wintheme.h"
+#include "./draw.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(blah) (sizeof(blah)/sizeof(*blah))
+#endif
+
+#ifndef OCR_NORMAL
+#define OCR_NORMAL 32512
+#endif
+
+#ifndef LONGX86
+#ifdef _WIN64
+ #define LONGX86 LONG_PTR
+#else /*_WIN64*/
+ #define LONGX86 LONG
+#endif /*_WIN64*/
+#endif // LONGX86
+
+#ifdef __cplusplus
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) ::SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#else
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#endif // __cplusplus
+
+#define SENDWAIPC(__ipcMsgId, __param) SENDMSG(hMainWindow, WM_WA_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
+
+#ifndef WM_NCUAHDRAWCAPTION
+#define WM_NCUAHDRAWCAPTION 0x00AE
+#define WM_NCUAHDRAWFRAME 0x00AF
+#endif //WM_NCUAHDRAWCAPTION
+
+// additional WM_SYSCOMMAND commands
+#define SC_DRAGMOVE 0xF012
+#define SC_DRAGSIZE_N 0xF003
+#define SC_DRAGSIZE_S 0xF006
+#define SC_DRAGSIZE_E 0xF002
+#define SC_DRAGSIZE_W 0xF001
+#define SC_DRAGSIZE_NW 0xF004
+#define SC_DRAGSIZE_NE 0xF005
+#define SC_DRAGSIZE_SW 0xF007
+#define SC_DRAGSIZE_SE 0xF008
+
+#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWL_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
+#define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
+
+#define RESIZESTEP_CX 25
+#define RESIZESTEP_CY 29
+
+static ATOM SKINNEDWND_ATOM = 0;
+
+// this flags for iternal use
+#define SWS_EX_MASK 0xFFFF0000
+#define SWS_EX_ATTACHED 0x00010000 // window attached
+#define SWS_EX_UNICODE 0x00020000 // winodow is unicode
+#define SWS_EX_THEMED 0x00040000 // was themed before
+#define SWS_EX_DIALOG 0x00100000 // treat this as dialog
+
+#define BORDERWIDTH_LEFT 11
+#define BORDERWIDTH_TOP 20
+#define BORDERWIDTH_RIGHT 8
+#define BORDERWIDTH_BOTTOM 14
+
+#define CHILDBORDER_LEFT 1
+#define CHILDBORDER_TOP 1
+#define CHILDBORDER_RIGHT 1
+#define CHILDBORDER_BOTTOM 1
+
+#define CLOSEBUTTON_HEIGHT 9
+#define CLOSEBUTTON_WIDTH 9
+#define CLOSEBUTTON_OFFSET_X -11
+#define CLOSEBUTTON_OFFSET_Y 3
+
+#define SIZERGRIP_WIDTH 20
+#define SIZERGRIP_HEIGHT 20
+
+#define MOVEABLEAREA_HEIGHT 13
+
+#define BUTTON_NORMAL 0
+#define BUTTON_PUSHED 1
+#define BUTTON_DISABLED (-1)
+
+#ifndef TME_NONCLIENT
+#define TME_NONCLIENT 0x00000010
+#define WM_NCMOUSELEAVE 0x02A2
+#endif
+
+#define WAMSG_CLOSE (WM_USER + 101)
+
+typedef struct __SKINNEDWND
+{
+ HWND hwnd;
+ WNDPROC fnWndProc;
+ DWORD flags;
+ POINT movingOffset;
+ INT buttonState;
+ embedWindowState embedData;
+} SKINNEDWND;
+
+#define GetSkinnedWnd(__hwnd) ((SKINNEDWND*)GetPropW((__hwnd), ((LPCWSTR)MAKEINTATOM(SKINNEDWND_ATOM))))
+#define IsDialog(__skinnedWindow) (0 != (SWS_EX_DIALOG & (__skinnedWindow)->flags))
+#define IsUnicode(__skinnedWindow) (0 != (SWS_EX_UNICODE & (__skinnedWindow)->flags))
+
+#define SetWndLongPtr(__skinnedWnd, __index, __data)\
+ ((LONG_PTR)(IsUnicode(__skinnedWnd) ? SetWindowLongPtrW((__skinnedWnd)->hwnd, (__index), ((LONGX86)(LONG_PTR)(__data))) :\
+ SetWindowLongPtrA((__skinnedWnd)->hwnd, (__index), ((LONGX86)(LONG_PTR)(__data)))))
+
+#define CallWndProc(__skinnedWnd, __uMsg, __wParam, __lParam)\
+ (IsUnicode(__skinnedWnd) ?\
+ CallWindowProcW((__skinnedWnd)->fnWndProc, (__skinnedWnd)->hwnd, (__uMsg), (__wParam), (__lParam)) :\
+ CallWindowProcA((__skinnedWnd)->fnWndProc, (__skinnedWnd)->hwnd, (__uMsg), (__wParam), (__lParam)))
+
+#define DefWndProc(__skinnedWnd, __uMsg, __wParam, __lParam)\
+ (IsUnicode(__skinnedWnd) ?\
+ DefWindowProcW((__skinnedWnd)->hwnd, (__uMsg), (__wParam), (__lParam)) :\
+ DefWindowProcA((__skinnedWnd)->hwnd, (__uMsg), (__wParam), (__lParam)))
+
+void draw_embed_tbar(HWND hwnd, int state, int w);
+void SnapWindowToAllWindows(RECT *outrc, HWND hwndNoSnap);
+
+static LRESULT CALLBACK SkinnedWnd_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static void SkinnedWindow_Delete(SKINNEDWND *pWnd)
+{
+ HWND hDetached = NULL;
+ if (NULL == pWnd) return;
+
+ hDetached = pWnd->hwnd;
+ SetWndLongPtr(pWnd, GWLP_USERDATA, NULL);
+ RemovePropW(pWnd->hwnd, ((LPCWSTR)MAKEINTATOM(SKINNEDWND_ATOM)));
+
+ if (NULL != pWnd->embedData.me)
+ {
+ EnterCriticalSection(&embedcs);
+ embedWindowState *p = embedwndlist;
+ if (p == &pWnd->embedData)
+ {
+ embedwndlist=pWnd->embedData.link; // remove ourselves
+ embedwndlist_cnt--;
+ }
+ else
+ {
+ while (p)
+ {
+ if (p->link == &pWnd->embedData)
+ {
+ p->link=pWnd->embedData.link;
+ embedwndlist_cnt--;
+ break;
+ }
+ p=p->link;
+ }
+ }
+ LeaveCriticalSection(&embedcs);
+ }
+
+ if (NULL != pWnd->fnWndProc)
+ {
+ SetWndLongPtr(pWnd, GWLP_WNDPROC, pWnd->fnWndProc);
+ pWnd->fnWndProc = NULL;
+ }
+ free(pWnd);
+
+ if (NULL != hDetached)
+ {
+ SetWindowPos(hDetached, NULL, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
+ }
+}
+
+static SKINNEDWND *SkinnedWindow_Cerate(HWND hwndToSkin)
+{
+ if (NULL == hwndToSkin || !IsWindow(hwndToSkin))
+ return NULL;
+
+ if (NULL != GetSkinnedWnd(hwndToSkin))
+ return NULL;
+
+ if (0 == SKINNEDWND_ATOM)
+ {
+ SKINNEDWND_ATOM = GlobalAddAtomW(L"WASKINNEDWND");
+ if (0 == SKINNEDWND_ATOM)
+ return NULL;
+ }
+
+ SKINNEDWND *pWnd = (SKINNEDWND*)calloc(1, sizeof(SKINNEDWND));
+ if (NULL == pWnd)
+ return NULL;
+
+ pWnd->hwnd = hwndToSkin;
+ if (IsWindowUnicode(hwndToSkin)) pWnd->flags |= SWS_EX_UNICODE;
+
+ WCHAR szName[128] = {0};
+ if (GetClassNameW(hwndToSkin, szName, ARRAYSIZE(szName)))
+ {
+ if (CSTR_EQUAL == CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, szName, -1, L"#32770", -1))
+ pWnd->flags |= SWS_EX_DIALOG;
+ }
+
+ pWnd->fnWndProc = (WNDPROC)SetWndLongPtr(pWnd, GWLP_WNDPROC, SkinnedWnd_WindowProc);
+ if (NULL == pWnd->fnWndProc || !SetPropW(hwndToSkin, ((LPCWSTR)MAKEINTATOM(SKINNEDWND_ATOM)), pWnd))
+ {
+ SkinnedWindow_Delete(pWnd);
+ return NULL;
+ }
+ pWnd->flags |= SWS_EX_ATTACHED;
+
+ if (S_OK == Dwm_LoadLibrary())
+ {
+ DWMNCRENDERINGPOLICY ncrp = DWMNCRP_DISABLED;
+ DWORD allow = FALSE;
+ DwmSetWindowAttribute(pWnd->hwnd, DWMWA_NCRENDERING_POLICY, &ncrp, sizeof(ncrp));
+ DwmSetWindowAttribute(pWnd->hwnd, DWMWA_ALLOW_NCPAINT, &allow, sizeof(allow));
+ }
+
+ if (S_OK == UxTheme_LoadLibrary() && IsAppThemed())
+ {
+ SetWindowTheme(pWnd->hwnd, NULL, L"");
+ pWnd->flags |= SWS_EX_THEMED;
+ }
+
+ if (!config_embedwnd_freesize &&
+ 0 == (WS_CHILD & GetWindowLongPtrW(pWnd->hwnd, GWL_STYLE)))
+ {
+ RECT rc;
+ if (GetWindowRect(hwndToSkin, &rc))
+ {
+ LONG w, h;
+ OffsetRect(&rc, -rc.left, -rc.top);
+
+ w = rc.right + (RESIZESTEP_CX - 1);
+ w -= w % RESIZESTEP_CX;
+ h = rc.bottom + (RESIZESTEP_CY - 1);
+ h -= h % RESIZESTEP_CY;
+
+ if (w != rc.right || h != rc.bottom)
+ SetWindowPos(hwndToSkin, NULL, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
+ }
+ }
+
+ return pWnd;
+}
+
+BOOL SkinWindow(HWND hwndToSkin, REFGUID windowGuid, UINT flagsEx, FFCALLBACK callbackFF)
+{
+ SKINNEDWND *pWnd = SkinnedWindow_Cerate(hwndToSkin);
+
+ if (NULL == pWnd)
+ return FALSE;
+
+ pWnd->embedData.me = pWnd->hwnd;
+ pWnd->embedData.user_ptr = pWnd;
+ pWnd->embedData.flags |= (EMBED_FLAGS_GUID | flagsEx);
+ pWnd->embedData.guid = windowGuid;
+
+ pWnd->embedData.callback = callbackFF;
+ if (NULL != pWnd->embedData.callback)
+ pWnd->embedData.flags |= EMBED_FLAGS_FFCALLBACK;
+
+ GetWindowRect(pWnd->hwnd, &pWnd->embedData.r);
+
+ EnterCriticalSection(&embedcs);
+
+ pWnd->embedData.link = embedwndlist;
+ embedwndlist = &pWnd->embedData;
+ embedwndlist_cnt++;
+
+ LeaveCriticalSection(&embedcs);
+
+ SetWndLongPtr(pWnd, GWLP_USERDATA, &pWnd->embedData);
+
+ return TRUE;
+}
+
+static int SkinnedWindow_GetTextWidth(LPCTSTR pszText, INT cchText)
+{
+ int w = 0;
+ while (cchText--)
+ {
+ char c = *pszText++;
+ if (c >= 'a' && c <= 'z') c+='A'-'a';
+
+ if (c >= 'A' && c <= 'Z' && titlebar_font_widths[c-'A'])
+ w+=titlebar_font_widths[c-'A'];
+ else if (c >= '0' && c <= '9' && titlebar_font_widths[c-'0'] && Skin_UseGenNums)
+ w+=titlebar_font_num_widths[c-'0'];
+ else if (c == '-' && titlebar_font_widths[10] && Skin_UseGenNums)
+ w+=titlebar_font_num_widths[10];
+ else if (c == ':' && titlebar_font_widths[11] && Skin_UseGenNums)
+ w+=titlebar_font_num_widths[11];
+ else w+=titlebar_font_unknown_width;
+
+ }
+ return w;
+}
+
+static void SkinnedWindow_DrawText(HDC hdc, HDC hdcSrc, int xp, int yp, LPCTSTR pszText, INT cchText, RECT *prc, BOOL bActive)
+{
+ int w;
+ int srcY = 88 + ((bActive) ? 8 : 0);
+ int srcYnum = 72 + ((bActive) ? 8 : 0);
+ int bgsrcY = ((bActive) ? 21 : 0);
+ int bgX = prc->left;
+ int maxw = prc->right;
+ while (cchText-- && maxw > 0)
+ {
+ char c = *pszText++;
+
+ if (bgX <= xp)
+ {
+ int bgW = 25;
+ if (bgW + bgX > prc->right) bgW = prc->right - bgX;
+ BitBlt(hdc, bgX, prc->top, bgW, (prc->bottom - prc->top), hdcSrc, 52, bgsrcY, SRCCOPY);
+ bgX += bgW;
+ }
+
+ if (c >= 'a' && c <= 'z') c+='A'-'a';
+ if (c >= 'A' && c <= 'Z' && titlebar_font_widths[c-'A'])
+ {
+ w = titlebar_font_widths[c - 'A'];
+ if (w > maxw) break;
+
+ if (bgX <= (xp + w))
+ {
+ int bgW = 25;
+ if (bgW + bgX > prc->right) bgW = prc->right - bgX;
+ BitBlt(hdc, bgX, prc->top, bgW, (prc->bottom - prc->top), hdcSrc, 52, bgsrcY, SRCCOPY);
+ bgX += bgW;
+ }
+
+ BitBlt(hdc, xp, yp, w, 7, hdcSrc, titlebar_font_offsets[c - 'A'], srcY, SRCCOPY);
+ }
+ else if (c >= '0' && c <= '9' && titlebar_font_num_widths[c - '0'] && Skin_UseGenNums)
+ {
+ w = titlebar_font_num_widths[c - '0'];
+ if (w > maxw) break;
+
+ if (bgX <= (xp + w))
+ {
+ int bgW = 25;
+ if (bgW + bgX > prc->right) bgW = prc->right - bgX;
+ BitBlt(hdc, bgX, prc->top, bgW, (prc->bottom - prc->top), hdcSrc, 52, bgsrcY, SRCCOPY);
+ bgX += bgW;
+ }
+
+ BitBlt(hdc, xp, yp, w, 7, hdcSrc, titlebar_font_num_offsets[c - '0'], srcYnum, SRCCOPY);
+ }
+ else if (c == '-' && titlebar_font_num_widths[10] && Skin_UseGenNums)
+ {
+ w = titlebar_font_num_widths[10];
+ if (w > maxw) break;
+
+ if (bgX <= (xp + w))
+ {
+ int bgW = 25;
+ if (bgW + bgX > prc->right) bgW = prc->right - bgX;
+ BitBlt(hdc, bgX, prc->top, bgW, (prc->bottom - prc->top), hdcSrc, 52, bgsrcY, SRCCOPY);
+ bgX += bgW;
+ }
+
+ BitBlt(hdc, xp, yp, w, 7, hdcSrc, titlebar_font_num_offsets[10], srcYnum, SRCCOPY);
+ }
+ else if (c == ':' && titlebar_font_num_widths[11] && Skin_UseGenNums)
+ {
+ w = titlebar_font_num_widths[11];
+ if (w > maxw) break;
+
+ if (bgX <= (xp + w))
+ {
+ int bgW = 25;
+ if (bgW + bgX > prc->right) bgW = prc->right - bgX;
+ BitBlt(hdc, bgX, prc->top, bgW, (prc->bottom - prc->top), hdcSrc, 52, bgsrcY, SRCCOPY);
+ bgX += bgW;
+ }
+
+ BitBlt(hdc, xp, yp, w, 7, hdcSrc, titlebar_font_num_offsets[11], srcYnum, SRCCOPY);
+ }
+ else
+ w = titlebar_font_unknown_width;
+
+ xp += w;
+ maxw -= w;
+ }
+}
+
+static void SkinnedWindow_DrawCloseButton(HDC hdc, HDC hdcSrc, RECT *prcWindow, BOOL bActive, INT buttonState)
+{
+ INT srcX, srcY;
+
+ switch(buttonState)
+ {
+ case BUTTON_PUSHED:
+ srcX = 148; srcY = 42;
+ break;
+ case BUTTON_NORMAL:
+ srcX = 144; srcY = 3;
+ if (!bActive) srcY += 21;
+ break;
+ case BUTTON_DISABLED:
+ default:
+ srcX = 144; srcY = 3;
+ break;
+ }
+ BitBlt(hdc, prcWindow->right - 11,prcWindow->top + 3, 9, 9, hdcSrc,srcX, srcY, SRCCOPY);
+}
+
+static void SkinnedWindow_DrawCaptionEx(HDC hdc, HDC hdcSrc, LPCTSTR pszText, INT cchText, int state, int w, int h)
+{
+ state = state ? 0 : 21;
+ int nt;
+ int xp=0;
+ int textw_exact = 0, textw = 0;
+ int cchTextOrig = cchText;
+ if (cchText > 0)
+ {
+ for(;cchText > 0; cchText--)
+ {
+ textw_exact = SkinnedWindow_GetTextWidth(pszText, cchText);
+ textw = textw_exact + 24;
+ textw -= textw % 25;
+ if ((w - textw) > 100) break;
+ textw = 0;
+ }
+ }
+
+ BitBlt(hdc,xp,0,25,20, hdcSrc, 0, state,SRCCOPY);
+ xp+=25;
+ nt = (w - 100 - textw)/25;
+ if (nt > 0)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdc,xp,0,12,20,hdcSrc,104,state,SRCCOPY);
+ xp+=12;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdc,xp,0,25,20,hdcSrc,104,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+
+ if (cchText > 0)
+ {
+ BitBlt(hdc,xp,0,25,20,hdcSrc,26,state,SRCCOPY);
+ xp+=25;
+ nt = textw/25;
+ if (nt > 0)
+ {
+
+ RECT rt;
+ SetRect(&rt, xp, 0, xp + textw, 20);
+
+ SkinnedWindow_DrawText(hdc, hdcSrc,
+ rt.left + ((cchText == cchTextOrig) ? (textw - textw_exact)/2 : 0), 4,
+ pszText, cchText, &rt, state);
+ xp += nt*25;
+ }
+
+ BitBlt(hdc,xp,0,25,20,hdcSrc,78,state,SRCCOPY);
+ xp+=25;
+ }
+ else
+ {
+ nt = (w - 50)/2;
+ if (nt > 25) nt = 25;
+ if (nt > 0)
+ {
+ BitBlt(hdc,xp, 0, nt,20,hdcSrc,104,state,SRCCOPY);
+ xp+=nt;
+ if (nt < 25 && 0 != (w - 50)%2)nt++;
+ BitBlt(hdc,xp, 0, nt, 20, hdcSrc,104 + (25- nt),state,SRCCOPY);
+ xp+=nt;
+ }
+ }
+
+ nt = (w - 100 - textw)/25;
+ if (nt > 0)
+ {
+ if (nt&1)
+ {
+ BitBlt(hdc,xp,0,13,20,hdcSrc,104,state,SRCCOPY);
+ xp+=13;
+ }
+ nt/=2;
+ while (nt-->0)
+ {
+ BitBlt(hdc,xp,0,25,20,hdcSrc,104,state,SRCCOPY);
+ xp+=25;
+ }
+ }
+ nt = (w - 100 - textw) % 25;
+ if (nt > 0)
+ {
+ BitBlt(hdc,xp,0,nt,20,hdcSrc,104,state,SRCCOPY);
+ //StretchBlt(hdc,xp,0,nt,20,hdcSrc,104,state,25,20,SRCCOPY);
+ xp += nt;
+ }
+ BitBlt(hdc,xp,0,25,20,hdcSrc,130,state,SRCCOPY);
+}
+
+static void SkinnedWindow_DrawCaption(SKINNEDWND *pWnd, BOOL bActive, POINT *cursor)
+{
+ RECT rc;
+ GetWindowRect(pWnd->hwnd, &rc);
+ OffsetRect(&rc, -rc.left, -rc.top);
+
+
+ UINT flags = DCX_PARENTCLIP | DCX_CACHE | DCX_WINDOW | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
+ DCX_INTERSECTUPDATE | DCX_VALIDATE | DCX_NORESETATTRS;
+ HDC hdc = GetDCEx(pWnd->hwnd, NULL, flags);
+ if (NULL == hdc)
+ return;
+
+ do_palmode(hdc);
+ setSrcBM(embedBM);
+
+ char szTitle[128] = {0};
+ INT cchTitle = GetWindowTextA(pWnd->hwnd, szTitle, ARRAYSIZE(szTitle));
+
+ INT state = pWnd->buttonState;
+ if (BUTTON_PUSHED == state)
+ {
+ if (NULL == cursor || HTCLOSE != SendMessageW(pWnd->hwnd, WM_NCHITTEST, 0, MAKELPARAM(cursor->x, cursor->y)))
+ state = BUTTON_NORMAL;
+ }
+
+ SkinnedWindow_DrawCaptionEx(hdc, bmDC, (LPCTSTR)szTitle, cchTitle, bActive ? 1 : (config_hilite?0:1),
+ rc.right - rc.left, rc.bottom - rc.top);
+ SkinnedWindow_DrawCloseButton(hdc, bmDC, &rc, bActive, state);
+
+ unsetSrcBM();
+ ReleaseDC(pWnd->hwnd, hdc);
+
+}
+
+static void SkinnedWindow_DrawBorder(SKINNEDWND *pWnd, HDC hdc, HRGN rgnUpdate, POINT *cursor)
+{
+
+ DWORD style = GetWindowLongPtrW(pWnd->hwnd, GWL_STYLE);
+ if (0 == (WS_BORDER & style))
+ return;
+
+ RECT rc;
+ GetWindowRect(pWnd->hwnd, &rc);
+ OffsetRect(&rc, -rc.left, -rc.top);
+ LONG w = rc.right, h = rc.bottom;
+
+ do_palmode(hdc);
+ setSrcBM(embedBM);
+
+ if (0 != (WS_CHILD & style))
+ {
+ if (!WADlg_initted())
+ WADlg_init(hMainWindow);
+ COLORREF rgbOld = SetBkColor(hdc, WADlg_getColor(WADLG_HILITE));
+
+ RECT part;
+ SetRect(&part, rc.left, rc.top, rc.right, rc.top + CHILDBORDER_TOP);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &part, NULL, 0, NULL);
+ SetRect(&part, rc.right - CHILDBORDER_RIGHT, rc.top + CHILDBORDER_TOP, rc.right, rc.bottom - CHILDBORDER_BOTTOM);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &part, NULL, 0, NULL);
+ SetRect(&part, rc.left, rc.bottom - CHILDBORDER_BOTTOM, rc.right, rc.bottom);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &part, NULL, 0, NULL);
+ SetRect(&part, rc.left, rc.top + CHILDBORDER_TOP, rc.left + CHILDBORDER_LEFT, rc.bottom - CHILDBORDER_BOTTOM);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &part, NULL, 0, NULL);
+
+ SetBkColor(hdc, rgbOld);
+ return;
+ }
+
+ if (0 != (WS_CAPTION & style))
+ {
+ char szTitle[128] = {0};
+ INT cchTitle = GetWindowTextA(pWnd->hwnd, szTitle, ARRAYSIZE(szTitle));
+
+ INT state = pWnd->buttonState;
+ if (BUTTON_PUSHED == state)
+ {
+ if (NULL == cursor || HTCLOSE != SendMessageW(pWnd->hwnd, WM_NCHITTEST, 0, MAKELPARAM(cursor->x, cursor->y)))
+ state = BUTTON_NORMAL;
+ }
+
+ BOOL bActive = (GetActiveWindow()==pWnd->hwnd) ? 1 : ((0 != config_hilite) ? 0 : 1);
+ SkinnedWindow_DrawCaptionEx(hdc, bmDC, (LPCTSTR)szTitle, cchTitle, bActive, w, h);
+ if (BUTTON_NORMAL != state)
+ SkinnedWindow_DrawCloseButton(hdc, bmDC, &rc, bActive, state);
+ }
+
+ int y=(h-20-38)/29;
+ int yp=20,x,xp;
+ while (y-->0)
+ {
+ BitBlt(hdc,0,yp,11,29,bmDC,127,42,SRCCOPY);
+ BitBlt(hdc,w-8,yp,8,29,bmDC,139,42,SRCCOPY);
+ yp += 29;
+ }
+ y=(h-20-38)%29;
+ if (y)
+ {
+ BitBlt(hdc,0,yp,11,y,bmDC,127,42,SRCCOPY);
+ //StretchBlt(hdc,0,yp,11,y,bmDC,127,42,11,29,SRCCOPY);
+ BitBlt(hdc,w-8,yp,8,y,bmDC,139,42,SRCCOPY);
+ //StretchBlt(hdc,w-8,yp,8,y,bmDC,139,42,8,29,SRCCOPY);
+ yp += y;
+ }
+
+ // 24 pixel lamity
+ BitBlt(hdc,0,yp,11,24,bmDC,158,42,SRCCOPY);
+ BitBlt(hdc,w-8,yp,8,24,bmDC,170,42,SRCCOPY);
+ yp += 24;
+
+ int realW = (w < 250) ? (w/2) : 125;
+ BitBlt(hdc,0,yp,realW,14,bmDC,0,42,SRCCOPY);
+
+ x=(w-125*2)/25;
+ xp=realW;
+ while (x-->0)
+ {
+ BitBlt(hdc,xp,yp,25,14,bmDC,127,72,SRCCOPY);
+ xp+=25;
+ }
+ x=(w-125*2)%25;
+ if (x > 0)
+ {
+ BitBlt(hdc,xp,yp,x,14,bmDC,127,72,SRCCOPY);
+ //StretchBlt(hdc,xp,yp,x,14,bmDC,127,72,25,14,SRCCOPY);
+ xp+=x;
+ }
+
+ if (realW < 125 && 0 != (w%2)) realW++;
+ BitBlt(hdc,xp,yp,realW,14,bmDC, (125 - realW),57,SRCCOPY);
+
+ if (0 != (EMBED_FLAGS_NORESIZE & pWnd->embedData.flags))
+ {
+ BitBlt(hdc,xp+112,yp+2,7,7,bmDC,118,72,SRCCOPY);
+ }
+
+ unsetSrcBM();
+}
+
+static BOOL SkinnedWindow_OnShowWindow(SKINNEDWND *pWnd, BOOL bShow, UINT flags)
+{
+ if (pWnd->embedData.reparenting)
+ return TRUE;
+
+ SENDWAIPC(((bShow) ? IPC_CB_ONSHOWWND : IPC_CB_ONHIDEWND), pWnd->hwnd);
+ return FALSE;
+}
+
+static LRESULT SkinnedWindow_OnNcCalcSize(SKINNEDWND *pWnd, BOOL bCalcValidRects, NCCALCSIZE_PARAMS *pncsp)
+{
+
+ DWORD style = (DWORD)GetWindowLongPtrW(pWnd->hwnd, GWL_STYLE);
+
+ RECT rc;
+ CopyRect(&rc, &pncsp->rgrc[0]);
+ CallWndProc(pWnd, WM_NCCALCSIZE, bCalcValidRects, (LPARAM)pncsp);
+ CopyRect(&pncsp->rgrc[0], &rc);
+
+ if (bCalcValidRects)
+ SetRect(&pncsp->rgrc[0], pncsp->lppos->x, pncsp->lppos->y,
+ pncsp->lppos->x + pncsp->lppos->cx, pncsp->lppos->y + pncsp->lppos->cy);
+ else
+ {
+ GetWindowRect(pWnd->hwnd, &pncsp->rgrc[0]);
+ if (0 != (WS_CHILD & style))
+ {
+ HWND hParent = GetParent(pWnd->hwnd);
+ if (NULL != hParent)
+ MapWindowPoints(HWND_DESKTOP, hParent, (POINT*)&pncsp->rgrc[0], 2);
+ }
+ }
+
+ if (0 != (WS_BORDER & style))
+ {
+ if (0 != (WS_CHILD & style))
+ {
+ pncsp->rgrc[0].top += CHILDBORDER_TOP;
+ pncsp->rgrc[0].left += CHILDBORDER_LEFT;
+ pncsp->rgrc[0].right -= CHILDBORDER_RIGHT;
+ pncsp->rgrc[0].bottom -= CHILDBORDER_BOTTOM;
+ }
+ else
+ {
+ pncsp->rgrc[0].top += BORDERWIDTH_TOP;
+ pncsp->rgrc[0].left += BORDERWIDTH_LEFT;
+ pncsp->rgrc[0].right -= BORDERWIDTH_RIGHT;
+ pncsp->rgrc[0].bottom -= BORDERWIDTH_BOTTOM;
+ }
+ }
+
+ return 0;
+}
+
+static void SkinnedWindow_OnNcPaint(SKINNEDWND *pWnd, HRGN rgnUpdate)
+{
+ if (0 == (WS_BORDER & GetWindowLongPtrW(pWnd->hwnd, GWL_STYLE)))
+ return;
+
+ UINT flags = DCX_PARENTCLIP | DCX_CACHE | DCX_WINDOW | DCX_CLIPSIBLINGS |
+ DCX_INTERSECTUPDATE | DCX_VALIDATE | DCX_NORESETATTRS;
+
+ HDC hdc = GetDCEx(pWnd->hwnd, ((HRGN)NULLREGION != rgnUpdate) ? rgnUpdate : NULL, flags);
+ if (NULL == hdc)
+ return;
+ POINT pt;
+ GetCursorPos(&pt);
+ SkinnedWindow_DrawBorder(pWnd, hdc, rgnUpdate, &pt);
+ ReleaseDC(pWnd->hwnd, hdc);
+}
+
+static void SkinnedWindow_OnPrint(SKINNEDWND *pWnd, HDC hdc, UINT options)
+{
+ if ((PRF_CHECKVISIBLE & options) && !IsWindowVisible(pWnd->hwnd)) return;
+ if (PRF_NONCLIENT & options)
+ {
+ POINT pt = {0, 0};
+ SkinnedWindow_DrawBorder(pWnd, hdc, (HRGN)NULLREGION, &pt);
+ }
+ if (PRF_CLIENT & options)
+ CallWndProc(pWnd, WM_PRINT, (WPARAM)hdc, (LPARAM)(~(PRF_NONCLIENT | PRF_CHECKVISIBLE) & options));
+}
+
+static LRESULT SkinnedWindow_OnNcHitTest(SKINNEDWND *pWnd, POINTS pts)
+{
+ POINT pt;
+ RECT rw, rt;
+ POINTSTOPOINT(pt, pts);
+
+ DWORD style = (DWORD)GetWindowLongPtrW(pWnd->hwnd, GWL_STYLE);
+
+ if (0 != (WS_DISABLED & style))
+ return HTERROR;
+
+ if (0 != (WS_CHILD & style))
+ {
+ if (0 != (WS_BORDER & style))
+ {
+ GetWindowRect(pWnd->hwnd, &rw);
+ rw.left += CHILDBORDER_LEFT;
+ rw.top += CHILDBORDER_TOP;
+ rw.right -= CHILDBORDER_RIGHT;
+ rw.bottom -= CHILDBORDER_BOTTOM;
+ if (PtInRect(&rt, pt))
+ return HTBORDER;
+ }
+ return HTCLIENT;
+ }
+
+ GetWindowRect(pWnd->hwnd, &rw);
+
+ if (0 != (WS_CAPTION & style))
+ {
+ SetRect(&rt, rw.left, rw.top, rw.right, rw.top + BORDERWIDTH_TOP);
+ if (PtInRect(&rt, pt)) // caption
+ {
+ SetRect(&rt, rw.right + CLOSEBUTTON_OFFSET_X, rw.top + CLOSEBUTTON_OFFSET_Y,
+ rw.right + CLOSEBUTTON_OFFSET_X + CLOSEBUTTON_WIDTH, rw.top + CLOSEBUTTON_OFFSET_Y + CLOSEBUTTON_HEIGHT);
+ if (PtInRect(&rt, pt)) // close button
+ return HTCLOSE;
+ return HTCAPTION;
+ }
+ }
+
+ if (0 != (WS_BORDER & style))
+ {
+ SetRect(&rt, rw.left, rw.top + BORDERWIDTH_TOP, rw.left + BORDERWIDTH_LEFT, rw.bottom - BORDERWIDTH_BOTTOM);
+ if (PtInRect(&rt, pt))
+ return HTBORDER; // left side (non resizable)
+
+ SetRect(&rt, rw.right - BORDERWIDTH_RIGHT, rw.top + BORDERWIDTH_TOP, rw.right, rw.bottom - SIZERGRIP_HEIGHT);
+ if (PtInRect(&rt, pt))
+ return HTBORDER; // right side (non resizable)
+
+ SetRect(&rt, rw.right - BORDERWIDTH_RIGHT, rw.bottom - SIZERGRIP_HEIGHT, rw.right, rw.bottom);
+ if (PtInRect(&rt, pt))
+ return (0 == (EMBED_FLAGS_NORESIZE & pWnd->embedData.flags)) ? HTBOTTOMRIGHT : HTBORDER; // sizer bottomright
+
+ SetRect(&rt, rw.left, rw.bottom - BORDERWIDTH_BOTTOM, rw.right -SIZERGRIP_WIDTH, rw.bottom);
+ if (PtInRect(&rt, pt))
+ return HTBORDER; // bottom_left + bottom (non resizable)
+
+ SetRect(&rt, rw.right - SIZERGRIP_WIDTH, rw.bottom - BORDERWIDTH_BOTTOM, rw.right, rw.bottom);
+ if (PtInRect(&rt, pt))
+ return (0 == (EMBED_FLAGS_NORESIZE & pWnd->embedData.flags)) ? HTBOTTOMRIGHT : HTBORDER; // sizer bottomright
+ }
+
+ SetRect(&rt, rw.left, rw.top, rw.right, rw.bottom);
+ if (PtInRect(&rt, pt))
+ return HTCLIENT; // client
+
+ return HTNOWHERE;
+}
+
+static LRESULT SkinnedWindow_OnSetCursor(SKINNEDWND *pWnd, HWND hwndCursor, INT hitTest, UINT uMsg)
+{
+ HCURSOR hCursor = NULL;
+
+ switch(uMsg)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_XBUTTONDOWN:
+ DisabledWindow_OnMouseClick(pWnd->hwnd);
+ break;
+ }
+
+ if (config_usecursors && !disable_skin_cursors)
+ {
+ int index = 15+5; // PNormal.cur
+ switch(hitTest)
+ {
+ case HTCAPTION:
+ { // this is required to emulate old behavior
+ POINT pt;
+ RECT rw;
+ GetCursorPos(&pt);
+ GetWindowRect(pWnd->hwnd, &rw);
+ rw.bottom = rw.top + MOVEABLEAREA_HEIGHT;
+ index = 15 + ((PtInRect(&rw, pt)) ? 2 : 5); // PTBar.cur
+ }
+ break;
+ case HTCLOSE:
+ index = 15 + 1; // PClose.cur
+ break;
+ case HTLEFT:
+ case HTRIGHT:
+ case HTTOP:
+ case HTTOPLEFT:
+ case HTTOPRIGHT:
+ case HTBOTTOM:
+ case HTBOTTOMLEFT:
+ case HTBOTTOMRIGHT:
+ index = 15 + 4;// PSize.cur
+ break;
+ }
+ hCursor = Skin_Cursors[index];
+ }
+
+ if (NULL != hCursor)
+ {
+ SetCursor(hCursor);
+ return TRUE;
+ }
+ return CallWndProc(pWnd, WM_SETCURSOR, (WPARAM)hwndCursor, MAKELPARAM(hitTest, uMsg));
+}
+
+static LRESULT SkinnedWindow_OnNcActivate(SKINNEDWND *pWnd, BOOL bActivate)
+{
+ if (0 == (WS_CAPTION & GetWindowLongPtrW(pWnd->hwnd, GWL_STYLE)))
+ return TRUE;
+
+ POINT pt;
+ GetCursorPos(&pt);
+ SkinnedWindow_DrawCaption(pWnd, bActivate, &pt);
+ return TRUE;
+}
+
+static void SkinnedWindow_OnActivate(SKINNEDWND *pWnd, unsigned int action, BOOL minimized, HWND otherWindow)
+{
+ if (NULL == pWnd)
+ return;
+
+ if (NULL != WASABI_API_APP)
+ {
+ if (WA_INACTIVE == action)
+ WASABI_API_APP->ActiveDialog_Unregister(pWnd->hwnd);
+ else
+ WASABI_API_APP->ActiveDialog_Register(pWnd->hwnd);
+ }
+}
+
+static BOOL SkinnedWindow_OnNcLButtonDown(SKINNEDWND *pWnd, INT hitTest, POINTS pts)
+{
+ switch(hitTest)
+ {
+ case HTCLOSE:
+ {
+ pWnd->buttonState = BUTTON_PUSHED;
+
+ TRACKMOUSEEVENT tm;
+ ZeroMemory(&tm, sizeof(TRACKMOUSEEVENT));
+ tm.cbSize = sizeof(TRACKMOUSEEVENT);
+ tm.dwFlags = TME_LEAVE | TME_NONCLIENT;
+ tm.hwndTrack = pWnd->hwnd;
+ TrackMouseEvent(&tm);
+
+ RedrawWindow(pWnd->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW);
+ }
+ return TRUE;
+ case HTCAPTION:
+ if (IsWindowEnabled(pWnd->hwnd) &&
+ GetActiveWindow() != pWnd->hwnd)
+ SetActiveWindow(pWnd->hwnd);
+ {
+ RECT rw;
+ if (GetWindowRect(pWnd->hwnd, &rw))
+ {
+ pWnd->movingOffset.x = pts.x - rw.left;
+ pWnd->movingOffset.y = pts.y - rw.top;
+ }
+ }
+ SendMessageW(pWnd->hwnd, WM_SYSCOMMAND, (SC_MOVE | 0x0002), (*(LPARAM*)&pts));
+ return TRUE;
+ case HTBOTTOM:
+ case HTBOTTOMLEFT:
+ case HTBOTTOMRIGHT:
+ if (IsWindowEnabled(pWnd->hwnd) &&
+ GetActiveWindow() != pWnd->hwnd)
+ SetActiveWindow(pWnd->hwnd);
+ SendMessageW(pWnd->hwnd, WM_SYSCOMMAND, SC_SIZE + hitTest - (HTLEFT - WMSZ_LEFT), (*(LPARAM*)&pts));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static BOOL SkinnedWindow_OnNcLButtonUp(SKINNEDWND *pWnd, INT hitTest, POINTS pts)
+{
+ BOOL bProcessed = FALSE;
+ if (HTCLOSE == hitTest && BUTTON_PUSHED == pWnd->buttonState)
+ {
+ SNDMSG(pWnd->hwnd, WM_SYSCOMMAND, SC_CLOSE, *(LPARAM*)&pts);
+ bProcessed = TRUE;
+ }
+
+ if (BUTTON_PUSHED == pWnd->buttonState)
+ {
+ pWnd->buttonState = BUTTON_NORMAL;
+ RedrawWindow(pWnd->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME);
+ }
+
+ return bProcessed;
+}
+
+static BOOL SkinnedWindow_OnNcRButtonDown(SKINNEDWND *pWnd, INT hitTest, POINTS pts)
+{
+ return TRUE;
+}
+
+static BOOL SkinnedWindow_OnNcRButtonUp(SKINNEDWND *pWnd, INT hitTest, POINTS pts)
+{
+ int ret = DoTrackPopup(main_menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pts.x, pts.y, pWnd->hwnd);
+ if (ret)
+ SendMessageW(hMainWindow,WM_COMMAND,ret,0);
+ return TRUE;
+}
+
+static void SkinnedWindow_OnNcMouseMove(SKINNEDWND *pWnd, INT hitTest, POINTS pts)
+{
+ if (BUTTON_PUSHED == pWnd->buttonState && HTCLOSE == hitTest)
+ {
+ RedrawWindow(pWnd->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME);
+ }
+}
+
+static void SkinnedWindow_OnNcMouseLeave(SKINNEDWND *pWnd)
+{
+ if (BUTTON_PUSHED == pWnd->buttonState)
+ {
+ if(0 != (0x8000 & GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON)))
+ {
+ TRACKMOUSEEVENT tm;
+ ZeroMemory(&tm, sizeof(TRACKMOUSEEVENT));
+ tm.cbSize = sizeof(TRACKMOUSEEVENT);
+ tm.dwFlags = TME_LEAVE | TME_NONCLIENT;
+ tm.hwndTrack = pWnd->hwnd;
+ TrackMouseEvent(&tm);
+ }
+ else
+ {
+ pWnd->buttonState = BUTTON_NORMAL;
+ RedrawWindow(pWnd->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME);
+ }
+ }
+}
+
+static void SkinnedWindow_OnWinampCustomClose(SKINNEDWND *pWnd, POINTS pts)
+{
+ if (0 != pWnd->embedData.reparenting)
+ return;
+
+ SNDMSG(pWnd->hwnd, WM_SYSCOMMAND, SC_CLOSE, *(LPARAM*)&pts);
+}
+
+static void SkinnedWindow_OnWindowPosChanging(SKINNEDWND *pWnd, WINDOWPOS *pwp)
+{
+ if (SWP_NOSIZE != ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
+ {
+ if (!config_embedwnd_freesize &&
+ 0 == (WS_CHILD & GetWindowLongPtrW(pWnd->hwnd, GWL_STYLE)))
+ {
+ pwp->cx += (RESIZESTEP_CX - 1);
+ pwp->cx -= pwp->cx % RESIZESTEP_CX;
+ pwp->cy += (RESIZESTEP_CY - 1);
+ pwp->cy -= pwp->cy % RESIZESTEP_CY;
+ }
+ if (pwp->cx < RESIZESTEP_CX*2) pwp->cx = RESIZESTEP_CX*2;
+ if (pwp->cy < RESIZESTEP_CY*2) pwp->cy = RESIZESTEP_CY*2;
+ }
+ CallWndProc(pWnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pwp);
+}
+
+static void SkinnedWindow_OnWindowPosChanged(SKINNEDWND *pWnd, WINDOWPOS *pwp)
+{
+ if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED) & pwp->flags))
+ {
+ SetRect(&pWnd->embedData.r, pwp->x, pwp->y, pwp->x + pwp->cx, pwp->y + pwp->cy);
+ }
+
+ CallWndProc(pWnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)pwp);
+}
+
+static void SkinnedWindow_OnMoving(SKINNEDWND *pWnd, RECT *prc)
+{
+ if (0 == (SWS_EX_NOSNAP & pWnd->flags) &&
+ (0xFFFF != pWnd->movingOffset.x && 0xFFFF != pWnd->movingOffset.y) &&
+ (!!config_snap + (0 != (0x8000 & GetAsyncKeyState(VK_SHIFT))) == 1))
+ {
+ POINT pt;
+ GetCursorPos(&pt);
+ INT cx = prc->right - prc->left;
+ INT cy = prc->bottom - prc->top;
+ prc->left = pt.x - pWnd->movingOffset.x;
+ prc->top = pt.y - pWnd->movingOffset.y;
+ prc->right = prc->left + cx;
+ prc->bottom = prc->top + cy;
+ SnapWindowToAllWindows(prc, pWnd->hwnd);
+ }
+}
+
+static void SkinnedWindow_OnSizing(SKINNEDWND *pWnd, UINT edge, RECT *prc)
+{
+ LONG cx, cy;
+ cx = prc->right - prc->left;
+ cy = prc->bottom - prc->top;
+
+ if (!config_embedwnd_freesize &&
+ 0 == (0x8000 & GetAsyncKeyState(VK_SHIFT)))
+ {
+ cx += (RESIZESTEP_CX - 1);
+ cx -= cx % RESIZESTEP_CX;
+ cy += (RESIZESTEP_CY - 1);
+ cy -= cy % RESIZESTEP_CY;
+ }
+
+ if (cx < RESIZESTEP_CX*2) cx = RESIZESTEP_CX*2;
+ if (cy < RESIZESTEP_CY*2) cy = RESIZESTEP_CY*2;
+ prc->right = prc->left + cx;
+ prc->bottom = prc->top + cy;
+}
+
+static void SkinnedWindow_OnEnterSizeMove(SKINNEDWND *pWnd)
+{
+ POINT pt;
+ RECT rw;
+ GetCursorPos(&pt);
+ GetWindowRect(pWnd->hwnd, &rw);
+ if (0xFFFF == pWnd->movingOffset.x)
+ pWnd->movingOffset.x = pt.x - rw.left;
+ if (0xFFFF == pWnd->movingOffset.y)
+ pWnd->movingOffset.y = pt.y - rw.top;
+}
+
+static void SkinnedWindow_OnExitSizeMove(SKINNEDWND *pWnd)
+{
+ pWnd->movingOffset.x = 0xFFFF;
+ pWnd->movingOffset.y = 0xFFFF;
+}
+
+static void SkinnedWindow_PatchCursor(SKINNEDWND *pWnd)
+{
+ RECT rc;
+ POINT ptOrig, pt;
+
+ if (!GetCursorPos(&ptOrig) ||
+ !GetWindowRect(pWnd->hwnd, &rc))
+ return;
+
+ pt.x = rc.right + 1;
+ pt.y = ptOrig.y;
+
+ ShowCursor(FALSE);
+ SetCursorPos(pt.x, pt.y);
+ ShowCursor(TRUE);
+ SetCursorPos(ptOrig.x, ptOrig.y);
+}
+
+static void SkinnedWindow_OnEnterMenuLoop(SKINNEDWND *pWnd, BOOL bTrackPopup)
+{
+ PostMessageW(pWnd->hwnd, WM_SETCURSOR, (WPARAM)pWnd->hwnd, MAKELPARAM(HTCLIENT,WM_ENTERMENULOOP));
+}
+
+static void SkinnedWindow_OnExitMenuLoop(SKINNEDWND *pWnd, BOOL bShortcut)
+{
+}
+
+static void SkinnedWindow_OnUnskin(SKINNEDWND *pWnd)
+{
+ if (NULL == pWnd) return;
+
+ HWND hwnd = pWnd->hwnd;
+
+ BOOL restoreVisible = FALSE;
+ DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ restoreVisible = TRUE;
+ SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+ }
+
+ if (NULL != pWnd->embedData.wasabi_window)
+ {
+ SENDWAIPC(IPC_CB_ONHIDEWND, pWnd->hwnd);
+ // start looping till we get callback
+
+ MSG msg;
+ BOOL stopLoop = FALSE;
+
+ while(FALSE == stopLoop)
+ {
+ DWORD status = MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+ if (WAIT_OBJECT_0 == status)
+ {
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (WAMSG_CLOSE == msg.message && msg.hwnd == pWnd->hwnd)
+ {
+ stopLoop = TRUE;
+ break;
+ }
+ else if (!CallMsgFilter(&msg, MSGF_DIALOGBOX))
+ {
+ if (msg.message == WM_QUIT)
+ {
+ PostQuitMessage((INT)msg.wParam);
+ stopLoop = TRUE;
+ break;
+ }
+ else
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ SkinnedWindow_Delete(pWnd);
+
+ if (FALSE != restoreVisible)
+ SetWindowLongPtrW(hwnd, GWL_STYLE, WS_VISIBLE | GetWindowLongPtrW(hwnd, GWL_STYLE));
+}
+
+static LRESULT SkinnedWindow_OnWinampIPC(SKINNEDWND *pWnd, UINT uCmd, WPARAM param)
+{
+ switch(uCmd)
+ {
+ case IPC_SKINWINDOW_SETEXSTYLE:
+ pWnd->flags = (SWS_EX_MASK & pWnd->flags) | (~SWS_EX_MASK & param);
+ return 0;
+
+ case IPC_SKINWINDOW_GETEXSTYLE:
+ return (~SWS_EX_MASK & pWnd->flags);
+
+ case IPC_SKINWINDOW_SETEMBEDFLAGS:
+ pWnd->embedData.flags = (INT)param;
+ return 0;
+
+ case IPC_SKINWINDOW_GETEMBEDFLAGS:
+ return pWnd->embedData.flags;
+
+ case IPC_SKINWINDOW_GETWASABIWND:
+ return (LRESULT)pWnd->embedData.wasabi_window;
+
+ case IPC_SKINWINDOW_UNSKIN:
+ SkinnedWindow_OnUnskin(pWnd);
+ break;
+
+ case IPC_SKINWINDOW_GETGUID:
+ if (NULL != param)
+ {
+ CopyMemory((void*)param, &pWnd->embedData.guid, sizeof(GUID));
+ return TRUE;
+ }
+ break;
+
+ case IPC_SKINWINDOW_GETEMBEDNUMS:
+ return Skin_UseGenNums;
+ }
+ return 0;
+}
+
+static void SkinnedWindow_OnSysCommand(SKINNEDWND *pWnd, UINT uCmd, LPARAM param)
+{
+ CallWndProc(pWnd, WM_SYSCOMMAND, (WPARAM)uCmd, param);
+
+ switch(uCmd)
+ {
+ case SC_MOVE:
+ case SC_SIZE:
+ case SC_DRAGMOVE:
+ case SC_DRAGSIZE_N:
+ case SC_DRAGSIZE_S:
+ case SC_DRAGSIZE_E:
+ case SC_DRAGSIZE_W:
+ case SC_DRAGSIZE_NW:
+ case SC_DRAGSIZE_NE:
+ case SC_DRAGSIZE_SW:
+ case SC_DRAGSIZE_SE:
+ SkinnedWindow_PatchCursor(pWnd);
+ break;
+ }
+}
+
+static LRESULT SkinnedWindow_OnSetText(SKINNEDWND *pWnd, LPCWSTR pszText)
+{
+ LRESULT result = CallWndProc(pWnd, WM_SETTEXT, 0, (LPARAM)pszText);
+ ifc_window *wnd = pWnd->embedData.wasabi_window;
+ if (NULL != wnd)
+ {
+ ifc_window *parent = wnd->getRootParent();
+ if (NULL == parent) parent = wnd;
+ parent->setWindowTitle(pszText);
+ }
+ else
+ {
+ SetWindowPos(pWnd->hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+ }
+ return result;
+}
+
+static LRESULT CALLBACK SkinnedWnd_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ SKINNEDWND *pWnd = GetSkinnedWnd(hwnd);
+ if (NULL == pWnd)
+ {
+ return ((IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
+ DefWindowProcA(hwnd, uMsg, wParam, lParam));
+ }
+
+ switch(uMsg)
+ {
+ case WM_DESTROY:
+ {
+ BOOL unicode = IsUnicode(pWnd);
+ WNDPROC wndProc = pWnd->fnWndProc;
+ SkinnedWindow_Delete(pWnd);
+ return ((unicode) ? CallWindowProcW(wndProc, hwnd, uMsg, wParam, lParam) :
+ CallWindowProcA(wndProc, hwnd, uMsg, wParam, lParam));
+ }
+ break;
+
+ case WAMSG_CLOSE: SkinnedWindow_OnWinampCustomClose(pWnd, MAKEPOINTS(lParam)); return 0;
+ case WM_NCHITTEST: return SkinnedWindow_OnNcHitTest(pWnd, MAKEPOINTS(lParam));
+ case WM_NCCALCSIZE: return SkinnedWindow_OnNcCalcSize(pWnd, (BOOL)wParam, (NCCALCSIZE_PARAMS*)lParam);
+ case WM_NCPAINT: SkinnedWindow_OnNcPaint(pWnd, (HRGN)wParam); return 0;
+ case WM_NCACTIVATE: return SkinnedWindow_OnNcActivate(pWnd, (BOOL)wParam);
+ case WM_ACTIVATE: SkinnedWindow_OnActivate(pWnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return 0;
+ case WM_PRINT: SkinnedWindow_OnPrint(pWnd, (HDC)wParam, (UINT)lParam); return 0;
+ case WM_SETCURSOR: return SkinnedWindow_OnSetCursor(pWnd, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
+ case WM_NCLBUTTONDOWN: if (SkinnedWindow_OnNcLButtonDown(pWnd, (INT)wParam, MAKEPOINTS(lParam))) return 0; break;
+ case WM_NCLBUTTONUP: if (SkinnedWindow_OnNcLButtonUp(pWnd, (INT)wParam, MAKEPOINTS(lParam))) return 0; break;
+ case WM_NCRBUTTONDOWN: if (SkinnedWindow_OnNcRButtonDown(pWnd, (INT)wParam, MAKEPOINTS(lParam))) return 0; break;
+ case WM_NCRBUTTONUP: if (SkinnedWindow_OnNcRButtonUp(pWnd, (INT)wParam, MAKEPOINTS(lParam))) return 0; break;
+ case WM_NCMOUSEMOVE: SkinnedWindow_OnNcMouseMove(pWnd, (INT)wParam, MAKEPOINTS(lParam)); break;
+ case WM_NCMOUSELEAVE: SkinnedWindow_OnNcMouseLeave(pWnd); break;
+ case WM_SHOWWINDOW: if (SkinnedWindow_OnShowWindow(pWnd, (BOOL)wParam, (UINT)lParam)) return 0; break;
+ case WM_WINDOWPOSCHANGING: SkinnedWindow_OnWindowPosChanging(pWnd, (WINDOWPOS*)lParam); return 0;
+ case WM_WINDOWPOSCHANGED: SkinnedWindow_OnWindowPosChanged(pWnd, (WINDOWPOS*)lParam); return 0;
+ case WM_ENTERSIZEMOVE: SkinnedWindow_OnEnterSizeMove(pWnd); break;
+ case WM_EXITSIZEMOVE: SkinnedWindow_OnExitSizeMove(pWnd); break;
+ case WM_MOVING: SkinnedWindow_OnMoving(pWnd, (RECT*)lParam); break;
+ case WM_SIZING: SkinnedWindow_OnSizing(pWnd, (UINT)wParam, (RECT*)lParam); break;
+ case WM_ENTERMENULOOP: SkinnedWindow_OnEnterMenuLoop(pWnd, (BOOL)wParam); break;
+ case WM_EXITMENULOOP: SkinnedWindow_OnExitMenuLoop(pWnd, (BOOL)wParam); break;
+ case WM_NCUAHDRAWCAPTION: return 0;
+ case WM_NCUAHDRAWFRAME: return 0;
+ case WM_WA_IPC: return SkinnedWindow_OnWinampIPC(pWnd, (UINT)lParam, wParam);
+ case WM_SYSCOMMAND: SkinnedWindow_OnSysCommand(pWnd, (UINT)wParam, lParam); return 0;
+ case WM_SETTEXT: return SkinnedWindow_OnSetText(pWnd, (LPCWSTR)lParam);
+ }
+
+ if (FALSE != IsDirectMouseWheelMessage(uMsg))
+ {
+ if (0 == (WS_CHILD & GetWindowStyle(hwnd)))
+ return TRUE;
+ else
+ {
+ HWND hParent;
+ hParent = GetAncestor(hwnd, GA_PARENT);
+ if (NULL != hParent)
+ return SendMessageW(hwnd, uMsg, wParam, lParam);
+
+ return FALSE;
+ }
+ }
+
+ return CallWndProc(pWnd, uMsg, wParam, lParam);
+} \ No newline at end of file
diff --git a/Src/Winamp/skinWindow.h b/Src/Winamp/skinWindow.h
new file mode 100644
index 00000000..bd3164c6
--- /dev/null
+++ b/Src/Winamp/skinWindow.h
@@ -0,0 +1,12 @@
+#ifndef NULLOSFT_WINAMP_SKINNEDWINDOW_HEADER
+#define NULLOSFT_WINAMP_SKINNEDWINDOW_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+BOOL SkinWindow(HWND hwndToSkin, REFGUID windowGuid, UINT flagsEx, FFCALLBACK callbackFF);
+
+#endif //NULLOSFT_WINAMP_SKINNEDWINDOW_HEADER \ No newline at end of file
diff --git a/Src/Winamp/skinWindowIPC.h b/Src/Winamp/skinWindowIPC.h
new file mode 100644
index 00000000..ff51b786
--- /dev/null
+++ b/Src/Winamp/skinWindowIPC.h
@@ -0,0 +1,23 @@
+#ifndef NULLOSFT_WINAMP_SKINNEDWINDOW_IPC_HEADER
+#define NULLOSFT_WINAMP_SKINNEDWINDOW_IPC_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#define SWS_EX_NOSNAP 0x00000001 // never snap
+
+// send next messages as WM_WA_IPC but directly to the skinnedWindow
+#define IPC_SKINWINDOW_SETEXSTYLE 1 // param - new flags
+#define IPC_SKINWINDOW_GETEXSTYLE 2 // param - not used
+#define IPC_SKINWINDOW_SETEMBEDFLAGS 3 // param - new flags
+#define IPC_SKINWINDOW_GETEMBEDFLAGS 4 // param - not used
+#define IPC_SKINWINDOW_GETWASABIWND 5 // param - not used; returns ifc_window if any
+#define IPC_SKINWINDOW_GETGUID 6 // param = (WPARAM)(GUID*)pguid; return TRUE on success
+#define IPC_SKINWINDOW_GETEMBEDNUMS 7 // param - not used
+
+#define IPC_SKINWINDOW_UNSKIN 10 // param - not used
+
+#endif // NULLOSFT_WINAMP_SKINNEDWINDOW_IPC_HEADER \ No newline at end of file
diff --git a/Src/Winamp/stats.cpp b/Src/Winamp/stats.cpp
new file mode 100644
index 00000000..ecf4be27
--- /dev/null
+++ b/Src/Winamp/stats.cpp
@@ -0,0 +1,185 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+** Filename:
+** Project:
+** Description:
+** Author:
+** Created:
+**/
+
+#include "main.h"
+#include "stats.h"
+#include "WinampAttributes.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+#include "api.h"
+#include <malloc.h>
+#include <rpc.h>
+
+/* benski> ideas for new stats
+bitmask of interesting config options (e.g. 24bit, replay gain)
+number of smart views
+number of tracks burned
+color theme
+
+other things:
+add generic key/value system to api_stats for strings (e.g. colortheme)
+*/
+
+Stats stats;
+
+Stats::Stats()
+{
+ memset(values, 0, sizeof(values));
+ values[LIBRARY_SIZE]=-1; // for historical reasons
+}
+
+void Stats::Init()
+{
+ char str[Stats::NUM_STATS*9+1] = {0}; // each stat is written as 8 digit hex and a comma (9 characters)
+ char *p=str;
+ GetPrivateProfileStringA("WinampReg","Stats","",str,sizeof(str),INI_FILEA);
+ for (int x = 0; x < NUM_STATS; x ++)
+ {
+ values[x]=strtol(p,&p,16);
+ if (*p) p++;
+ else break;
+ }
+}
+
+void Stats::SetStat(int stat, int value)
+{
+ if (stat >= 0 && stat < NUM_STATS)
+ values[stat] = value;
+}
+
+void Stats::IncrementStat(int stat)
+{
+ if (stat >= 0 && stat < NUM_STATS)
+ values[stat]++;
+}
+
+void Stats::Write()
+{
+ char str[Stats::NUM_STATS*9+1] = {0}; // each stat is written as 8 digit hex and a comma (9 characters)
+ char *str_ptr = str;
+ size_t str_size = sizeof(str)/sizeof(*str);
+ for (int x = 0; x < NUM_STATS; x ++)
+ {
+ StringCchPrintfExA(str_ptr, str_size, &str_ptr, &str_size, 0, "%08X,",values[x]);
+ }
+ WritePrivateProfileStringA("WinampReg","Stats",str,INI_FILEA);
+}
+
+void Stats::GetStats(int stats[NUM_STATS]) const
+{
+ memcpy(stats, values, sizeof(*stats)*NUM_STATS);
+}
+
+void Stats::SetString(const char *key, const wchar_t *value)
+{
+ WritePrivateProfileStringA("WinampReg",key,AutoChar(value, CP_UTF8),INI_FILEA);
+}
+
+void Stats::GetString(const char *key, wchar_t *value, size_t value_cch) const
+ {
+ *value = 0;
+ char *utf8 = (char *)alloca(value_cch);
+ if (utf8)
+ {
+ GetPrivateProfileStringA("WinampReg",key,"",utf8,(DWORD)value_cch,INI_FILEA);
+ MultiByteToWideCharSZ(CP_UTF8, 0, utf8, -1, value, (int)value_cch);
+ }
+ }
+
+// return a bitmask of interesting configuration choices
+/*static int stats_get_cfg()
+{
+ int s = 0;
+ s |= !!config_replaygain;
+ s |= (config_audio_bits == 24) << 1;
+ /* TODO:
+ agent on or off
+ EQ on
+ global hotkeys enabled
+ info panel on or off
+ remember search on or off
+ */
+/*}*/
+
+void stats_write(void)
+{
+ /* benski>
+ write skin and color theme (if available) on close
+ since we'll have a reliable way to get color themes (gen_ff hasn't loaded yet when versioncheck runs)
+ and it's a more accurate picture of the skin the user was using
+ */
+ const wchar_t *colorTheme = 0;
+ if (WASABI_API_COLORTHEMES)
+ colorTheme = WASABI_API_COLORTHEMES->getGammaSet();
+ stats.SetString("colortheme", colorTheme);
+ stats.SetString("skin", config_skin);
+
+ stats.IncrementStat(Stats::LAUNCHES);
+ stats.SetStat(Stats::REGVER, 2);
+ stats.SetStat(Stats::PLEDIT_LENGTH, PlayList_getlength());
+ stats.Write();
+}
+
+void stats_save()
+{
+ stats.Write();
+}
+
+void stats_getuidstr(char str[512])
+{
+ GUID uid;
+ GetPrivateProfileStringA("WinampReg","ID","",str,128,INI_FILEA);
+
+ if (strlen(str) > sizeof(GUID)*2) // reset bad ID's which were being generated for some time (fixed in 5.5)
+ str[0]=0;
+
+ if (!str[0])
+ {
+ int x;
+ unsigned char *p;
+
+ size_t strsize = 512;
+ char *strbuf = str;
+
+ CoCreateGuid(&uid);
+ p=(unsigned char *)&uid;
+ str[0]=0;
+ for (x = 0; x < sizeof(uid); x ++)
+ {
+ StringCchPrintfExA(strbuf, strsize, &strbuf, &strsize, 0, "%02X", p[x]);
+ }
+ WritePrivateProfileStringA("WinampReg","ID",str,INI_FILEA);
+ }
+}
+
+void Stats_OnPlay(const wchar_t *playstring)
+{
+ if (!_wcsnicmp(playstring, L"http://", 7)
+ || !_wcsnicmp(playstring, L"sc://", 5)
+ || !_wcsnicmp(playstring, L"mms://", 6)
+ || !_wcsnicmp(playstring, L"icy://", 6))
+ stats.IncrementStat(Stats::STREAMS_PLAYED);
+ else if (!_wcsnicmp(playstring, L"cda://", 6) ||
+ !_wcsicmp(extensionW(playstring), L"cda"))
+ stats.IncrementStat(Stats::CDS_PLAYED);
+ else
+ stats.IncrementStat(Stats::FILES_PLAYED);
+}
+
+void stats_init()
+{
+ stats.Init();
+}
+
+#define CBCLASS Stats
+START_DISPATCH;
+VCB(SETSTAT, SetStat);
+VCB(INCREMENTSTAT, IncrementStat);
+VCB(SETSTRING, SetString);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/stats.h b/Src/Winamp/stats.h
new file mode 100644
index 00000000..66d45fea
--- /dev/null
+++ b/Src/Winamp/stats.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "api_stats.h"
+#include <api/service/services.h>
+
+class Stats : public api_stats
+{
+public:
+ static const char *getServiceName() { return "Anonymous Statistics API"; }
+ static const GUID getServiceGuid() { return AnonymousStatsGUID; }
+ static FOURCC getServiceType() { return WaSvc::UNIQUE; }
+public:
+ Stats();
+ void Init();
+ void Write();
+
+ /* API implementation */
+ void SetStat(int stat, int value);
+ void IncrementStat(int stat);
+ void GetStats(int stats[NUM_STATS]) const;
+ void SetString(const char *key, const wchar_t *value);
+ void GetString(const char *key, wchar_t *value, size_t value_cch) const;
+
+private:
+ int values[NUM_STATS];
+protected:
+ RECVS_DISPATCH;
+};
+
+extern Stats stats; \ No newline at end of file
diff --git a/Src/Winamp/strutil.cpp b/Src/Winamp/strutil.cpp
new file mode 100644
index 00000000..abd349ac
--- /dev/null
+++ b/Src/Winamp/strutil.cpp
@@ -0,0 +1,486 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+#include <windows.h>
+#include <Shlwapi.h>
+#include "strutil.h"
+
+char *SkipX(char *str, int count)
+{
+ while (count--)
+ {
+ str = CharNextA(str);
+ }
+
+ return str;
+}
+
+wchar_t *SkipXW(wchar_t *str, int count)
+{
+ while (count--)
+ {
+ str = CharNextW(str);
+ }
+
+ return str;
+}
+
+void CopyChar(char *dest, const char *src)
+{
+ char *end = CharNextA(src);
+ ptrdiff_t count = end-src;
+ while (count--)
+ {
+ *dest++=*src++;
+ }
+}
+
+ptrdiff_t CopyCharW(wchar_t *dest, const wchar_t *src)
+{
+ wchar_t *end = CharNextW(src);
+ ptrdiff_t count = end-src;
+ for (ptrdiff_t i=0;i<count;i++)
+ {
+ *dest++=*src++;
+ }
+ return count;
+}
+
+void MakeRelativePathName(const wchar_t *filename, wchar_t *outFile, const wchar_t *path)
+{
+ wchar_t outPath[MAX_PATH] = {0};
+
+ int common = PathCommonPrefixW(path, filename, outPath);
+ if (common && common == lstrlenW(path))
+ {
+ PathAddBackslashW(outPath);
+ const wchar_t *p = filename + lstrlenW(outPath);
+ lstrcpynW(outFile, p, FILENAME_SIZE);
+ }
+ else if (!PathIsUNCW(filename) && PathIsSameRootW(filename, path))
+ {
+ lstrcpynW(outFile, filename+2, FILENAME_SIZE);
+ }
+}
+
+static int CharacterCompareW(const wchar_t *ch1, const wchar_t *ch2)
+{
+ wchar_t str1[3]={0,0,0}, str2[3]={0,0,0};
+
+ CopyCharW(str1, ch1);
+ CharUpperW(str1);
+
+ CopyCharW(str2, ch2);
+ CharUpperW(str2);
+
+ return memcmp(str1, str2, 3*sizeof(wchar_t));
+}
+
+static void IncHelperW(LPCWSTR *src, ptrdiff_t *size)
+{
+ wchar_t *end = CharNextW(*src);
+ ptrdiff_t count = end-*src;
+ *size-=count;
+ *src=end;
+}
+
+int IsCharDigit(char digit)
+{
+ WORD type=0;
+ GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return type&C1_DIGIT;
+}
+
+int IsCharDigitW(wchar_t digit)
+{
+ WORD type=0;
+ GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return type&C1_DIGIT;
+}
+
+int FileCompareLogical(const wchar_t *str1, const wchar_t *str2)
+{
+ if (str1 && str2)
+ {
+ while (str1 && *str1)
+ {
+ if (!*str2)
+ return 1;
+ else if (IsCharDigitW(*str1))
+ {
+ int iStr, iComp;
+
+ if (!IsCharDigitW(*str2))
+ return -1;
+
+ /* Compare the numbers */
+ StrToIntExW(str1, 0, &iStr);
+ StrToIntExW(str2, 0, &iComp);
+
+ if (iStr < iComp)
+ return -1;
+ else if (iStr > iComp)
+ return 1;
+
+ /* Skip */
+ while (IsCharDigitW(*str1))
+ str1=CharNextW(str1);
+ while (IsCharDigitW(*str2))
+ str2=CharNextW(str2);
+ }
+ else if (IsCharDigitW(*str2))
+ return 1;
+ else
+ {
+ int diff = CharacterCompareW(str1, str2);
+ if (diff > 0)
+ return 1;
+ else if (diff < 0)
+ return -1;
+
+ str1=CharNextW(str1);
+ str2=CharNextW(str2);
+ }
+ }
+ if (*str2)
+ return -1;
+ }
+ return 0;
+}
+
+static int StringLengthNoDigits(LPCWSTR str, LPCWSTR *end)
+{
+ ptrdiff_t length=0;
+ while (str && *str && !IsCharDigitW(*str))
+ {
+ IncHelperW(&str, &length);
+ }
+ if (end) *end = str;
+ return (int)(-length); // IncHelper decrements so we need to negate
+}
+
+int CompareStringLogical(LPCWSTR str1, LPCWSTR str2)
+{
+ if (str1 && str2)
+ {
+ while (str1 && *str1)
+ {
+ if (!*str2)
+ return 1;
+ else if (IsCharDigitW(*str1))
+ {
+ int iStr, iComp;
+
+ if (!IsCharDigitW(*str2))
+ return -1;
+
+ /* Compare the numbers */
+ StrToIntExW(str1, 0, &iStr);
+ StrToIntExW(str2, 0, &iComp);
+
+ if (iStr < iComp)
+ return -1;
+ else if (iStr > iComp)
+ return 1;
+
+ /* Skip */
+ while (IsCharDigitW(*str1))
+ str1=CharNextW(str1);
+ while (IsCharDigitW(*str2))
+ str2=CharNextW(str2);
+ }
+ else if (IsCharDigitW(*str2))
+ return 1;
+ else
+ {
+ LPCWSTR next1, next2;
+ int len1 = StringLengthNoDigits(str1, &next1);
+ int len2 = StringLengthNoDigits(str2, &next2);
+
+ int comp = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE|NORM_IGNOREWIDTH, str1, len1, str2, len2);
+ if (comp == CSTR_LESS_THAN)
+ return -1;
+ else if (comp == CSTR_GREATER_THAN)
+ return 1;
+
+ str1 = next1;
+ str2 = next2;
+ }
+ }
+ if (*str2)
+ return -1;
+ }
+ return 0;
+}
+
+int FileCompareLogicalN(LPCWSTR str1, ptrdiff_t str1size, LPCWSTR str2, ptrdiff_t str2size)
+{
+ if (str1 && str2)
+ {
+ while (str1 && *str1 && str1size)
+ {
+ if (!*str2 || !str2size)
+ return 1;
+ else if (IsCharDigitW(*str1))
+ {
+ int iStr, iComp;
+
+ if (!IsCharDigitW(*str2))
+ return -1;
+
+ /* Compare the numbers */
+ StrToIntExW(str1, 0, &iStr);
+ StrToIntExW(str2, 0, &iComp);
+
+ if (iStr < iComp)
+ return -1;
+ else if (iStr > iComp)
+ return 1;
+
+ /* Skip */
+ while (IsCharDigitW(*str1))
+ IncHelperW(&str1, &str1size);
+ while (IsCharDigitW(*str2))
+ IncHelperW(&str2, &str2size);
+ }
+ else if (IsCharDigitW(*str2))
+ return 1;
+ else
+ {
+ int diff = CharacterCompareW(str1, str2);
+ if (diff > 0)
+ return 1;
+ else if (diff < 0)
+ return -1;
+
+ IncHelperW(&str1, &str1size);
+ IncHelperW(&str2, &str2size);
+ }
+ }
+
+ if (!str1size && !str2size)
+ return 0;
+ if (*str2 || str2size < str1size)
+ return -1;
+ if (*str1 || str1size < str2size)
+ return 1;
+ }
+ return 0;
+}
+
+char *GetLastCharacter(char *string)
+{
+ if (!string || !*string)
+ return string;
+
+ return CharPrevA(string, string+lstrlenA(string));
+}
+
+wchar_t *GetLastCharacterW(wchar_t *string)
+{
+ if (!string || !*string)
+ return string;
+
+ return CharPrevW(string, string+lstrlenW(string));
+}
+
+const char *GetLastCharacterc(const char *string)
+{
+ if (!string || !*string)
+ return string;
+
+ for (;;)
+ {
+ const char *next = CharNextA(string);
+ if (!*next)
+ return string;
+ string = next;
+ }
+}
+
+const wchar_t *GetLastCharactercW(const wchar_t *string)
+{
+ if (!string || !*string)
+ return string;
+
+ return CharPrevW(string, string+lstrlenW(string));
+}
+
+wchar_t *scanstr_backW(wchar_t *str, wchar_t *toscan, wchar_t *defval)
+{
+ wchar_t *s = GetLastCharacterW(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ wchar_t *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextW(t);
+ }
+ t = CharPrevW(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+const wchar_t *scanstr_backcW(const wchar_t *str, const wchar_t *toscan, const wchar_t *defval)
+{
+ const wchar_t *s = GetLastCharactercW(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ const wchar_t *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextW(t);
+ }
+ t = CharPrevW(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+char *scanstr_back(char *str, char *toscan, char *defval)
+{
+ char *s = GetLastCharacter(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ char *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextA(t);
+ }
+ t = CharPrevA(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+const char *scanstr_backc(const char *str, const char *toscan, const char *defval)
+{
+ const char *s = GetLastCharacterc(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ const char *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextA(t);
+ }
+ t = CharPrevA(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+char *extension(const char *fn)
+{
+ // TODO: deal with making sure that URLs don't return .com, etc.
+ // e.g. http://www.winamp.com should return nothing
+ char *end = scanstr_back((char*)fn, "./\\", 0);
+ if (!end)
+ return (char*)(fn+lstrlenA(fn));
+
+ if (*end == '.')
+ return CharNextA(end);
+
+ return (char*)(fn+lstrlenA(fn));
+}
+
+wchar_t *extensionW(const wchar_t *fn)
+{
+ // TODO: deal with making sure that URLs don't return .com, etc.
+ // e.g. http://www.winamp.com should return nothing
+ wchar_t *end = scanstr_backW((wchar_t*)fn, L"./\\", 0);
+ if (!end)
+ return (wchar_t *)(fn+lstrlenW(fn));
+
+ if (*end == L'.')
+ return CharNextW(end);
+
+ return (wchar_t*)(fn+lstrlenW(fn));
+}
+
+const char *extensionc(const char *fn)
+{
+ return extension(fn);
+}
+
+const wchar_t *extensioncW(const wchar_t *fn)
+{
+ return extensionW(fn);
+}
+
+void extension_ex(const char *fn, char *buf, int buflen)
+{
+ const char *s = extensionc(fn);
+ if (!PathIsURLA(fn)
+ || (!strstr(s, "?") && !strstr(s, "&") && !strstr(s, "=") && *s))
+ {
+ lstrcpynA(buf, s, buflen);
+ return ;
+ }
+ // s is not a terribly good extension, let's try again
+ {
+ char *copy = _strdup(fn);
+ s = "";
+ again:
+ {
+ char *p = scanstr_back(copy, "?", copy);
+ if (p != copy)
+ {
+ *p = 0;
+ s = extension(copy);
+ if (!*s) goto again;
+ }
+ lstrcpynA(buf, s, buflen);
+ }
+ free(copy);
+ }
+}
+
+void extension_exW(const wchar_t *fn, wchar_t *buf, int buflen)
+{
+ const wchar_t *s = extensioncW(fn);
+ if (!PathIsURLW(fn)
+ || (!wcsstr(s, L"?") && !wcsstr(s, L"&") && !wcsstr(s, L"=") && *s))
+ {
+ lstrcpynW(buf, s, buflen);
+ return ;
+ }
+ // s is not a terribly good extension, let's try again
+ {
+ wchar_t *copy = _wcsdup(fn);
+ s = L"";
+ again:
+ {
+ wchar_t *p = scanstr_backW(copy, L"?", copy);
+ if (p != copy)
+ {
+ *p = 0;
+ s = extensionW(copy);
+ if (!*s) goto again;
+ }
+ lstrcpynW(buf, s, buflen);
+ }
+ free(copy);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/strutil.h b/Src/Winamp/strutil.h
new file mode 100644
index 00000000..a1dbdfac
--- /dev/null
+++ b/Src/Winamp/strutil.h
@@ -0,0 +1,51 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+#ifndef NULLSOFT_STRUTILH
+#define NULLSOFT_STRUTILH
+
+#ifndef FILENAME_SIZE
+#define FILENAME_SIZE (MAX_PATH * 4)
+#endif
+
+#ifndef FILETITLE_SIZE
+#define FILETITLE_SIZE 400
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+char *SkipX(char *str, int count);
+wchar_t *SkipXW(wchar_t *str, int count);
+void CopyChar(char *dest, const char *src);
+ptrdiff_t CopyCharW(wchar_t *dest, const wchar_t *src); // returns number of character copied
+void MakeRelativePathName(const wchar_t *filename, wchar_t *outFile, const wchar_t *path);
+int FileCompareLogicalN(const wchar_t *str1, ptrdiff_t str1size, const wchar_t *str2, ptrdiff_t str2size);
+int FileCompareLogical(const wchar_t *str1, const wchar_t *str2);
+int CompareStringLogical(const wchar_t * str1, const wchar_t * str2);
+char *GetLastCharacter(char *string);
+wchar_t *GetLastCharacterW(wchar_t *string);
+const char *GetLastCharacterc(const char *string);
+const wchar_t *GetLastCharactercW(const wchar_t *string);
+
+wchar_t *scanstr_backW(wchar_t *str, wchar_t *toscan, wchar_t *defval);
+const wchar_t *scanstr_backcW(const wchar_t *str, const wchar_t *toscan, const wchar_t *defval);
+char *scanstr_back(char *str, char *toscan, char *defval);
+char *scanstr_backc(const char *str, char *toscan, char *defval);
+
+char *extension(const char *fn);
+wchar_t *extensionW(const wchar_t *fn);
+const char *extensionc(const char *fn);
+void extension_ex(const char *fn, char *buf, int buflen);
+void extension_exW(const wchar_t *fn, wchar_t *buf, int buflen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/tagz.cpp b/Src/Winamp/tagz.cpp
new file mode 100644
index 00000000..6076f8c1
--- /dev/null
+++ b/Src/Winamp/tagz.cpp
@@ -0,0 +1,343 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "tagz.h"
+#include "../tagz/ifc_tagprovider.h"
+#include "../tagz/ifc_tagparams.h"
+#include "api.h"
+#include "TagProvider.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/ns_wc.h"
+extern "C"
+{
+ typedef char * (*GetTagFunc)(const char * tag, void * p);
+ typedef void (*FreeTagFunc)(char * tag,void * p);
+ typedef wchar_t * (*GetTagFuncW)(const wchar_t * tag, void * p);
+ typedef void (*FreeTagFuncW)(wchar_t * tag,void * p);
+}
+
+class TagParameters : public ifc_tagparams
+{
+public:
+ TagParameters(const wchar_t *_filename) :filename(_filename){}
+ void *GetParameter(const GUID *parameterID)
+ {
+ if (*parameterID == filenameParameterID)
+ return (void *)filename;
+ return 0;
+ }
+protected:
+ RECVS_DISPATCH;
+private:
+ const wchar_t *filename;
+};
+
+class ExternalTagProvider : public ifc_tagprovider
+{
+public:
+ ExternalTagProvider(GetTagFunc getter, FreeTagFunc freer, void *context);
+ wchar_t *GetTag(const wchar_t *name, ifc_tagparams *parameters);
+ void FreeTag(wchar_t *Tag);
+protected:
+ RECVS_DISPATCH;
+private:
+ GetTagFunc externalGetTag;
+ FreeTagFunc externalFreeTag;
+ void *externalContext;
+};
+
+class ExtendedTagProvider : public ifc_tagprovider
+{
+public:
+ ExtendedTagProvider(const wchar_t *_filename, GetTagFuncW getter, FreeTagFuncW freer, void *context, bool _useExtendedInfo);
+ wchar_t *GetTag(const wchar_t *name, ifc_tagparams *parameters);
+ void FreeTag(char *Tag);
+protected:
+ RECVS_DISPATCH;
+private:
+ GetTagFuncW externalGetTag;
+ FreeTagFuncW externalFreeTag;
+ void *externalContext;
+ const wchar_t *filename;
+ bool useExtendedInfo;
+};
+
+static void CleanupTitle(char *title)
+{
+ while (title && *title)
+ {
+ if (*title == '\n' || *title == '\r')
+ *title = ' ';
+ title = CharNextA(title);
+ }
+}
+
+static void CleanupTitleW(wchar_t *title)
+{
+ while (title && *title)
+ {
+ if (*title == L'\n' || *title == L'\r')
+ *title = L' ';
+ title = CharNextW(title);
+ }
+}
+
+void FormatTitle(waFormatTitle *format)
+{
+ AutoWide wideSpec(format->spec);
+ wchar_t *spec = (format->spec ? wideSpec : config_titlefmt);
+
+ if (format->out && format->out_len)
+ {
+ memset(format->out, 0, format->out_len);
+ if (WINAMP5_API_TAGZ)
+ {
+ if (format->TAGFUNC)
+ {
+ ExternalTagProvider provider(format->TAGFUNC, format->TAGFREEFUNC, format->p);
+ wchar_t *tempOut = (wchar_t *)calloc(format->out_len, sizeof(wchar_t));
+ if (tempOut)
+ {
+ WINAMP5_API_TAGZ->format(spec, tempOut, format->out_len, &provider, 0 /*&parameters*/);
+ WideCharToMultiByteSZ(CP_ACP, 0, tempOut, -1, format->out, format->out_len, 0, 0);
+ free(tempOut);
+ }
+ }
+ else
+ {
+ AutoWide wideFn((char *)format->p); // we'd better hope it's the filename!
+ TagParameters parameters(wideFn);
+ wchar_t *tempOut = (wchar_t *)calloc(format->out_len, sizeof(wchar_t));
+ if (tempOut)
+ {
+ WINAMP5_API_TAGZ->format(spec, tempOut, format->out_len, tagProvider, &parameters);
+ WideCharToMultiByteSZ(CP_ACP, 0, tempOut, -1, format->out, format->out_len, 0, 0);
+ free(tempOut);
+ }
+ }
+ CleanupTitle(format->out);
+ }
+ }
+}
+
+void FormatTitleExtended(waFormatTitleExtended *format)
+{
+ if (!format->filename || format->filename && !*format->filename) return;
+
+ const wchar_t *spec = (format->spec ? format->spec : config_titlefmt);
+ if (format->out && format->out_len)
+ {
+ if (WINAMP5_API_TAGZ)
+ {
+ ExtendedTagProvider provider(format->filename, format->TAGFUNC, format->TAGFREEFUNC, format->p, !!format->useExtendedInfo);
+ WINAMP5_API_TAGZ->format(spec, format->out, format->out_len, &provider, 0 /*&parameters*/);
+ CleanupTitleW(format->out);
+ }
+ else
+ {
+ lstrcpynW(format->out, format->filename, format->out_len);
+ PathStripPathW(format->out);
+ }
+ }
+}
+
+int FormatTitle(waHookTitleStructW *hts)
+{
+ if (hts && hts->title &&
+ ((hts->force_useformatting&1) || !(PathIsURLW(hts->filename) && StrCmpNIW(hts->filename, L"cda://", 6))))
+ {
+ wchar_t buf[32] = {0};
+ wchar_t buf2[32] = {0};
+ hts->length = -1;
+ hts->title[0] = 0;
+ if (in_get_extended_fileinfoW(hts->filename, L"length", buf, 32) ||
+ in_get_extended_fileinfoW(hts->filename, L"type", buf2, 32))
+ {
+ hts->length = StrToIntW(buf);
+ if (hts->length <= 0)
+ hts->length = -1;
+ else
+ hts->length /= 1000;
+ if (WINAMP5_API_TAGZ)
+ {
+ TagParameters parameters(hts->filename);
+
+ WINAMP5_API_TAGZ->format(config_titlefmt, hts->title, 2048, tagProvider, &parameters);
+ }
+ CleanupTitleW(hts->title);
+ if (hts->title[0]) return 1;
+ }
+ }
+ return 0;
+}
+
+namespace Winamp
+{
+ /* our tag getting functions */
+ wchar_t *GetTag(const wchar_t *tag, const wchar_t *filename) // for simple tags
+ {
+ if (!_wcsicmp(tag, L"filename"))
+ return _wcsdup(filename);
+
+ else if (!_wcsicmp(tag, L"folder"))
+ {
+ wchar_t *folder = (wchar_t *)calloc(MAX_PATH, sizeof(wchar_t));
+ if (folder)
+ {
+ lstrcpynW(folder, filename, MAX_PATH);
+ PathRemoveFileSpecW(folder);
+ PathRemoveBackslashW(folder);
+ PathStripPathW(folder);
+ return folder;
+ }
+ }
+
+ return 0;
+ }
+
+ wchar_t *GetExtendedTag(const wchar_t *tag, const wchar_t *filename) //return 0 if not found
+ {
+ wchar_t buf[1024] = {0};
+
+ if (!_wcsicmp(tag, L"tracknumber"))
+ tag = L"track";
+
+#if 0
+ if (in_get_extended_fileinfo(filename, tag, buf, sizeof(buf)) && buf[0])
+ return _strdup(buf);
+#else
+ extendedFileInfoStructW s = {filename, tag, buf, 1024};
+ if (SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE) && buf[0])
+ return _wcsdup(buf);
+#endif
+ return 0;
+ }
+} // namespace Winamp
+
+/* --- ExternalTagProvider ---
+
+maybe we'll move this to a separate file once it's done
+*/
+ExternalTagProvider::ExternalTagProvider(GetTagFunc getter, FreeTagFunc freer, void *context)
+: externalGetTag(getter), externalFreeTag(freer), externalContext(context)
+{
+}
+
+wchar_t *ExternalTagProvider::GetTag(const wchar_t *name, ifc_tagparams *parameters)
+{
+ if (externalGetTag)
+ {
+ char *tag = externalGetTag(AutoChar(name), externalContext);
+ if (tag == reinterpret_cast<char *>(-1))
+ return 0;
+
+ int size = MultiByteToWideChar(CP_ACP, 0, tag, -1, 0, 0);
+ if (!size)
+ {
+ if (externalFreeTag)
+ externalFreeTag(tag, externalContext);
+ return 0;
+ }
+
+ wchar_t *wide = (wchar_t *)calloc(size, sizeof(wchar_t));
+ if (!MultiByteToWideChar(CP_ACP, 0, tag, -1, wide, size))
+ {
+ if (wide) free(wide);
+ if (externalFreeTag)
+ externalFreeTag(tag, externalContext);
+ return 0;
+ }
+
+ if (externalFreeTag)
+ externalFreeTag(tag, externalContext);
+ return wide;
+ }
+
+ return 0;
+}
+
+void ExternalTagProvider::FreeTag(wchar_t *tag)
+{
+ if (tag) free(tag);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS ExternalTagProvider
+START_DISPATCH;
+CB(IFC_TAGPROVIDER_GET_TAG, GetTag);
+VCB(IFC_TAGPROVIDER_FREE_TAG, FreeTag);
+END_DISPATCH;
+#undef CBCLASS
+
+
+/* --- ExtendedTagProvider ---
+
+maybe we'll move this to a separate file once it's done
+*/
+ExtendedTagProvider::ExtendedTagProvider(const wchar_t *_filename, GetTagFuncW getter, FreeTagFuncW freer, void *context, bool _useExtendedInfo)
+: externalGetTag(getter), externalFreeTag(freer), externalContext(context), filename(_filename), useExtendedInfo(_useExtendedInfo)
+{
+}
+
+wchar_t *ExtendedTagProvider::GetTag(const wchar_t *name, ifc_tagparams *parameters)
+{
+ wchar_t *tag=0;
+ if (externalGetTag)
+ tag=externalGetTag(name, externalContext);
+
+ if (tag) // if we got a tag, we'll need to make a copy, because we won't be able to tell where it came from when it's time to free it
+ {
+ if (tag == reinterpret_cast<wchar_t *>(-1))
+ return 0;
+ wchar_t *temp = *tag?_wcsdup(tag):0;
+ if (externalFreeTag)
+ externalFreeTag(tag, externalContext);
+ return temp;
+ }
+ else
+ {
+ tag = Winamp::GetTag(name, filename);
+ if (tag == reinterpret_cast<wchar_t *>(-1))
+ return 0;
+ if (!tag && useExtendedInfo)
+ tag = Winamp::GetExtendedTag(name, filename);
+ if (tag == reinterpret_cast<wchar_t *>(-1))
+ return 0;
+ return tag;
+ }
+}
+
+void ExtendedTagProvider::FreeTag(char *tag)
+{
+ if (tag) free(tag);
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS ExtendedTagProvider
+START_DISPATCH;
+CB(IFC_TAGPROVIDER_GET_TAG, GetTag);
+VCB(IFC_TAGPROVIDER_FREE_TAG, FreeTag);
+END_DISPATCH;
+#undef CBCLASS
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS TagParameters
+START_DISPATCH;
+CB(IFC_TAGPARAMS_GETPARAMETER, GetParameter);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/tagz.h b/Src/Winamp/tagz.h
new file mode 100644
index 00000000..08c7a5a5
--- /dev/null
+++ b/Src/Winamp/tagz.h
@@ -0,0 +1,15 @@
+#ifndef NULLSOFT_WINAMP_TAGZ_H
+#define NULLSOFT_WINAMP_TAGZ_H
+
+#include "wa_ipc.h"
+void FormatTitle(waFormatTitle *format);
+void FormatTitleExtended(waFormatTitleExtended *format);
+int FormatTitle(waHookTitleStructW *hts);
+
+namespace Winamp
+{
+ wchar_t *GetTag(const wchar_t *tag, const wchar_t *filename); // for simple tags
+ wchar_t *GetExtendedTag(const wchar_t *tag, const wchar_t *filename); //return 0 if not found
+}
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/updateService.cpp b/Src/Winamp/updateService.cpp
new file mode 100644
index 00000000..43c34157
--- /dev/null
+++ b/Src/Winamp/updateService.cpp
@@ -0,0 +1,232 @@
+#include "main.h"
+#include "./updateService.h"
+#include "./api.h"
+#include "./externalCOM.h"
+
+#include "../omBrowser/obj_ombrowser.h"
+#include "../omBrowser/ifc_omservice.h"
+#include "../omBrowser/browserPopup.h"
+#include "../omBrowser/ifc_omdebugconfig.h"
+
+HRESULT ServiceSubclass_Attach(HWND hwnd, UpdateService *service);
+
+UpdateService::UpdateService(obj_ombrowser *browserObject, LPWSTR pszUrl)
+: ref(1), url(pszUrl), browserManager(browserObject)
+{
+ if (NULL != browserManager)
+ browserManager->AddRef();
+}
+
+UpdateService::~UpdateService()
+{
+ Finish();
+}
+
+HRESULT UpdateService::CreateInstance(LPCSTR pszUrl, UpdateService **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = NULL;
+
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(OBJ_OmBrowser);
+ if (NULL == sf) return E_FAIL;
+
+ obj_ombrowser *browserManager = reinterpret_cast<obj_ombrowser*>(sf->getInterface());
+ sf->Release();
+
+ if (NULL == browserManager)
+ return E_NOINTERFACE;
+
+ HRESULT hr = browserManager->Initialize(NULL, hMainWindow);
+ if (SUCCEEDED(hr))
+ {
+ LPWSTR url = NULL;
+ if (NULL != pszUrl)
+ {
+ UINT cchUrlMax = MultiByteToWideChar(CP_UTF8, 0, pszUrl, -1, NULL, 0);
+ if (0 != cchUrlMax)
+ {
+ cchUrlMax++;
+ url = (LPWSTR)calloc(cchUrlMax, sizeof(WCHAR));
+ if (NULL == url) hr = E_OUTOFMEMORY;
+ else
+ {
+ if (0 == MultiByteToWideChar(CP_UTF8, 0, pszUrl, -1, url, cchUrlMax))
+ hr = E_FAIL;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *instance = new UpdateService(browserManager, url);
+ if (NULL == *instance)
+ {
+ if (NULL != url) free(url);
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ }
+
+ browserManager->Release();
+ return hr;
+}
+
+size_t UpdateService::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t UpdateService::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int UpdateService::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmService))
+ *object = static_cast<ifc_omservice*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+unsigned int UpdateService::GetId()
+{
+ return 505;
+}
+
+HRESULT UpdateService::GetName(wchar_t *pszBuffer, int cchBufferMax)
+{
+ getStringW(IDS_WINAMP_UPDATE, pszBuffer, cchBufferMax);
+ return S_OK;
+}
+
+HRESULT UpdateService::GetUrl(wchar_t *pszBuffer, int cchBufferMax)
+{
+
+ return StringCchCopyExW(pszBuffer, cchBufferMax, url, NULL, NULL, STRSAFE_IGNORE_NULLS );
+}
+
+HRESULT UpdateService::GetIcon(wchar_t *pszBuffer, int cchBufferMax)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT UpdateService::GetExternal(IDispatch **ppDispatch)
+{
+ if (NULL == ppDispatch)
+ return E_POINTER;
+
+ ExternalCOM *external;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (FAILED(hr)) external = NULL;
+
+ *ppDispatch = (IDispatch*)external;
+ return S_OK;
+}
+
+HRESULT UpdateService::Show()
+{
+ if (NULL == browserManager)
+ return E_UNEXPECTED;
+
+ LONG cx = 300;
+ LONG cy = 200;
+
+ RECT centerRect;
+ HWND hCenter = (NULL != g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow;
+
+ if (NULL == hCenter ||
+ 0 == GetWindowRect(hCenter, &centerRect) ||
+ ((centerRect.right - centerRect.left) < cx) ||
+ ((centerRect.bottom - centerRect.top) < cy))
+ {
+ HMONITOR hMonitor = MonitorFromWindow(hCenter, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO info;
+ info.cbSize = sizeof(info);
+
+ if (NULL != hMonitor && 0 != GetMonitorInfo(hMonitor, &info))
+ CopyRect(&centerRect, &info.rcWork);
+ else
+ SetRectEmpty(&centerRect);
+
+ }
+
+ LONG x = centerRect.left + (centerRect.right - centerRect.left - cx)/2;
+ LONG y = centerRect.top + (centerRect.bottom - centerRect.top - cy)/2;
+ if (x < centerRect.left) x = centerRect.left;
+ if (y < centerRect.top) y = centerRect.top;
+
+ UINT popupFlags = NBCS_NOTOOLBAR | NBCS_NOSTATUSBAR | NBCS_DIALOGMODE | NBCS_BLOCKPOPUP;
+
+ ifc_omdebugconfig *debugConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmDebugConfig, (void**)&debugConfig)))
+ {
+ if (S_OK == debugConfig->GetMenuFilterEnabled())
+ popupFlags |= NBCS_DISABLECONTEXTMENU;
+ debugConfig->Release();
+ }
+
+ HWND hPopup;
+ HRESULT hr = browserManager->CreatePopup(this, x, y, cx, cy, hMainWindow, NULL, popupFlags, &hPopup);
+ if (SUCCEEDED(hr))
+ {
+ if (FAILED(ServiceSubclass_Attach(hPopup, this)))
+ {
+ ShowWindowAsync(hPopup, SW_SHOWNORMAL);
+ }
+ }
+
+ return hr;
+}
+
+HRESULT UpdateService::Finish()
+{
+ if (NULL != browserManager)
+ {
+ browserManager->Finish();
+ browserManager->Release();
+ browserManager = NULL;
+ }
+
+ if (NULL != url)
+ {
+ free(url);
+ url = NULL;
+ }
+
+ return S_OK;
+}
+
+#define CBCLASS UpdateService
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETID, GetId)
+CB(API_GETNAME, GetName)
+CB(API_GETURL, GetUrl)
+CB(API_GETICON, GetIcon)
+CB(API_GETEXTERNAL, GetExternal)
+END_DISPATCH;
+#undef CBCLASS
+
diff --git a/Src/Winamp/updateService.h b/Src/Winamp/updateService.h
new file mode 100644
index 00000000..8ad62774
--- /dev/null
+++ b/Src/Winamp/updateService.h
@@ -0,0 +1,48 @@
+#ifndef NULLSOFT_WINAMP_UPDATE_SERVICE_HEADER
+#define NULLSOFT_WINAMP_UPDATE_SERVICE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "../omBrowser/ifc_omservice.h"
+
+class obj_ombrowser;
+
+class UpdateService : public ifc_omservice
+{
+protected:
+ UpdateService(obj_ombrowser *browserObject, LPWSTR pszUrl);
+ ~UpdateService();
+
+public:
+ static HRESULT CreateInstance(LPCSTR pszUrl, UpdateService **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omservice */
+ unsigned int GetId();
+ HRESULT GetName(wchar_t *pszBuffer, int cchBufferMax);
+ HRESULT GetUrl(wchar_t *pszBuffer, int cchBufferMax);
+ HRESULT GetExternal(IDispatch **ppDispatch);
+ HRESULT GetIcon(wchar_t *pszBuffer, int cchBufferMax);
+
+public:
+ HRESULT Show();
+ HRESULT Finish();
+
+protected:
+ ULONG ref;
+ LPWSTR url;
+ obj_ombrowser *browserManager;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_UPDATE_SERVICE_HEADER \ No newline at end of file
diff --git a/Src/Winamp/updateServicePopup.cpp b/Src/Winamp/updateServicePopup.cpp
new file mode 100644
index 00000000..f7b3a8bc
--- /dev/null
+++ b/Src/Winamp/updateServicePopup.cpp
@@ -0,0 +1,112 @@
+#include "main.h"
+#include "./updateService.h"
+#include "./api.h"
+
+#include "../omBrowser/obj_ombrowser.h"
+#include "../omBrowser/ifc_omservice.h"
+#include "../omBrowser/browserPopup.h"
+#include "../omBrowser/browserHost.h"
+
+#ifndef LONGX86
+#ifdef _WIN64
+ #define LONGX86 LONG_PTR
+#else /*_WIN64*/
+ #define LONGX86 LONG
+#endif /*_WIN64*/
+#endif // LONGX86
+
+#define SVCPOPUP_PROP L"Winamp_UpdateSvcWndProp"
+
+typedef struct __SVCPOPUP
+{
+ UpdateService *service;
+ WNDPROC originalProc;
+} SVCPOPUP;
+
+static LRESULT WINAPI ServicePopup_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+HRESULT ServiceSubclass_Attach(HWND hwnd, UpdateService *service)
+{
+ SVCPOPUP *psp = (SVCPOPUP*)calloc(1, sizeof(SVCPOPUP));
+ if (NULL == psp) return E_OUTOFMEMORY;
+
+ psp->service = service;
+ if (NULL != service) service->AddRef();
+
+ psp->originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)ServicePopup_WindowProc);
+ if (NULL == psp->originalProc || FALSE == SetPropW(hwnd, SVCPOPUP_PROP, psp))
+ {
+ if (NULL != psp->originalProc)
+ SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)psp->originalProc);
+
+ if (NULL != psp->service)
+ service->Release();
+
+ free(psp);
+
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+static void ServicePopup_Dettach(HWND hwnd, SVCPOPUP *psp)
+{
+ RemovePropW(hwnd, SVCPOPUP_PROP);
+ if (NULL == psp) return;
+
+ if (NULL != psp->originalProc)
+ SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)psp->originalProc);
+
+ if (NULL != psp->service)
+ {
+ psp->service->Finish();
+ psp->service->Release();
+ }
+ free(psp);
+}
+
+static void ServicePopup_OnBrowserNotify(HWND hwnd, UpdateService *service, NMHDR *pnmh)
+{
+ switch(pnmh->code)
+ {
+ case NBHN_DOCUMENTREADY:
+ if (0 == (WS_VISIBLE & GetWindowLongPtrW(hwnd, GWL_STYLE)))
+ ShowWindowAsync(hwnd, SW_SHOWNORMAL);
+ break;
+ }
+
+}
+
+static LRESULT WINAPI ServicePopup_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ SVCPOPUP *psp = (SVCPOPUP*)GetPropW(hwnd, SVCPOPUP_PROP);
+ if (NULL == psp || NULL == psp->originalProc)
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+
+ switch(uMsg)
+ {
+ case WM_NCDESTROY:
+ case WM_DESTROY:
+ {
+ WNDPROC proc = psp->originalProc;
+ ServicePopup_Dettach(hwnd, psp);
+ if (NULL != proc)
+ CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
+ }
+ return 0;
+
+ case WM_NOTIFY:
+ switch(wParam)
+ {
+ case 0x1000 /*IDC_BROWSER*/:
+ ServicePopup_OnBrowserNotify(hwnd, psp->service, (NMHDR*)lParam);
+ break;
+ }
+ break;
+ }
+
+ return CallWindowProcW(psp->originalProc, hwnd, uMsg, wParam, lParam);
+}
+
+
diff --git a/Src/Winamp/urlmanager.cpp b/Src/Winamp/urlmanager.cpp
new file mode 100644
index 00000000..c034e8dd
--- /dev/null
+++ b/Src/Winamp/urlmanager.cpp
@@ -0,0 +1,36 @@
+#include "urlmanager.h"
+
+const wchar_t *URLManager::GetURL(const wchar_t *urlid)
+{
+ for (URLList::iterator itr=urls.begin();itr!=urls.end();itr++)
+ {
+ if (!_wcsicmp(urlid, itr->urlid))
+ {
+ return itr->url;
+ }
+ }
+ return 0;
+}
+
+void URLManager::AddURL(const wchar_t *urlid, const wchar_t *url)
+{
+ for (URLList::iterator itr=urls.begin();itr!=urls.end();itr++)
+ {
+ if (!_wcsicmp(urlid, itr->urlid))
+ {
+ free(itr->url);
+ itr->url=_wcsdup(url);
+ return ;
+ }
+ }
+ URLS newUrl;
+ newUrl.urlid = _wcsdup(urlid);
+ newUrl.url = _wcsdup(url);
+ urls.push_back(newUrl);
+}
+
+#define CBCLASS URLManager
+START_DISPATCH;
+CB(API_URLMANAGER_GETURL, GetURL);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Winamp/urlmanager.h b/Src/Winamp/urlmanager.h
new file mode 100644
index 00000000..6483dd5c
--- /dev/null
+++ b/Src/Winamp/urlmanager.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "api_urlmanager.h"
+#include <vector>
+
+class URLManager : public api_urlmanager
+{
+public:
+ static const char *getServiceName() { return "URL Manager API"; }
+ static const GUID getServiceGuid() { return urlManagerGUID; }
+public:
+ const wchar_t *GetURL(const wchar_t *urlid);
+// int Parse(const wchar_t *filename);
+
+private:
+ void AddURL(const wchar_t *urlid, const wchar_t *url);
+ struct URLS
+ {
+ wchar_t *urlid;
+ wchar_t *url;
+ };
+ typedef std::vector<URLS> URLList;
+ URLList urls;
+
+protected:
+ RECVS_DISPATCH;
+};
+
diff --git a/Src/Winamp/util.cpp b/Src/Winamp/util.cpp
new file mode 100644
index 00000000..23427f56
--- /dev/null
+++ b/Src/Winamp/util.cpp
@@ -0,0 +1,660 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+#include <windows.h>
+#include "strutil.h"
+#include "../nu/ns_wc.h"
+#include "plush/plush.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoWide.h"
+#include "WinampAttributes.h"
+
+#undef GetSystemMetrics
+
+int IsUrl(const char *url)
+{
+ return !!strstr(url, "://");
+}
+
+
+void link_startsubclass(HWND hwndDlg, UINT id){
+HWND ctrl = GetDlgItem(hwndDlg, id);
+ if(!GetPropW(ctrl, L"link_proc"))
+ {
+ SetPropW(ctrl, L"link_proc",
+ (HANDLE)SetWindowLongPtrW(ctrl, GWLP_WNDPROC, (LONG_PTR)link_handlecursor));
+ }
+}
+
+static HCURSOR link_hand_cursor;
+LRESULT link_handlecursor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT ret = CallWindowProcW((WNDPROC)GetPropW(hwndDlg, L"link_proc"), hwndDlg, uMsg, wParam, lParam);
+ // override the normal cursor behaviour so we have a hand to show it is a link
+ if(uMsg == WM_SETCURSOR)
+ {
+ if((HWND)wParam == hwndDlg)
+ {
+ if(!link_hand_cursor)
+ {
+ link_hand_cursor = LoadCursor(NULL, IDC_HAND);
+ }
+ SetCursor(link_hand_cursor);
+ return TRUE;
+ }
+ }
+ return ret;
+}
+
+void link_handledraw(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_DRAWITEM)
+ {
+ DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
+ if (di->CtlType == ODT_BUTTON)
+ {
+ wchar_t wt[123] = {0};
+ int y;
+ RECT r;
+ HPEN hPen, hOldPen;
+ GetDlgItemTextW(hwndDlg, wParam, wt, sizeof(wt)/sizeof(wt[0]));
+
+ // draw text
+ SetTextColor(di->hDC, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220));
+ r = di->rcItem;
+ // is used by the file types page to have a slimmer button so it doesn't override other
+ // characters which are otherwise drawn over by the size of the button needed for a link
+ if(GetPropW(di->hwndItem, L"slim"))
+ {
+ r.top -= 2;
+ }
+ r.left += 2;
+ DrawTextW(di->hDC, wt, -1, &r, DT_VCENTER | DT_SINGLELINE);
+
+ memset(&r, 0, sizeof(r));
+ DrawTextW(di->hDC, wt, -1, &r, DT_SINGLELINE | DT_CALCRECT);
+
+ // draw underline
+ y = di->rcItem.bottom - ((di->rcItem.bottom - di->rcItem.top) - (r.bottom - r.top)) / 2 - 1;
+ hPen = CreatePen(PS_SOLID, 0, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220));
+ hOldPen = (HPEN) SelectObject(di->hDC, hPen);
+ MoveToEx(di->hDC, di->rcItem.left + 2, y, NULL);
+ LineTo(di->hDC, di->rcItem.right + 2 - ((di->rcItem.right - di->rcItem.left) - (r.right - r.left)), y);
+ SelectObject(di->hDC, hOldPen);
+ DeleteObject(hPen);
+ }
+ }
+}
+
+///////// if you update this, be sure to update the copy of it in $/winampa/winampicon.c
+// thx.
+int geticonid(int x)
+{
+ switch (x) {
+ case 1: return IDI_FILEICON;
+ case 2: return IDI_FILEICON2;
+ case 3: return IDI_FILEICON3;
+ case 4: return IDI_FILEICON10;
+ case 5: return IDI_FILEICON5;
+ case 6: return IDI_FILEICON6;
+ case 7: return IDI_FILEICON7;
+ case 8: return IDI_FILEICON8;
+ case 9: return IDI_FILEICON9;
+ case 10: return IDI_FILEICON4;
+ case 11: return IDI_FILEICON11;
+ case 12: return ICON_TB1;
+ case 13: return -666;
+ default: return ICON_XP;
+ }
+}
+/*
+void plSplineGetPoint(pl_Spline *s, float frame, float *out)
+{
+ int i, i_1, i0, i1, i2;
+ float time1, time2, time3;
+ float t1, t2, t3, t4, u1, u2, u3, u4, v1, v2, v3;
+ float a, b, c, d;
+
+ float *keys = s->keys;
+
+ a = (1 - s->tens) * (1 + s->cont) * (1 + s->bias);
+ b = (1 - s->tens) * (1 - s->cont) * (1 - s->bias);
+ c = (1 - s->tens) * (1 - s->cont) * (1 + s->bias);
+ d = (1 - s->tens) * (1 + s->cont) * (1 - s->bias);
+ v1 = t1 = -a / 2.0f; u1 = a;
+ u2 = ( -6 - 2 * a + 2 * b + c) / 2.0f; v2 = (a - b) / 2.0f; t2 = (4 + a - b - c) / 2.0f;
+ t3 = ( -4 + b + c - d) / 2.0f;
+ u3 = (6 - 2 * b - c + d) / 2.0f;
+ v3 = b / 2.0f;
+ t4 = d / 2.0f; u4 = -t4;
+
+ i0 = (int) frame;
+ i_1 = i0 - 1;
+ while (i_1 < 0) i_1 += s->numKeys;
+ i1 = i0 + 1;
+ while (i1 >= s->numKeys) i1 -= s->numKeys;
+ i2 = i0 + 2;
+ while (i2 >= s->numKeys) i2 -= s->numKeys;
+ time1 = frame - (float) ((int) frame);
+ time2 = time1 * time1;
+ time3 = time2 * time1;
+ i0 *= s->keyWidth;
+ i1 *= s->keyWidth;
+ i2 *= s->keyWidth;
+ i_1 *= s->keyWidth;
+ for (i = 0; i < s->keyWidth; i ++)
+ {
+ a = t1 * keys[i + i_1] + t2 * keys[i + i0] + t3 * keys[i + i1] + t4 * keys[i + i2];
+ b = u1 * keys[i + i_1] + u2 * keys[i + i0] + u3 * keys[i + i1] + u4 * keys[i + i2];
+ c = v1 * keys[i + i_1] + v2 * keys[i + i0] + v3 * keys[i + i1];
+ *out++ = a * time3 + b * time2 + c * time1 + keys[i + i0];
+ }
+}
+*/
+//int transAccel(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+//{
+// HACCEL h;
+// MSG msg;
+// if (hwnd == hMainWindow) h = hAccel[0];
+// else if (hwnd == hEQWindow) h = hAccel[1];
+// else if (hwnd == hPLWindow) h = hAccel[2];
+// // else if (hwnd==hMBWindow) h=hAccel[3];
+// else if (hwnd == hVideoWindow || GetParent(hwnd) == hVideoWindow)
+// {
+// h = hAccel[0];
+// }
+// else
+// {
+// return 0;
+// }
+// msg.hwnd = hwnd;
+// msg.lParam = lParam;
+// msg.message = uMsg;
+// msg.wParam = wParam;
+// return TranslateAccelerator(hwnd, h, &msg);
+//
+//}
+
+#include <pshpack4.h>
+
+typedef struct
+{
+ DWORD dwSize;
+ HANDLE hrasconn;
+ char szEntryName[256 + 1];
+ char szDeviceType[ 16 + 1 ];
+ char szDeviceName[ 128 + 1 ];
+}
+RASCONN ;
+#include <poppack.h>
+
+typedef DWORD (WINAPI *RASENUMCONNECTIONS)(RASCONN *lprasconn,
+ LPDWORD lpcb,
+ LPDWORD lpcConnections);
+
+static int isRASActive()
+{
+ int r = 0;
+ HINSTANCE h = LoadLibraryA("rasapi32.dll");
+ RASENUMCONNECTIONS RasEnumConnections;
+ RASCONN v = {sizeof(RASCONN), };
+
+ DWORD i = sizeof(v), o = 0;
+
+ if (!h) return 0;
+ RasEnumConnections = (RASENUMCONNECTIONS)GetProcAddress(h, "RasEnumConnectionsA");
+ if (RasEnumConnections && !RasEnumConnections(&v, &i, &o) && o) r = 1;
+ FreeModule(h);
+ return r;
+}
+
+int isInetAvailable(void)
+{
+ if (config_inet_mode == 3)
+ {
+ if (isRASActive()) config_inet_mode = 1;
+ else config_inet_mode = 0;
+ return (1 == config_inet_mode);
+ }
+ if (config_inet_mode == 0) return 1;
+ if (config_inet_mode == 2) return 0;
+ return isRASActive();
+}
+
+unsigned int getDay(void)
+{
+ unsigned int day = 0;
+ SYSTEMTIME tm, st = {0, };
+ FILETIME ft1, ft2;
+ ULARGE_INTEGER l1, l2;
+ GetSystemTime(&tm);
+ st.wYear = 1978;
+ st.wMonth = 10;
+ st.wDay = 14;
+ SystemTimeToFileTime(&tm, &ft1);
+ SystemTimeToFileTime(&st, &ft2);
+ memcpy(&l1, &ft1, sizeof(l1));
+ memcpy(&l2, &ft2, sizeof(l2));
+ day = (int) ((l1.QuadPart - l2.QuadPart) / (10 * 1000 * 1000) / (60 * 60 * 24));
+ return day;
+}
+
+void recent_add(const wchar_t *loc)
+{
+ wchar_t ls[MAX_PATH] = {0};
+ _r_sW("RecentURL1", ls, MAX_PATH);
+ _w_sW("RecentURL1", loc);
+
+ if (wcscmp(ls, loc))
+ {
+ int x = 2;
+ while(1)
+ {
+ char s[123] = {0};
+ wchar_t temp[MAX_PATH] = {0};
+ StringCchPrintfA(s, 123, "RecentURL%d", x);
+
+ _r_sW(s, temp, MAX_PATH);
+ if (ls[0]) _w_sW(s, ls);
+ if (!_wcsicmp(temp, loc) || !temp[0])
+ break;
+ lstrcpynW(ls, temp, MAX_PATH);
+ x++;
+ }
+ }
+}
+
+#include <assert.h>
+void getViewport(RECT *r, HWND wnd, int full, RECT *sr)
+{
+ POINT *p = NULL;
+ if (p || sr || wnd)
+ {
+ HMONITOR hm = NULL;
+
+ if (sr)
+ hm = MonitorFromRect(sr, MONITOR_DEFAULTTONEAREST);
+ else if (wnd)
+ hm = MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST);
+ else if (p)
+ hm = MonitorFromPoint(*p, MONITOR_DEFAULTTONEAREST);
+
+ if (hm)
+ {
+ MONITORINFOEXW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+
+ if (GetMonitorInfoW(hm, &mi))
+ {
+ if (!full)
+ *r = mi.rcWork;
+ else
+ *r = mi.rcMonitor;
+
+ return ;
+ }
+ }
+ }
+ if (full)
+ { // this might be borked =)
+ r->top = r->left = 0;
+ r->right = GetSystemMetrics(SM_CXSCREEN);
+ r->bottom = GetSystemMetrics(SM_CYSCREEN);
+ }
+ else
+ {
+ SystemParametersInfoW(SPI_GETWORKAREA, 0, r, 0);
+ }
+}
+
+BOOL windowOffScreen(HWND hwnd, POINT pt)
+{
+ RECT r = {0}, wnd = {0}, sr = {0};
+ GetWindowRect(hwnd, &wnd);
+ sr.left = pt.x;
+ sr.top = pt.y;
+ sr.right = sr.left + (wnd.right - wnd.left);
+ sr.bottom = sr.top + (wnd.bottom - wnd.top);
+ getViewport(&r, hwnd, 0, &sr);
+ return !PtInRect(&r, pt);
+}
+
+void readwrite_client_uid(int isWrite, wchar_t uid_str[64])
+{
+ HKEY hkey;
+ wchar_t path[MAX_PATH] = {0};
+ GetModuleFileNameW(0, path, MAX_PATH);
+
+ if (isWrite)
+ {
+ IFileTypeRegistrar *registrar=0;
+ if (GetRegistrar(&registrar, true) == 0 && registrar)
+ {
+ registrar->WriteClientUIDKey(path, uid_str);
+ registrar->Release();
+ }
+ return;
+ }
+
+ if (!isWrite) *uid_str = 0;
+ if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Nullsoft\\Winamp", 0, 0, 0, KEY_READ, NULL, &hkey, NULL) == ERROR_SUCCESS)
+ {
+ DWORD s = 512, t = REG_SZ;
+ if (RegQueryValueExW(hkey, path, 0, &t, (LPBYTE)uid_str, &s) != ERROR_SUCCESS || t != REG_SZ) uid_str[0] = 0;
+ RegCloseKey(hkey);
+ }
+}
+
+
+BOOL read_compatmode()
+{
+ HKEY hkey = NULL;
+ wchar_t path[MAX_PATH] = {0};
+ GetModuleFileNameW(0, path, MAX_PATH);
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 0, 0, 0, KEY_READ, NULL, &hkey, NULL) == ERROR_SUCCESS)
+ {
+ DWORD s = 512, t = REG_SZ;
+ wchar_t buf[128] = {0};
+ if (RegQueryValueExW(hkey, path, 0, &t, (LPBYTE)buf, &s) != ERROR_SUCCESS || t != REG_SZ) buf[0] = 0;
+ RegCloseKey(hkey);
+
+ wchar_t *p = buf, *fields[] = {L"256COLOR", L"640X480", L"DISABLETHEMES", L"$",
+ L"DISABLEDWM", L"DISABLEUSERCALLBACKEXCEPTION",
+ L"HIGHDPIAWARE", L"RUNASADMIN", L"IGNOREFREELIBRARY",
+ L"ELEVATECREATEPROCESS", L"#", L"~", L"PLACEHOLDERFILES"};
+ int fields_len[] = {8, 7, 13, 1, 10, 28, 12, 10, 17, 20, 1, 1, 16};
+ while (p && *p)
+ {
+ wchar_t *pp = p;
+ while (pp && *pp && *pp != L' ')
+ {
+ pp = CharNextW(pp);
+ }
+
+ wchar_t pp_old = (pp ? *pp : 0);
+ if (pp && *pp) *pp = 0;
+
+ bool found = false;
+ for (int i = 0; i < sizeof(fields)/sizeof(fields[0]); i++)
+ {
+ if (!wcsncmp(fields[i], p, fields_len[i]))
+ found = true;
+ }
+ if (!found)
+ return TRUE;
+
+ if (pp) *pp = pp_old;
+ if (!pp_old) break;
+ p = CharNextW(pp);
+ }
+ }
+ return FALSE;
+}
+
+BOOL IsVista(void)
+{
+ static INT fVista = -1;
+
+ if (-1 == fVista)
+ {
+ OSVERSIONINFO osver = {0};
+ osver.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+ fVista = (::GetVersionEx(&osver) && osver.dwPlatformId == VER_PLATFORM_WIN32_NT && (osver.dwMajorVersion >= 6)) ? 1 : 0;
+ }
+
+ return (1 == fVista);
+}
+
+BOOL IsVistaOrLower(void)
+{
+ static INT fVistaOrLower = -1;
+
+ if (-1 == fVistaOrLower)
+ {
+ OSVERSIONINFO osver = {0};
+ osver.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+ fVistaOrLower = (::GetVersionEx(&osver) && osver.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+ (osver.dwMajorVersion <= 5 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0))) ? 1 : 0;
+ }
+
+ return (1 == fVistaOrLower);
+}
+
+BOOL IsWin8(void)
+{
+ static INT fWin8 = -1;
+
+ if (-1 == fWin8)
+ {
+ OSVERSIONINFO osver = {0};
+ osver.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+ fWin8 = ( ::GetVersionEx(&osver) && osver.dwPlatformId == VER_PLATFORM_WIN32_NT && (osver.dwMajorVersion > 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion >= 2))) ? 1 : 0;
+ }
+
+ return (1 == fWin8);
+}
+
+//XP Theme crap
+typedef HRESULT (WINAPI * ENABLETHEMEDIALOGTEXTURE)(HWND, DWORD);
+
+int IsWinXPTheme(void)
+{
+ static int previousRet = -1;
+ if (previousRet == -1)
+ {
+ BOOL bEnabled(FALSE);
+ OSVERSIONINFO vi;
+
+ vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (GetVersionEx(&vi) && (vi.dwMajorVersion > 5 || (vi.dwMajorVersion == 5 && vi.dwMinorVersion > 0)))
+ {
+ HINSTANCE dll = LoadLibraryW(TEXT("uxtheme.dll"));
+ if (dll)
+ {
+ BOOL (WINAPI *waIsAppThemed)(void);
+ BOOL (WINAPI *waIsThemeActive)(void);
+ waIsAppThemed = (BOOL (WINAPI *)())GetProcAddress(dll, "IsAppThemed");
+ waIsThemeActive = (BOOL (WINAPI *)())GetProcAddress(dll, "IsThemeActive");
+
+ if (waIsAppThemed && waIsThemeActive && waIsAppThemed() && waIsThemeActive())
+ {
+ HMODULE hComCtl = LoadLibraryW(TEXT("comctl32.dll"));
+ if (hComCtl)
+ {
+ HRESULT (CALLBACK *waDllGetVersion)(DLLVERSIONINFO*) = (HRESULT (CALLBACK *)(DLLVERSIONINFO*))GetProcAddress(hComCtl, "DllGetVersion");
+ if (waDllGetVersion)
+ {
+ DLLVERSIONINFO dllVer;
+ dllVer.cbSize = sizeof(DLLVERSIONINFO);
+ if (S_OK == waDllGetVersion(&dllVer) && dllVer.dwMajorVersion >= 6) bEnabled = TRUE;
+ }
+ FreeLibrary(hComCtl);
+ }
+ }
+ FreeLibrary(dll);
+ }
+ }
+ previousRet = bEnabled;
+ }
+ return previousRet;
+}
+
+void DoWinXPStyle(HWND tab)
+{
+ WAEnableThemeDialogTexture(tab, ETDT_ENABLETAB);
+}
+
+HRESULT WAEnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
+{
+ static int uxThemeTried = 0;
+ static ENABLETHEMEDIALOGTEXTURE pfnETDT = NULL;
+
+ if(!uxThemeTried)
+ {
+ HINSTANCE ux_hDll;
+ if ((ux_hDll = LoadLibraryA("uxtheme.dll")) != NULL)
+ pfnETDT = (ENABLETHEMEDIALOGTEXTURE)GetProcAddress(ux_hDll, "EnableThemeDialogTexture");
+
+ uxThemeTried = 1;
+ }
+
+ return (pfnETDT) ? pfnETDT(hwnd, dwFlags) : E_NOTIMPL;
+}
+
+typedef BOOL(WINAPI*ISCOMPOSITIONACTIVE)(VOID);
+
+int IsAero(void)
+{
+ static int uxTried = 0;
+ static ISCOMPOSITIONACTIVE IsAeroActive = 0;
+ if (!uxTried)
+ {
+ static HMODULE UXTHEME = 0;
+ if ((UXTHEME = LoadLibraryA("uxtheme.dll")) != NULL)
+ IsAeroActive = (ISCOMPOSITIONACTIVE)GetProcAddress(UXTHEME, "IsCompositionActive");
+
+ uxTried = 1;
+ }
+ if (IsAeroActive)
+ return !!IsAeroActive();
+ else
+ return 0;
+}
+
+/*
+int IsCharSpace(char digit)
+{
+ WORD type=0;
+ GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return type&C1_SPACE;
+}
+
+int IsCharSpaceW(wchar_t digit)
+{
+ WORD type=0;
+ GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return type&C1_SPACE;
+}
+*/
+LPCWSTR BuildFullPath(LPCWSTR pszPathRoot, LPCWSTR pszPath, LPWSTR pszDest, INT cchDest)
+{
+ LPCWSTR pszFile;
+ if (!pszPath || !*pszPath)
+ {
+ pszDest[0] = 0x00;
+ return pszDest;
+ }
+ pszFile = PathFindFileNameW(pszPath);
+ if (pszFile != pszPath)
+ {
+ if (PathIsRelativeW(pszPath))
+ {
+ wchar_t szTemp[MAX_PATH] = {0};
+ PathCombineW(szTemp, pszPathRoot, pszPath);
+ PathCanonicalizeW(pszDest, szTemp);
+ }
+ else StringCchCopyW(pszDest, cchDest, pszPath);
+ }
+ else {
+ if (pszPathRoot && *pszPathRoot) PathCombineW(pszDest, pszPathRoot, pszPath);
+ else StringCchCopyW(pszDest, cchDest, pszPath);
+ }
+
+ return pszDest;
+}
+
+INT ComparePath(LPCWSTR pszPath1, LPCWSTR pszPath2, LPCWSTR pszPathRoot) // compares two pathes
+{
+ INT cr;
+ DWORD lcid;
+ LPCWSTR pszFile1, pszFile2;
+
+ if (!pszPath1 || !pszPath2) return 0;
+
+ lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ pszFile1 = PathFindFileNameW(pszPath1);
+ pszFile2 = PathFindFileNameW(pszPath2);
+
+ cr = CompareStringW(lcid, NORM_IGNORECASE, pszFile1, -1, pszFile2, -1);
+
+ if (CSTR_EQUAL == cr && (pszFile1 != pszPath1 || pszFile2 != pszPath2))
+ {
+ wchar_t path1[MAX_PATH*2] = {0}, path2[MAX_PATH*2] = {0};
+ pszPath1 = BuildFullPath(pszPathRoot, pszPath1, path1, sizeof(path1)/sizeof(wchar_t));
+ pszPath2 = BuildFullPath(pszPathRoot, pszPath2, path2, sizeof(path2)/sizeof(wchar_t));
+ if (!pszPath1 || !pszPath2) return 0;
+ cr = CompareStringW(lcid, NORM_IGNORECASE, pszPath1, -1, path2, -1);
+ }
+ return cr;
+}
+
+BOOL DisabledWindow_OnMouseClick(HWND hwnd)
+{
+ DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ if (WS_DISABLED != ((WS_CHILD | WS_DISABLED) & windowStyle))
+ return FALSE;
+
+ HWND hActive = GetActiveWindow();
+ HWND hPopup = GetWindow(hwnd, GW_ENABLEDPOPUP);
+
+ BOOL beepOk = (hPopup == hActive || hwnd == GetWindow(hActive, GW_OWNER));
+ if (!beepOk && NULL == hPopup)
+ {
+ for (HWND hWalker = hwnd; ;)
+ {
+ hWalker = GetWindow(hWalker, GW_OWNER);
+ if (NULL == hWalker || (0 != (WS_CHILD & GetWindowLongPtrW(hWalker, GWL_STYLE))))
+ break;
+ if (hActive == GetWindow(hWalker, GW_ENABLEDPOPUP))
+ {
+ beepOk = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (beepOk)
+ {
+ if (config_accessibility_modalflash.GetBool())
+ {
+ FLASHWINFO flashInfo;
+ flashInfo.cbSize = sizeof(FLASHWINFO);
+ flashInfo.hwnd = hActive;
+ flashInfo.dwFlags = FLASHW_CAPTION;
+ flashInfo.uCount = 2;
+ flashInfo.dwTimeout = 100;
+
+ FlashWindowEx(&flashInfo);
+ }
+
+ if (config_accessibility_modalbeep.GetBool())
+ MessageBeep(MB_OK);
+ }
+ else
+ {
+ for (HWND hWalker = hwnd; NULL == hPopup;)
+ {
+ hWalker = GetWindow(hWalker, GW_OWNER);
+ if (NULL == hWalker || (0 != (WS_CHILD & GetWindowLongPtrW(hWalker, GWL_STYLE))))
+ break;
+ hPopup = GetWindow(hWalker, GW_ENABLEDPOPUP);
+ }
+
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
+ if (NULL != hPopup && hPopup != hwnd)
+ {
+ BringWindowToTop(hPopup);
+ SetActiveWindow(hPopup);
+ }
+ }
+
+ return TRUE;
+} \ No newline at end of file
diff --git a/Src/Winamp/verchk.cpp b/Src/Winamp/verchk.cpp
new file mode 100644
index 00000000..fee83d96
--- /dev/null
+++ b/Src/Winamp/verchk.cpp
@@ -0,0 +1,285 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "Main.h"
+#if 0
+static int (__stdcall *p_recv)(SOCKET s, char FAR* buf, int len, int flags);
+
+
+static int g_nvck;
+
+static int recv_string(SOCKET s, char *str, int maxlen)
+{
+ int p=0;
+ do
+ {
+ int t=0;
+ while (t!=1)
+ {
+ t=p_recv(s,str+p,1,0);
+ if (t != 1)
+ {
+ str[0]=0;
+ return -1;
+ }
+ if (str[p] == '\r') t=0;
+ }
+ } while (str[p] != '\n' && ++p < maxlen-1);
+ str[p--]=0;
+ while (str[p] == '\n' && p > 0)
+ {
+ str[p--]=0;
+ }
+ if (p < 0) p = 0;
+ return p;
+}
+
+
+static DWORD WINAPI _Thread(void *p666)
+{
+ char *rf_url = (char *)p666;
+ HINSTANCE hws = LoadLibrary("wsock32.dll");
+ SOCKET sock;
+ char *proxy;
+ char connect_host[MAX_PATH];
+ unsigned short connect_port;
+ int success=0;
+ int (__stdcall *select)(int nfds,fd_set FAR * readfds,fd_set FAR * writefds,fd_set FAR * exceptfds,const struct timeval FAR * timeout);
+ int (__stdcall *WSAGetLastError)(void);
+ int (__stdcall *WSACleanup)(void);
+ int (__stdcall *WSAStartup)(WORD wVersionRequested,LPWSADATA lpWSAData);
+ int (__stdcall *closesocket)(SOCKET s);
+ int (__stdcall *send)(SOCKET s,const char FAR *buf,int len,int flags);
+ SOCKET (__stdcall *socket)(int af, int type,int protocol);
+ int (__stdcall *connect)( SOCKET s, const struct sockaddr FAR *name, int namelen );
+
+ unsigned long (__stdcall *inet_addr)(const char FAR *cp );
+ struct hostent FAR * (__stdcall *gethostbyname)(const char FAR *name);
+ int (__stdcall *ioctlsocket)(SOCKET s,long cmd,u_long FAR *argp);
+ u_short (__stdcall *htons)(u_short hostshort);
+
+ if (hws)
+ {
+ WSAGetLastError=(void*)GetProcAddress(hws,"WSAGetLastError");
+ WSACleanup=(void*)GetProcAddress(hws,"WSACleanup");
+ WSAStartup=(void*)GetProcAddress(hws,"WSAStartup");
+ closesocket=(void*)GetProcAddress(hws,"closesocket");
+ send=(void*)GetProcAddress(hws,"send");
+ p_recv=(void*)GetProcAddress(hws,"recv");
+ select=(void*)GetProcAddress(hws,"select");
+ connect=(void*)GetProcAddress(hws,"connect");
+ socket=(void*)GetProcAddress(hws,"socket");
+ inet_addr=(void*)GetProcAddress(hws,"inet_addr");
+ gethostbyname=(void*)GetProcAddress(hws,"gethostbyname");
+ ioctlsocket=(void*)GetProcAddress(hws,"ioctlsocket");
+ htons=(void*)GetProcAddress(hws,"htons");
+ }
+
+ if (!hws || !p_recv || !WSACleanup ||
+ !WSAStartup || !closesocket || !send ||
+ !connect || !socket || !inet_addr ||
+ !gethostbyname || !ioctlsocket || !htons || !select || !WSAGetLastError)
+ {
+ if (hws) FreeLibrary(hws);
+ return 0;
+ }
+
+ {
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(1, 1), &wsaData))
+ {
+ FreeLibrary(hws);
+ return 0;
+ }
+ }
+
+ // determine if proxy server used
+ proxy=config_proxy;
+ while (*proxy == ' ' || *proxy == '\t') proxy++;
+
+ if (*proxy)
+ {
+ lstrcpyn(connect_host,proxy,sizeof(connect_host)/sizeof(*connect_host));
+ }
+ else
+ {
+ lstrcpyn(connect_host,"www.winamp.com",sizeof(connect_host)/sizeof(*connect_host));
+ }
+ connect_port=80;
+
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET)
+ {
+ WSACleanup();
+ FreeLibrary(hws);
+ return 0;
+ }
+
+ {
+ int t;
+ struct sockaddr_in blah;
+ struct hostent *he;
+ memset((char *)&blah,0,sizeof(blah));
+ blah.sin_family=AF_INET;
+ blah.sin_addr.s_addr=inet_addr(connect_host);
+ blah.sin_port=htons(connect_port);
+
+ if (blah.sin_addr.s_addr == INADDR_NONE)
+ {
+ if ((he = gethostbyname(connect_host)) != NULL)
+ memcpy((char *)&blah.sin_addr, he->h_addr, he->h_length);
+ else if ((blah.sin_addr.s_addr = inet_addr(connect_host))==INADDR_NONE)
+ {
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ return 0;
+ }
+ }
+ t=connect(sock,(struct sockaddr *)&blah,16);
+ if (t==-1) goto cleanup;
+ }
+ {
+ char send_string[2048];
+ char request_file[1024];
+ StringCchCopy(send_string,2048,rf_url);
+ if (*proxy)
+ {
+ StringCchPrintf(request_file,1024, "http://www.winamp.com%s",rf_url);
+ }
+ else StringCchCopy(request_file,1024,rf_url);
+ StringCchPrintf(send_string,2048,"GET %s HTTP/1.0\r\n"
+ "User-Agent: Winamp/%s\r\n"
+ "Host: www.winamp.com\r\n"
+ "Accept: */*\r\n\r\n",request_file,app_version);
+// MessageBox(NULL,send_string,"SENDING:",0);
+ send(sock,send_string,lstrlen(send_string),0);
+ }
+
+ { // get the standard HTTP 1.0 200 OK
+ char buf[1024];
+ int x = recv_string(sock,buf,sizeof(buf));
+// MessageBox(NULL,buf,buf,0);
+ if (x < 0 || !strstr(buf,"OK")) goto cleanup;
+ }
+
+ if (g_nvck&2) stats_clear();
+ while (1)
+ {
+ char buf[1024],*p;
+ int x = recv_string(sock,buf,sizeof(buf));
+ if (x < 0) goto cleanup;
+ if (buf[0] == '\r' || !buf[0]) break;
+
+ {
+ p=buf;
+ while (*p && *p != ':') p++;
+ if (*p == ':')
+ {
+ *p++=0;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+ else p=NULL;
+ }
+ }
+
+ {
+ int is_upd=0;
+ char obuf[32768]="";
+ char buf[1024];
+ int x = recv_string(sock,buf,sizeof(buf));
+ if (x < 0 || buf[1] != '.') goto cleanup;
+ if (buf[0] > app_version[0]) is_upd=1;
+ else if (buf[0] == app_version[0])
+ {
+ int r2;
+ char oldver[4];
+ int oldlen;
+ oldlen = lstrlen(app_version+2);
+ if ( oldlen == 3 )
+ {
+ oldver[0]=*(app_version+2);
+ oldver[1]=*(app_version+3);
+ oldver[2]=*(app_version+4);
+ }
+ if ( oldlen == 2 )
+ {
+ oldver[0]=*(app_version+2);
+ oldver[1]=*(app_version+3);
+ oldver[2]='0';
+ }
+ if ( oldlen == 1 )
+ {
+ oldver[0]=*(app_version+2);
+ oldver[1]='0';
+ oldver[2]='0';
+ }
+ oldver[3]=0;
+ r2=atoi(oldver);
+ if (atoi(buf+2)>r2) is_upd=1;
+ }
+
+ if (!is_upd)
+ {
+ if ((g_nvck&1)&&config_newverchk) config_newverchk=getDay();
+ goto cleanup;
+ }
+ while (lstrlen(obuf)<32768-sizeof(buf)*2)
+ {
+ x=recv_string(sock,buf,sizeof(buf));
+ if (x < 0) break;
+ StringCchCat(obuf,32768,buf);
+ StringCchCat(obuf,32768,"\r\n");
+ }
+ if (g_nvck&1)
+ {
+ if (MessageBox(NULL,obuf,getString(IDS_WINAMP_UPDATE_MSG,NULL,0),MB_YESNO) == IDYES)
+ {
+ myOpenURL(NULL, L"http://www.winamp.com/getwinamp/");
+ }
+ else
+ {
+ if ((g_nvck&1)&&config_newverchk) config_newverchk=getDay();
+ }
+ }
+ }
+cleanup:
+ closesocket(sock);
+ WSACleanup();
+ FreeLibrary(hws);
+ return 0;
+}
+
+void newversioncheck(void)
+{
+ DWORD id;
+ static char s[512];
+ int stats[NUM_STATS]={0,};
+ int x;
+ g_nvck=(config_newverchk2?2:0)|(config_newverchk?1:0);
+ if (g_nvck&3)
+ {
+ StringCchPrintf(s,512,"/update/latest-version.jhtml?v=%s",app_version);
+ if (g_nvck&2)
+ {
+ stats_get(stats);
+ StringCchCat(s,512,"&ID=");
+ stats_getuidstr(s+lstrlen(s));
+ for (x = 0; x < NUM_STATS; x ++)
+ {
+ StringCchPrintf(s+lstrlen(s),512-lstrlen(s),"&st%d=%d",x+1,stats[x]);
+ }
+ StringCchPrintf(s+lstrlen(s),512-lstrlen(s),"&regv=%d",g_regver);
+ }
+
+ // MessageBox(NULL,s,"metric",0);
+ CloseHandle(CreateThread(NULL,0,_Thread,(LPVOID)s,0,&id));
+ }
+}
+
+#endif
diff --git a/Src/Winamp/version.rc2 b/Src/Winamp/version.rc2
new file mode 100644
index 00000000..daed198c
--- /dev/null
+++ b/Src/Winamp/version.rc2
@@ -0,0 +1,42 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION WINAMP_PRODUCTVER
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", "Visit http://www.winamp.com/ for updates."
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp"
+ VALUE "FileVersion", STR_WINAMP_PRODUCTVER
+ VALUE "InternalName", "Winamp"
+ VALUE "LegalCopyright", "Copyright © 1997-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "winamp.exe"
+ VALUE "PrivateBuild", "1"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ VALUE "SpecialBuild", "1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Winamp/vid_d3d.cpp b/Src/Winamp/vid_d3d.cpp
new file mode 100644
index 00000000..1048ed09
--- /dev/null
+++ b/Src/Winamp/vid_d3d.cpp
@@ -0,0 +1,740 @@
+#include "vid_d3d.h"
+#include "vid_subs.h"
+#include "../nu/AutoWide.h"
+#include "videooutput.h"
+#include "../nsutil/image.h"
+#include <d3d9.h>
+#include "WinampAttributes.h"
+#include "IVideoD3DOSD.h"
+#include <stdint.h>
+
+struct YV12_PLANES;
+
+typedef HRESULT (WINAPI *DIRECT3DCREATE9EX)(UINT SDKVersion, IDirect3D9Ex **);
+typedef IDirect3D9 *(WINAPI *DIRECT3DCREATE9)(UINT SDKVersion);
+static DIRECT3DCREATE9EX creatorex=0;
+static DIRECT3DCREATE9 creator=0;
+static HMODULE d3d_lib = 0;
+static bool tried=false;
+static DWORD winver;
+
+extern IVideoOSD *posd;
+
+static bool CreateDirect3D(IDirect3D9 **d3d, IDirect3D9Ex **d3dEx)
+{
+ if (!d3d_lib && !creator)
+ {
+ if (tried)
+ return false;
+
+ d3d_lib = LoadLibraryW(L"d3d9.dll");
+ if (!d3d_lib)
+ {
+ tried=true;
+ return false;
+ }
+
+ creatorex = (DIRECT3DCREATE9EX)GetProcAddress(d3d_lib, "Direct3DCreate9Ex");
+ creator = (DIRECT3DCREATE9)GetProcAddress(d3d_lib, "Direct3DCreate9");
+ if (!creatorex && !creator)
+ {
+ FreeLibrary(d3d_lib);
+ tried=true;
+ return false;
+ }
+ }
+ if (creatorex)
+ {
+ if (SUCCEEDED(creatorex(D3D_SDK_VERSION, d3dEx)) && *d3dEx)
+ {
+ (*d3dEx)->QueryInterface(__uuidof(IDirect3D9), (void **)d3d);
+ return true;
+ }
+ }
+
+ if (creator)
+ {
+ *d3d = creator(D3D_SDK_VERSION);
+ *d3dEx=0;
+ return !!d3d;
+ }
+ return false;
+}
+
+static void BuildPresentationParameters(D3DPRESENT_PARAMETERS &presentation_parameters, HWND hwnd, D3DSWAPEFFECT swap_effect)
+{
+ memset(&presentation_parameters, 0, sizeof(presentation_parameters));
+ presentation_parameters.BackBufferWidth = 0;
+ presentation_parameters.BackBufferHeight = 0;
+ presentation_parameters.BackBufferFormat = D3DFMT_UNKNOWN;
+ presentation_parameters.BackBufferCount = 1;
+ presentation_parameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+ presentation_parameters.MultiSampleQuality = 0;
+ presentation_parameters.SwapEffect = swap_effect;
+
+ presentation_parameters.hDeviceWindow = hwnd;
+ presentation_parameters.Windowed = TRUE;
+ presentation_parameters.EnableAutoDepthStencil = FALSE;
+ presentation_parameters.Flags = /*D3DPRESENTFLAG_LOCKABLE_BACKBUFFER |*/ D3DPRESENTFLAG_VIDEO;
+ presentation_parameters.FullScreen_RefreshRateInHz = 0;
+ presentation_parameters.PresentationInterval = (!config_video_vsync2 ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE);
+}
+
+static UINT FindMyMonitor(IDirect3D9 *d3d, HWND hwnd)
+{
+ HMONITOR monitor=MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+ if (monitor)
+ {
+ UINT num_adapters = d3d->GetAdapterCount();
+ for (UINT i=0;i!=num_adapters;i++)
+ {
+ if (d3d->GetAdapterMonitor(i) == monitor)
+ return i;
+ }
+ }
+ return D3DADAPTER_DEFAULT;
+}
+
+D3DDEVTYPE Direct3DVideoOutput::GetDeviceType(IDirect3D9 *d3d, UINT display_adapter)
+{
+ D3DCAPS9 caps;
+ D3DDEVTYPE device_type = D3DDEVTYPE_HAL;
+ for(;;)
+ {
+ HRESULT hr = d3d->GetDeviceCaps(display_adapter, device_type, &caps);
+ if (hr == S_OK)
+ {
+ if ((D3DPTFILTERCAPS_MAGFLINEAR & caps.StretchRectFilterCaps) && (D3DPTFILTERCAPS_MINFLINEAR & caps.StretchRectFilterCaps))
+ stretch_filter = D3DTEXF_LINEAR;
+ else if ((D3DPTFILTERCAPS_MAGFPOINT & caps.StretchRectFilterCaps) && (D3DPTFILTERCAPS_MINFPOINT & caps.StretchRectFilterCaps))
+ stretch_filter = D3DTEXF_POINT;
+ else
+ stretch_filter = D3DTEXF_NONE;
+ return device_type;
+ }
+ if (device_type == D3DDEVTYPE_HAL)
+ device_type = D3DDEVTYPE_REF;
+ else
+ break;
+ }
+
+ return (D3DDEVTYPE)0;
+}
+
+static D3DSWAPEFFECT GetSwapEffect(IDirect3D9 *d3d, UINT adapter, D3DDEVTYPE device_type, bool ex)
+{
+ if (ex)
+ {
+ D3DCAPS9 caps;
+ d3d->GetDeviceCaps(adapter, device_type, &caps);
+ if (caps.Caps & D3DCAPS_OVERLAY)
+ {
+ return D3DSWAPEFFECT_OVERLAY;
+ }
+ else
+ {
+ return D3DSWAPEFFECT_FLIPEX;// (D3DSWAPEFFECT)5;
+ }
+ }
+ else
+ {
+ return D3DSWAPEFFECT_FLIP;
+ }
+}
+
+Direct3DVideoOutput::Direct3DVideoOutput(HWND parent, VideoAspectAdjuster *_adjuster)
+{
+ CreateDirect3D(&d3d, &d3dEx);
+ device = 0;
+ deviceEx = 0;
+ surface = 0;
+ width=0;
+ height=0;
+ GetWindowRect(parent, &last_rect);
+ surface_type = D3DFMT_UNKNOWN;
+ display_adapter = 0;
+ subtitle_font = 0;
+ current_subtitle = 0;
+ need_change = 0;
+ adjuster = _adjuster;
+ hwnd = parent;
+ opened=false;
+ valid_surface=false;
+ logo_surface = 0;
+ input_type = 0;
+ flip = 0;
+ m_palette = 0;
+
+ if (d3dEx)
+ {
+ display_adapter = FindMyMonitor(d3d, parent);
+ D3DDEVTYPE device_type = GetDeviceType(d3d, display_adapter);
+ swap_effect = GetSwapEffect(d3d, display_adapter, device_type, true);
+ D3DPRESENT_PARAMETERS presentation_parameters;
+ BuildPresentationParameters(presentation_parameters, parent, swap_effect);
+ HRESULT hr = d3dEx->CreateDeviceEx(display_adapter, D3DDEVTYPE_HAL, parent,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
+ &presentation_parameters, 0,
+ &deviceEx);
+
+ if (FAILED(hr))
+ { // try again with mixed processing
+ hr = d3dEx->CreateDeviceEx(display_adapter, D3DDEVTYPE_HAL, parent,
+ D3DCREATE_MIXED_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
+ &presentation_parameters, 0,
+ &deviceEx);
+
+ if (FAILED(hr))
+ { // and finally software
+ hr = d3dEx->CreateDeviceEx(display_adapter, D3DDEVTYPE_HAL, parent,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
+ &presentation_parameters, 0,
+ &deviceEx);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ deviceEx->QueryInterface(__uuidof(IDirect3DDevice9), (void **)&device);
+ }
+
+ if (!deviceEx)
+ {
+ display_adapter = FindMyMonitor(d3d, parent);
+ D3DDEVTYPE device_type = GetDeviceType(d3d, display_adapter);
+ swap_effect = GetSwapEffect(d3d, display_adapter, device_type, false);
+ if (device_type)
+ {
+ D3DPRESENT_PARAMETERS presentation_parameters;
+ BuildPresentationParameters(presentation_parameters, parent, swap_effect);
+ HRESULT hr = d3d->CreateDevice(display_adapter, device_type, parent,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
+ &presentation_parameters,
+ &device);
+
+ if (FAILED(hr))
+ { // try again with mixed processing
+ hr = d3d->CreateDevice(display_adapter, device_type, parent,
+ D3DCREATE_MIXED_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
+ &presentation_parameters,
+ &device);
+ if (FAILED(hr))
+ { // and finally software
+ /*hr = */d3d->CreateDevice(display_adapter, device_type, parent,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
+ &presentation_parameters,
+ &device);
+ }
+ }
+ }
+ }
+
+ if (device)
+ {
+ // TODO: retrieve dimensions from VideoOutput
+ device->CreateOffscreenPlainSurface(128, 128, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &logo_surface, 0);
+ ((IVideoD3DOSD *)posd)->CreateOSD(device);
+ }
+}
+
+static D3DFORMAT GetColorFormat(unsigned int type)
+{
+ switch(type)
+ {
+ case MAKEFOURCC('Y', 'V', '1', '2'):
+ return (D3DFORMAT)type;
+ case MAKEFOURCC('Y', 'U', 'Y', '2'):
+ return D3DFMT_YUY2;
+ case MAKEFOURCC('U', 'Y', 'V', 'Y'):
+ return D3DFMT_UYVY;
+ case MAKEFOURCC('R', 'G', 'B', '8'):
+ return D3DFMT_P8;
+ case MAKEFOURCC('R', 'G', '3', '2'):
+ return D3DFMT_X8R8G8B8;
+ case MAKEFOURCC('R', 'G', '2', '4'):
+ return D3DFMT_R8G8B8;
+ case MAKEFOURCC('R', '5', '5', '5'):
+ return D3DFMT_X1R5G5B5;
+ case MAKEFOURCC('R', '5', '6', '5'):
+ return D3DFMT_R5G6B5;
+ default:
+ return (D3DFORMAT)D3DFMT_UNKNOWN;
+ }
+}
+
+static bool SubstituteSurfaceType(D3DFORMAT surface_format, D3DFORMAT &substitute_format, int n)
+{
+ if (surface_format == D3DFMT_R8G8B8)
+ {
+ switch(n)
+ {
+ case 0:
+ substitute_format = D3DFMT_X8R8G8B8;
+ return true;
+ }
+ }
+ else if (surface_format == (D3DFORMAT)MAKEFOURCC('Y', 'V', '1', '2'))
+ {
+ switch(n)
+ {
+ case 0:
+ substitute_format = D3DFMT_YUY2;
+ return true;
+ case 1:
+ substitute_format = D3DFMT_UYVY;
+ return true;
+ case 2:
+ substitute_format = D3DFMT_X8R8G8B8;
+ return true;
+ }
+ }
+ return false;
+}
+
+static void PreferredSurfaceType(D3DFORMAT &surface_format)
+{
+ if (surface_format == D3DFMT_P8)
+ {
+ surface_format = D3DFMT_X8R8G8B8;
+ }
+}
+
+void Direct3DVideoOutput::setVFlip(int on)
+{
+ flip = on;
+ if (config_video_fliprgb)
+ flip = !flip;
+}
+
+int Direct3DVideoOutput::OpenVideo(int w, int h, unsigned int type, int flipit, double aspectratio)
+{
+ if (!device)
+ return 0;
+ D3DFORMAT new_surface_type = GetColorFormat(type);
+ if (new_surface_type == D3DFMT_UNKNOWN) // not supported
+ return 0;
+
+ PreferredSurfaceType(new_surface_type);
+
+ input_type = type;
+
+ // see what was set for the flip flag
+ // as nsv streams are generally flipped
+ // so we'll need to invert the handling
+ flip = flipit;
+ if (config_video_fliprgb)
+ flip = !flip;
+
+ // see if we can re-use our old surface
+ if (!surface || surface_type != new_surface_type || w != width || h != height)
+ {
+ if (surface)
+ {
+ surface->Release();
+ surface=0;
+ }
+
+ HRESULT hr;
+
+ D3DFORMAT try_surface_type = new_surface_type;
+ int n=0;
+ do
+ {
+ hr = device->CreateOffscreenPlainSurface(w, h, try_surface_type, D3DPOOL_DEFAULT, &surface, 0);
+
+ } while (hr != S_OK && SubstituteSurfaceType(new_surface_type, try_surface_type, n++));
+
+ surface_type = try_surface_type;
+
+ if (hr != S_OK)
+ return 0;
+
+ width = w;
+ height =h;
+ }
+
+ valid_surface=false;
+ opened=true;
+
+ return 1;
+}
+
+void Direct3DVideoOutput::OnWindowSize()
+{
+ if (device)
+ {
+ RECT wnd_rect;
+ GetWindowRect(hwnd, &wnd_rect);
+ if (need_change || !EqualRect(&wnd_rect, &last_rect))
+ {
+ if ( need_change || (last_rect.right - last_rect.left) != (wnd_rect.right - wnd_rect.left)
+ || (last_rect.bottom - last_rect.top) != (wnd_rect.bottom - wnd_rect.top))
+ {
+ // TODO: check adapter
+ D3DPRESENT_PARAMETERS presentation_parameters;
+ BuildPresentationParameters(presentation_parameters, hwnd, swap_effect);
+ //if (surface)
+ // surface->Release();
+ //surface=0;
+ if (subtitle_font)
+ subtitle_font->Release(); // I hate to do this but we might need a new font size, and it works around a bug
+ subtitle_font = 0;
+
+ if (((IVideoD3DOSD *)posd)->isOSDInited())
+ {
+ ((IVideoD3DOSD *)posd)->LostOSD();
+ }
+ HRESULT hr = device->Reset(&presentation_parameters);
+ if (FAILED(hr))
+ {
+ if (surface)
+ surface->Release();
+ surface=0;
+ /*hr = */device->Reset(&presentation_parameters);
+ /*hr = */device->CreateOffscreenPlainSurface(width, height, surface_type, D3DPOOL_DEFAULT, &surface, 0);
+ }
+ if (((IVideoD3DOSD *)posd)->isOSDInited())
+ {
+ ((IVideoD3DOSD *)posd)->ResetOSD(device);
+ }
+ drawSubtitle(current_subtitle);
+ last_rect = wnd_rect;
+ hr = device->BeginScene();
+ if (SUCCEEDED(hr))
+ DoRender();
+ }
+ else
+ {
+ // TODO: check adapter
+ }
+
+ last_rect = wnd_rect;
+ }
+ }
+}
+
+HRESULT Direct3DVideoOutput::DoRender()
+{
+ RECT r;
+ r = last_rect;
+ r.right -= r.left;
+ r.left = 0;
+ r.bottom -= r.top;
+ r.top = 0;
+
+ //GetClientRect(hwnd, &r);
+ HRESULT hr ;
+
+ IDirect3DSurface9 *back_buffer = 0;
+ hr = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer);
+ if (FAILED(hr))
+ {
+ need_change=1;
+ device->EndScene();
+ return hr;
+ }
+ RECT full_rect = r;
+ adjuster->adjustAspect(r);
+
+ if (opened && valid_surface)
+ {
+ RECT sides[4]={
+ {0, 0, r.left, full_rect.bottom}, // left side
+ {r.right, 0, full_rect.right, full_rect.bottom}, // right side
+ {0, 0, full_rect.right, r.top}, // top
+ {0, r.bottom, full_rect.right, full_rect.bottom} // bottom
+ };
+ for (int i=0;i<4;i++)
+ hr=device->ColorFill(back_buffer, &sides[i], D3DCOLOR_XRGB(0, 0, 0));
+
+ hr = device->StretchRect(surface, NULL, back_buffer, &r, stretch_filter);
+ }
+ else
+ {
+ hr=device->ColorFill(back_buffer, 0, D3DCOLOR_XRGB(0, 0, 0));
+ HDC logo_dc=0;
+ HRESULT hr = logo_surface->GetDC(&logo_dc);
+ if (hr == S_OK)
+ { // draw logo
+ RECT r={0,0,128,128};
+ adjuster->DrawLogo(logo_dc, &r);
+ logo_surface->ReleaseDC(logo_dc);
+ POINT logo_pt = {full_rect.right/2 - 64,full_rect.bottom/2 - 64};
+ device->UpdateSurface(logo_surface, 0, back_buffer, &logo_pt);
+ }
+ }
+ back_buffer->Release();
+
+ if (current_subtitle && subtitle_font)
+ {
+ DWORD oldValue;
+ device->GetRenderState(D3DRS_ALPHABLENDENABLE, &oldValue);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ RECT subRect, origRect;
+ GetClientRect(hwnd, &subRect);
+ origRect = subRect;
+ D3DCOLOR text_color = D3DCOLOR_XRGB(current_subtitle->colorRed, current_subtitle->colorGreen, current_subtitle->colorBlue);
+ AutoWide wide_text(current_subtitle->text);
+
+ // calculate where to draw
+ // TODO: move to drawSubtitle
+ subtitle_font->DrawTextW(NULL, wide_text, -1, &subRect, DT_TOP | DT_WORDBREAK | DT_NOCLIP | DT_CENTER | DT_CALCRECT, text_color);
+ int height_delta = (origRect.bottom - origRect.top) - (subRect.bottom - subRect.top);
+ subRect.top += height_delta;
+ subRect.bottom += height_delta;
+ // draw
+ hr = subtitle_font->DrawTextW(NULL, wide_text, -1, &subRect, DT_TOP | DT_WORDBREAK | DT_NOCLIP | DT_CENTER, text_color);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, oldValue);
+ }
+
+ if (posd && ((IVideoD3DOSD *)posd)->Showing() && ((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
+ {
+ ((IVideoD3DOSD *)posd)->DrawOSD(device);
+ }
+
+ hr = device->EndScene();
+
+ if (FAILED(hr))
+ {
+ need_change = 1;
+ return hr;
+ }
+
+ if (deviceEx)
+ hr = deviceEx->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_DONOTWAIT);
+ else
+ hr = device->Present(NULL, NULL, NULL, NULL);
+
+ if (hr == D3DERR_DEVICELOST)
+ need_change = 1;
+
+ return hr;
+}
+
+void YV12_to_UYVY(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip);
+void YV12_to_YV12(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip);
+void YV12_to_YUY2(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip);
+void YUY2_to_YUY2(unsigned char *output, const char *buf, int pitch, int width, int height, int flip);
+
+void Direct3DVideoOutput::displayFrame(const char *buf, int size, int time)
+{
+ if (need_change || !surface)
+ return;
+
+ RECT r;
+ GetClientRect(hwnd, &r);
+
+ HRESULT hr = device->BeginScene();
+ if (FAILED(hr))
+ {
+ need_change=1;
+ return;
+ }
+
+ D3DLOCKED_RECT locked_surface;
+ hr = surface->LockRect(&locked_surface, NULL, D3DLOCK_DISCARD);
+ if (SUCCEEDED(hr))
+ {
+ if (input_type == MAKEFOURCC('Y','V','1','2'))
+ {
+ const YV12_PLANES *planes = (const YV12_PLANES *)buf;
+ switch((DWORD)surface_type)
+ {
+ case MAKEFOURCC('Y','V','1','2'):
+ YV12_to_YV12((unsigned char *)locked_surface.pBits, planes, locked_surface.Pitch, width, height, flip);
+ break;
+ case MAKEFOURCC('Y','U','Y','2'):
+ YV12_to_YUY2((unsigned char *)locked_surface.pBits, planes, locked_surface.Pitch, width, height, flip);
+ break;
+ case MAKEFOURCC('U','Y','V','Y'):
+ YV12_to_UYVY((unsigned char *)locked_surface.pBits, planes, locked_surface.Pitch, width, height, flip);
+ break;
+ case D3DFMT_X8R8G8B8:
+ {
+ const uint8_t *plane_bufs[3] = { planes->y.baseAddr, planes->v.baseAddr, planes->u.baseAddr};
+ const size_t plane_strides[3] = { (size_t)planes->y.rowBytes, (size_t)planes->v.rowBytes, (size_t)planes->u.rowBytes };
+ if (flip)
+ nsutil_image_Convert_YUV420_RGB32((RGB32 *)((int8_t *)locked_surface.pBits + locked_surface.Pitch*(height-1)), -locked_surface.Pitch, width, height, plane_bufs, plane_strides);
+ else
+ nsutil_image_Convert_YUV420_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, width, height, plane_bufs, plane_strides);
+ }
+ break;
+ }
+ }
+ else if (surface_type == D3DFMT_YUY2) // YUY2
+ {
+ YUY2_to_YUY2((unsigned char *)locked_surface.pBits, buf, locked_surface.Pitch, width, height, flip);
+ }
+ else if (surface_type == D3DFMT_UYVY) // YUY2
+ {
+ YUY2_to_YUY2((unsigned char *)locked_surface.pBits, buf, locked_surface.Pitch, width, height, flip);
+ }
+ else if (surface_type == D3DFMT_P8) // 8bit with palette
+ {
+ if (flip)
+ nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height);
+ else
+ nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height);
+ }
+ else if (surface_type == D3DFMT_X8R8G8B8) // RGB32
+ {
+ if (input_type == MAKEFOURCC('R','G','3','2'))
+ {
+ if (flip)
+ nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*4, width*4, height);
+ else
+ nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*4, width*4, height);
+ }
+ else if (input_type == MAKEFOURCC('R','G','2','4'))
+ {
+ if (flip)
+ nsutil_image_ConvertFlipped_RGB24_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*3, width, height);
+ else
+ nsutil_image_Convert_RGB24_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*3, width, height);
+ }
+ else if (input_type == MAKEFOURCC('R','G','B','8') && m_palette)
+ {
+ if (flip)
+ nsutil_image_PaletteFlipped_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height, (RGB32 *)m_palette);
+ else
+ nsutil_image_Palette_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height, (RGB32 *)m_palette);
+ }
+ }
+ else if (surface_type == D3DFMT_R8G8B8) // RGB24
+ {
+ if (flip || locked_surface.Pitch != width*3)
+ {
+ char *start = (char *)locked_surface.pBits;
+ if (flip)
+ start += locked_surface.Pitch * (height-1);
+ ptrdiff_t pitch = flip?-locked_surface.Pitch:locked_surface.Pitch;
+
+ for (int i=0;i<height;i++)
+ {
+ char *line = start + pitch * i;
+ memcpy(line, buf + width*i*3, width*3);
+ }
+ }
+ else
+ {
+ memcpy(locked_surface.pBits, buf, width*height*3);
+ }
+ }
+ else if (surface_type == D3DFMT_X1R5G5B5)
+ {
+ if (flip)
+ nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
+ else
+ nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
+ }
+ else if (surface_type == D3DFMT_R5G6B5)
+ {
+ if (flip)
+ nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
+ else
+ nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
+ }
+
+ valid_surface = true;
+ /*hr = */surface->UnlockRect();
+ }
+ DoRender();
+}
+
+void Direct3DVideoOutput::close()
+{
+ opened=false;
+}
+
+int Direct3DVideoOutput::onPaint(HWND hwnd)
+{
+ PAINTSTRUCT p;
+ BeginPaint(hwnd, &p);
+ if (swap_effect == D3DSWAPEFFECT_OVERLAY)
+ {
+ deviceEx->PresentEx(0, 0, 0, 0, D3DPRESENT_UPDATEOVERLAYONLY);
+ }
+ else
+ {
+ RECT r;
+ GetClientRect(hwnd, &r);
+
+ if (surface && !need_change)
+ {
+ HRESULT hr = device->BeginScene();
+ if (SUCCEEDED(hr))
+ DoRender();
+ else
+ need_change=1;
+ }
+ }
+ EndPaint(hwnd, &p);
+ return 1;
+}
+
+void Direct3DVideoOutput::Refresh()
+{
+ /* TODO: sanity check but do this
+ HRESULT hr = device->BeginScene();
+ IDirect3DSurface9 *back_buffer = 0;
+ hr = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer);
+ adjuster->adjustAspect(r);
+ hr = device->StretchRect(surface, NULL, back_buffer, &r, stretch_filter);
+ back_buffer->Release();
+ hr = device->EndScene();
+ hr = device->Present(NULL, NULL, NULL, NULL);
+ */
+ InvalidateRect(hwnd, NULL, TRUE);
+}
+
+void Direct3DVideoOutput::timerCallback()
+{
+}
+
+void Direct3DVideoOutput::drawSubtitle(SubsItem *item)
+{
+ current_subtitle = item;
+ if (current_subtitle)
+ {
+ if (!subtitle_font)
+ {
+ int font_size = 14 + item->fontSize + MulDiv(18, (last_rect.bottom - last_rect.top), 768);
+ pCreateFontW(device, font_size, 0, 400,
+
+ 1,
+ 0,
+ DEFAULT_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,//DEFAULT_QUALITY,
+ DEFAULT_PITCH,
+ L"Arial",
+ &subtitle_font);
+ }
+
+ if (subtitle_font)
+ {
+ // TODO: make an AutoWideDup and use during rendering also, saves some mallocs
+ AutoWide wide_text(item->text, CP_UTF8);
+ if (wide_text)
+ subtitle_font->PreloadTextW(wide_text, lstrlenW(wide_text));
+ // TODO: DT_CALCRECT
+ }
+ }
+}
+
+void Direct3DVideoOutput::resetSubtitle()
+{
+ current_subtitle = 0;
+}
+
+void Direct3DVideoOutput::setPalette(RGBQUAD *pal)
+{
+ /* benski> can't get D3DFMT_P8 surfaces to use this during StretchRect, so I'll just forget about it
+ for (int i=0;i<256;i++)
+ {
+ pal[i].rgbReserved = 0xFF;
+ }
+ HRESULT hr = device->SetPaletteEntries(0, (CONST PALETTEENTRY *)pal);
+ hr = device->SetCurrentTexturePalette(0);
+ hr = device->SetPaletteEntries(0, (CONST PALETTEENTRY *)pal);*/
+ m_palette = pal;
+} \ No newline at end of file
diff --git a/Src/Winamp/vid_d3d.h b/Src/Winamp/vid_d3d.h
new file mode 100644
index 00000000..9bde7919
--- /dev/null
+++ b/Src/Winamp/vid_d3d.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "VideoOutputChild.h"
+#include <d3d9.h>
+#include <d3dx9.h>
+
+typedef HRESULT (WINAPI *D3DXCREATEFONTW)(LPDIRECT3DDEVICE9, INT, UINT, UINT, UINT, BOOL, DWORD, DWORD, DWORD, DWORD, LPCWSTR, LPD3DXFONT *);
+extern D3DXCREATEFONTW pCreateFontW;
+
+class Direct3DVideoOutput
+{
+public:
+ Direct3DVideoOutput(HWND hwnd, VideoAspectAdjuster *_adjuster);
+ int OpenVideo(int w, int h, unsigned int type, int flipit, double aspectratio);
+ void OnWindowSize();
+
+ int onPaint(HWND hwnd);
+ void displayFrame(const char *buf, int size, int time);
+ void close(); // hides any output of the video
+ void timerCallback();
+ void setPalette(RGBQUAD *pal);
+ void drawSubtitle(SubsItem *item);
+ void resetSubtitle();
+ void setVFlip(int on);
+ void Refresh();
+
+private:
+ HRESULT DoRender();
+ bool FindSuitableConversion(UINT adapter, D3DFORMAT output_format);
+ D3DDEVTYPE GetDeviceType(IDirect3D9 *d3d, UINT display_adapter);
+ IDirect3D9 *d3d;
+ IDirect3D9Ex *d3dEx;
+ IDirect3DDevice9 *device;
+ IDirect3DDevice9Ex *deviceEx;
+ IDirect3DSurface9 *surface, *logo_surface;
+ ID3DXFont *subtitle_font;
+ D3DFORMAT surface_type;
+ D3DSWAPEFFECT swap_effect;
+ int input_type;
+ int width, height;
+ VideoAspectAdjuster *adjuster;
+ HWND hwnd;
+ RECT last_rect;
+ int flip;
+ UINT display_adapter;
+ SubsItem *current_subtitle;
+ bool opened, valid_surface;
+ int need_change;
+ D3DTEXTUREFILTERTYPE stretch_filter;
+
+ RGBQUAD *m_palette;
+}; \ No newline at end of file
diff --git a/Src/Winamp/vid_ddraw.cpp b/Src/Winamp/vid_ddraw.cpp
new file mode 100644
index 00000000..42c81c58
--- /dev/null
+++ b/Src/Winamp/vid_ddraw.cpp
@@ -0,0 +1,980 @@
+#include <ddraw.h>
+#include <multimon.h>
+#include "main.h"
+#include "vid_subs.h"
+#include "vid_ddraw.h"
+#include "directdraw.h"
+#include "WinampAttributes.h"
+#include "../nsutil/image.h"
+
+DDrawVideoOutput ddrawVideo;
+#define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
+
+DDrawVideoOutput::DDrawVideoOutput()
+{
+ lpDD = NULL;
+ lpddsOverlay = NULL;
+ lastresizerect.bottom = 0;
+ lastresizerect.top = 0;
+ lastresizerect.left = 0;
+ lastresizerect.right = 0;
+
+ lpddsPrimary = NULL;
+ lpddsClipper = NULL;
+ lpddsSTTemp = NULL;
+
+ width = height = flip = 0;
+ type = VIDEO_MAKETYPE('Y', 'V', '1', '2');
+ uDestSizeAlign = uSrcSizeAlign = 0;
+ dwUpdateFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
+ m_depth = 16;
+
+ initing = false;
+ needchange = 0;
+ m_palette = NULL;
+ m_lastsubtitle = NULL;
+ sttmp_w = sttmp_h = 0;
+ subFont = NULL;
+ m_sub_needremeasure = 0;
+ m_fontsize = 0;
+ memset(&winRect, 0, sizeof(winRect));
+}
+
+void DDrawVideoOutput::close()
+{
+ if (lpddsSTTemp) lpddsSTTemp->Release(); lpddsSTTemp = 0;
+ if (lpddsPrimary) lpddsPrimary->Release(); lpddsPrimary = 0;
+ if (lpddsOverlay) lpddsOverlay->Release(); lpddsOverlay = 0;
+ if (lpddsClipper) lpddsClipper->Release(); lpddsClipper = 0;
+ if (lpDD) lpDD->Release(); lpDD = 0;// BU added NULL check in response to talkback
+ if (subFont) DeleteObject(subFont); subFont = 0;
+// removeFullScreen();
+}
+DDrawVideoOutput::~DDrawVideoOutput()
+{
+ DDrawVideoOutput::close();
+}
+
+void DDrawVideoOutput::drawSubtitle(SubsItem *item)
+{
+ m_lastsubtitle = item;
+ m_sub_needremeasure = 1;
+}
+
+int DDrawVideoOutput::create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int ptype, int flipit, double aspectratio)
+{
+ needchange = 0;
+ this->parent = parent;
+ m_lastsubtitle = NULL;
+ type = ptype;
+ width = w;
+ height = h;
+ flip = flipit;
+ adjuster = _adjuster;
+
+ initing = true;
+ HWND hwnd = this->parent;
+
+ if (lpDD) lpDD->Release();
+ lpDD = NULL;
+
+ update_monitor_coords();
+
+ if (_DirectDrawCreate)
+ {
+ if (!foundGUID) _DirectDrawCreate(NULL, &lpDD, NULL);
+ else _DirectDrawCreate(&m_devguid, &lpDD, NULL);
+ }
+
+ if (!lpDD)
+ {
+ initing = false;
+ return 0;
+ }
+
+ lpDD->SetCooperativeLevel(hwnd, DDSCL_NOWINDOWCHANGES | DDSCL_NORMAL);
+
+ DDSURFACEDESC ddsd;
+ INIT_DIRECTDRAW_STRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ HRESULT ddrval = lpDD->CreateSurface(&ddsd, &lpddsPrimary, NULL);
+
+ if (FAILED(ddrval) || !lpddsPrimary)
+ {
+ initing = false;
+ return 0;
+ }
+
+ HRESULT v = -1;
+ DDSURFACEDESC DDsd = {sizeof(DDsd), };
+ lpddsPrimary->GetSurfaceDesc(&ddsd);
+ DDsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; //create the surface at screen depth
+ DDsd.dwWidth = w;
+ DDsd.dwHeight = h;
+ DDsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN;
+ if (config_video_ddraw) v = lpDD->CreateSurface(&DDsd, &lpddsOverlay, NULL);
+ if (!config_video_ddraw || FAILED(v))
+ {
+ // fall back to system memory if video mem doesn't work
+ DDsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
+ v = lpDD->CreateSurface(&DDsd, &lpddsOverlay, NULL);
+ }
+ if (FAILED(v))
+ {
+ // this video card sucks then :)
+ lpddsOverlay = NULL;
+ initing = false;
+ return 0;
+ }
+
+ // get the depth
+ m_depth = 8;
+ INIT_DIRECTDRAW_STRUCT(m_ddpf);
+ if (lpddsOverlay->GetPixelFormat(&m_ddpf) >= 0)
+ {
+ m_depth = m_ddpf.dwRGBBitCount;
+ if (m_depth == 16 && m_ddpf.dwGBitMask == 0x03e0) m_depth = 15;
+ }
+
+ if (lpDD->CreateClipper(0, &lpddsClipper, NULL) != DD_OK)
+ {
+ lpddsClipper = NULL;
+ initing = false;
+ return 0;
+ }
+
+ lpddsClipper->SetHWnd(0, hwnd);
+ lpddsPrimary->SetClipper(lpddsClipper);
+ initing = false;
+
+ //get current monitor
+ getViewport(&m_monRect, hwnd, 1, NULL);
+
+ return 1;
+}
+
+bool DDrawVideoOutput::Paint(HWND hwnd)
+{
+ RECT r;
+ GetClientRect(hwnd, &r);
+ RECT fullr = r;
+ adjuster->adjustAspect(r);
+ if (r.left != lastresizerect.left || r.right != lastresizerect.right || r.top != lastresizerect.top ||
+ r.bottom != lastresizerect.bottom)
+ {
+ if (r.left != 0)
+ {
+ RECT tmp = {0, 0, r.left, fullr.bottom};
+ InvalidateRect(hwnd, &tmp, TRUE);
+ }
+
+ if (r.right != fullr.right)
+ {
+ RECT tmp = {r.right, 0, fullr.right, fullr.bottom};
+ InvalidateRect(hwnd, &tmp, TRUE);
+ }
+ if (r.top != 0)
+ {
+ RECT tmp = {r.left, 0, r.right, r.top};
+ InvalidateRect(hwnd, &tmp, TRUE);
+ }
+ if (r.bottom != fullr.bottom)
+ {
+ RECT tmp = {r.left, r.bottom, r.right, fullr.bottom};
+ InvalidateRect(hwnd, &tmp, TRUE);
+ }
+
+ lastresizerect = r;
+ }
+
+ ClientToScreen(hwnd, (LPPOINT)&r);
+ ClientToScreen(hwnd, ((LPPOINT)&r) + 1);
+
+ // transform coords from windows desktop coords (where 0,0==upper-left corner of box encompassing all monitors)
+ // to the coords for the monitor we're displaying on:
+ r.left -= m_mon_x;
+ r.right -= m_mon_x;
+ r.top -= m_mon_y;
+ r.bottom -= m_mon_y;
+
+ HDC hdc = NULL;
+ HDC inhdc = NULL;
+
+ RECT *pSrcRect = NULL;
+
+
+ int needst = 0;
+
+
+ SubsItem *mlst = m_lastsubtitle;
+ if (mlst)
+ {
+ int curw = r.right - r.left, curh = r.bottom - r.top;
+ if (!lpddsSTTemp || sttmp_w != curw || sttmp_h != curh)
+ {
+ if (lpddsSTTemp) lpddsSTTemp->Release();
+ lpddsSTTemp = 0;
+
+ HRESULT v = -1;
+ DDSURFACEDESC DDsd = {sizeof(DDsd), };
+ DDSURFACEDESC ddsd;
+ INIT_DIRECTDRAW_STRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ lpddsPrimary->GetSurfaceDesc(&ddsd);
+ DDsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; //create the surface at screen depth
+ DDsd.dwWidth = sttmp_w = curw;
+ DDsd.dwHeight = sttmp_h = curh;
+ DDsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
+ if (config_video_ddraw) v = lpDD->CreateSurface(&DDsd, &lpddsSTTemp, NULL);
+ if (!config_video_ddraw || FAILED(v))
+ {
+ // fall back to system memory if video mem doesn't work
+ DDsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
+ lpDD->CreateSurface(&DDsd, &lpddsSTTemp, NULL);
+ }
+ m_sub_needremeasure = 1;
+ }
+ if (lpddsSTTemp) needst = 1;
+ }
+
+ if (needst)
+ {
+ HDC tmpdc = NULL;
+ if (!config_video_ddraw || lpddsSTTemp->Blt(NULL, lpddsOverlay, NULL, DDBLT_WAIT, 0) != DD_OK)
+ {
+ // as a last resort, BitBlt().
+ HDC tmpdc2;
+ if (lpddsOverlay->GetDC(&tmpdc2) == DD_OK)
+ {
+ if (lpddsSTTemp->GetDC(&tmpdc) == DD_OK)
+ {
+ BitBlt(tmpdc, 0, 0, sttmp_w, sttmp_h, tmpdc2, 0, 0, SRCCOPY);
+ }
+ }
+ }
+
+ if (mlst && (tmpdc || lpddsSTTemp->GetDC(&tmpdc) == DD_OK))
+ {
+ int m_lastsubxp = mlst->xPos;
+ int m_lastsubyp = mlst->yPos;
+
+ RECT oldwinRect = winRect;
+ GetClientRect(hwnd, &winRect);
+ if (!subFont || ((winRect.bottom - winRect.top) != (oldwinRect.bottom - oldwinRect.top)) || m_fontsize != mlst->fontSize)
+ {
+ if (subFont) DeleteObject(subFont);
+ m_fontsize = mlst->fontSize;
+ subFont = CreateFontA(14 + m_fontsize + 18 * (winRect.bottom - winRect.top) / 768, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
+ }
+
+ HGDIOBJ oldobj = SelectObject(tmpdc, subFont);
+
+ int centerflags = 0;
+ if (m_lastsubxp < 127) centerflags |= DT_LEFT;
+ else if (m_lastsubxp > 127) centerflags |= DT_RIGHT;
+ else centerflags |= DT_CENTER;
+
+ if (m_lastsubyp < 127) centerflags |= DT_TOP;
+ else if (m_lastsubyp > 127) centerflags |= DT_BOTTOM;
+
+ if (m_sub_needremeasure && mlst)
+ {
+ subRect = r;
+ subRect.bottom -= subRect.top;
+ subRect.right -= subRect.left;
+ subRect.top = subRect.left = 0;
+
+ SIZE s;
+ GetTextExtentPoint32A(tmpdc, mlst->text, lstrlenA(mlst->text), &s);
+
+ // calcul for multiline text
+ const char *p = mlst->text;
+ int n = 0;
+ while (*p != 0) if (*p++ == '\n') n++;
+ if (n) s.cy *= (n + 1);
+
+ if (m_lastsubxp > 127) // towards the right
+ {
+ subRect.right -= ((subRect.right - subRect.left) * (255 - m_lastsubxp)) / 256;
+ }
+ else if (m_lastsubxp < 127)
+ {
+ subRect.left += ((subRect.right - subRect.left) * m_lastsubxp) / 256;
+ }
+
+ subRect.top += ((subRect.bottom - s.cy - subRect.top) * m_lastsubyp) / 255;
+
+ subRect.bottom = subRect.top + s.cy;
+ }
+
+ SetBkMode(tmpdc, TRANSPARENT);
+
+ // draw outline
+ SetTextColor(tmpdc, RGB(0, 0, 0));
+ int y = 1;
+ int x = 1;
+ RECT r2 = {subRect.left + x, subRect.top + y, subRect.right + x, subRect.bottom + y};
+ if (mlst)
+ {
+ DrawTextA(tmpdc, mlst->text, -1, &r2, centerflags | DT_NOCLIP | DT_NOPREFIX);
+ // draw text
+ SetTextColor(tmpdc, RGB(mlst->colorRed, mlst->colorGreen, mlst->colorBlue));
+ DrawTextA(tmpdc, mlst->text, -1, &subRect, centerflags | DT_NOCLIP | DT_NOPREFIX);
+ }
+ SelectObject(tmpdc, oldobj);
+ lpddsSTTemp->ReleaseDC(tmpdc);
+ }
+ if (!config_video_ddraw || lpddsPrimary->Blt(&r, lpddsSTTemp, pSrcRect, DDBLT_WAIT, 0) != DD_OK)
+ {
+ // as a last resort, BitBlt().
+ if (lpddsOverlay->GetDC(&inhdc) != DD_OK)
+ {
+ needchange = 1;
+ return false;
+ }
+ if (lpddsPrimary->GetDC(&hdc) != DD_OK)
+ {
+ lpddsOverlay->ReleaseDC(inhdc); inhdc = NULL;
+ needchange = 1;
+ return false;
+ }
+
+ int src_w = width;
+ int src_h = pSrcRect ? (pSrcRect->bottom - pSrcRect->top) : height;
+ if (r.right - r.left == src_w && r.bottom - r.top == src_h)
+ BitBlt(hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, inhdc, 0, 0, SRCCOPY);
+ else
+ StretchBlt(hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, inhdc, 0, 0, src_w, src_h, SRCCOPY);
+ }
+ }
+ else
+ {
+ if (!config_video_ddraw || lpddsPrimary->Blt(&r, lpddsOverlay, pSrcRect, DDBLT_WAIT, 0) != DD_OK)
+ {
+ // as a last resort, BitBlt().
+ if (lpddsOverlay->GetDC(&inhdc) != DD_OK)
+ {
+ needchange = 1;
+ return false;
+ }
+ if (lpddsPrimary->GetDC(&hdc) != DD_OK)
+ {
+ lpddsOverlay->ReleaseDC(inhdc); inhdc = NULL;
+ needchange = 1;
+ return false;
+ }
+
+ int src_w = width;
+ int src_h = pSrcRect ? (pSrcRect->bottom - pSrcRect->top) : height;
+ if (r.right - r.left == src_w && r.bottom - r.top == src_h)
+ BitBlt(hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, inhdc, 0, 0, SRCCOPY);
+ else
+ StretchBlt(hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, inhdc, 0, 0, src_w, src_h, SRCCOPY);
+ }
+ }
+
+ if (hdc)
+ {
+ lpddsPrimary->ReleaseDC(hdc); hdc = NULL;
+ }
+ if (inhdc)
+ {
+ lpddsOverlay->ReleaseDC(inhdc); inhdc = NULL;
+ }
+
+ return true;
+}
+
+int DDrawVideoOutput::onPaint(HWND hwnd)
+{
+ // reblit the last frame
+ if (lpddsPrimary)
+ {
+ PAINTSTRUCT p;
+ BeginPaint(hwnd, &p);
+
+ RECT r;
+
+ GetClientRect(hwnd, &r);
+
+ HRGN hrgn = CreateRectRgnIndirect(&r);
+ HBRUSH b = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ FillRgn(p.hdc, hrgn, b);
+ DeleteObject(b);
+ DeleteObject(hrgn);
+
+ if (Paint(hwnd))
+ {
+ EndPaint(hwnd, &p);
+
+ return 1;
+ }
+ EndPaint(hwnd, &p);
+ }
+ return 0;
+
+}
+
+bool DDrawVideoOutput::LockSurface(DDSURFACEDESC *dd)
+{
+ for (;;Sleep(0))
+ {
+ HRESULT hr = lpddsOverlay->Lock(0, dd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
+
+ if (dd->lpSurface)
+ break;
+
+ if (hr == DDERR_SURFACELOST)
+ {
+ lpddsPrimary->Restore();
+ lpddsOverlay->Restore();
+ hr = lpddsOverlay->Lock(0, dd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
+ if (hr == DDERR_SURFACELOST)
+ return false;
+ }
+ else if (hr != DDERR_WASSTILLDRAWING)
+ return false;
+ }
+
+ return true;
+}
+
+void DDrawVideoOutput::displayFrame(const char *buf, int size, int time)
+{
+ DDSURFACEDESC dd = {sizeof(dd), };
+ if (config_video_vsync2) lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
+
+ if (!LockSurface(&dd))
+ {
+ needchange = 1;
+ return ;
+ }
+ if (type == VIDEO_MAKETYPE('Y', 'V', '1', '2'))
+ {
+ const YV12_PLANES *planes = (YV12_PLANES *)buf;
+ // convert yv12 to rgb
+ int bytes = m_depth >> 3;
+ if (m_depth == 15) bytes = 2;
+ int i, j, y00, y01, y10, y11, u, v;
+ unsigned char *pY = (unsigned char *)planes->y.baseAddr;
+ unsigned char *pU = (unsigned char *)planes->u.baseAddr;
+ unsigned char *pV = (unsigned char *)planes->v.baseAddr;
+ unsigned char *pOut = (unsigned char*)dd.lpSurface;
+ const int rvScale = (int)(2.017 * 65536.0); //91881;
+ const int gvScale = - (int)(0.392 * 65536.0); // -22553;
+ const int guScale = - (int)(0.813 * 65536.0); // -46801;
+ const int buScale = (int)(1.596 * 65536.0); //116129;
+ const int yScale = (int)(1.164 * 65536.0); //(1.164*65536.0);
+ int addOut = dd.lPitch * 2 - width * bytes;
+ int yrb = planes->y.rowBytes;
+ int addL = dd.lPitch;
+
+ /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
+#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
+
+ if (flip)
+ {
+ pOut += (dd.lPitch) * (height - 1);
+ addOut = -dd.lPitch * 2 - width * bytes;
+ addL = -addL;
+ }
+
+ for (j = 0; j <= height - 2; j += 2)
+ {
+ for (i = 0; i <= width - 2; i += 2)
+ {
+ y00 = *pY - 16;
+ y01 = *(pY + 1) - 16;
+ y10 = *(pY + yrb) - 16;
+ y11 = *(pY + yrb + 1) - 16;
+ u = (*pU++) - 128;
+ v = (*pV++) - 128;
+
+ {
+ int r, g, b;
+
+ g = guScale * v + gvScale * u;
+ r = buScale * v;
+ b = rvScale * u;
+
+ y00 *= yScale; y01 *= yScale;
+ y10 *= yScale; y11 *= yScale;
+
+ switch (m_depth)
+ {
+ case 15:
+ {
+ unsigned short *rgb = (unsigned short *)pOut;
+ rgb[0] = ((LIMIT(r + y00) >> 3) << 10) | ((LIMIT(g + y00) >> 3) << 5) | (LIMIT(b + y00) >> 3);
+ rgb[1] = ((LIMIT(r + y01) >> 3) << 10) | ((LIMIT(g + y01) >> 3) << 5) | (LIMIT(b + y01) >> 3);
+ rgb += addL / 2;
+ rgb[0] = ((LIMIT(r + y10) >> 3) << 10) | ((LIMIT(g + y10) >> 3) << 5) | (LIMIT(b + y10) >> 3);
+ rgb[1] = ((LIMIT(r + y11) >> 3) << 10) | ((LIMIT(g + y11) >> 3) << 5) | (LIMIT(b + y11) >> 3);
+ }
+ break;
+ case 16:
+ {
+ unsigned short *rgb = (unsigned short *)pOut;
+ rgb[0] = ((LIMIT(r + y00) >> 3) << 11) | ((LIMIT(g + y00) >> 2) << 5) | (LIMIT(b + y00) >> 3);
+ rgb[1] = ((LIMIT(r + y01) >> 3) << 11) | ((LIMIT(g + y01) >> 2) << 5) | (LIMIT(b + y01) >> 3);
+ rgb += addL / 2;
+ rgb[0] = ((LIMIT(r + y10) >> 3) << 11) | ((LIMIT(g + y10) >> 2) << 5) | (LIMIT(b + y10) >> 3);
+ rgb[1] = ((LIMIT(r + y11) >> 3) << 11) | ((LIMIT(g + y11) >> 2) << 5) | (LIMIT(b + y11) >> 3);
+ }
+ break;
+ case 24:
+ {
+ unsigned char *rgb = pOut;
+ /* Write out top two pixels */
+ rgb[0] = LIMIT(b + y00); rgb[1] = LIMIT(g + y00); rgb[2] = LIMIT(r + y00);
+ rgb[3] = LIMIT(b + y01); rgb[4] = LIMIT(g + y01); rgb[5] = LIMIT(r + y01);
+
+ /* Skip down to next line to write out bottom two pixels */
+ rgb += addL;
+ rgb[0] = LIMIT(b + y10); rgb[1] = LIMIT(g + y10); rgb[2] = LIMIT(r + y10);
+ rgb[3] = LIMIT(b + y11); rgb[4] = LIMIT(g + y11); rgb[5] = LIMIT(r + y11);
+ }
+ break;
+ case 32:
+ {
+ unsigned char *rgb = pOut;
+ /* Write out top two pixels */
+ rgb[0] = LIMIT(b + y00); rgb[1] = LIMIT(g + y00); rgb[2] = LIMIT(r + y00);
+ rgb[4] = LIMIT(b + y01); rgb[5] = LIMIT(g + y01); rgb[6] = LIMIT(r + y01);
+
+ /* Skip down to next line to write out bottom two pixels */
+ rgb += addL;
+ rgb[0] = LIMIT(b + y10); rgb[1] = LIMIT(g + y10); rgb[2] = LIMIT(r + y10);
+ rgb[4] = LIMIT(b + y11); rgb[5] = LIMIT(g + y11); rgb[6] = LIMIT(r + y11);
+ }
+ break;
+ }
+ }
+
+ pY += 2;
+ pOut += 2 * bytes;
+ }
+ pY += yrb + yrb - width;
+ pU += planes->u.rowBytes - width / 2;
+ pV += planes->v.rowBytes - width / 2;
+ pOut += addOut;
+ }
+ }
+ else if (type == VIDEO_MAKETYPE('R', 'G', '3', '2'))
+ {
+ //FUCKO: do we need to support 8bits depth?
+ switch (m_depth)
+ {
+ case 15:
+ { // convert RGB32 -> RGB16 (555)
+ const char *a = buf;
+ char *b = (char *)dd.lpSurface;
+ int l = width * 4, l2 = dd.lPitch;
+ int ladj = l;
+ if (flip)
+ {
+ a += l * (height - 1); ladj = -ladj;
+ }
+ for (int i = 0;i < height;i++)
+ {
+ short *dest = (short *)b;
+ int *src = (int *)a;
+ for (int j = 0;j < width;j++)
+ {
+ int c = *(src++);
+ int r = c >> 16;
+ int g = (c >> 8) & 0xff;
+ int b = (c) & 0xff;
+ *(dest++) = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+ }
+ a += ladj; b += l2;
+ }
+ }
+ break;
+ case 16:
+ { // convert RGB32 -> RGB16
+ //FUCKO: this assumes 565
+ const char *a = buf;
+ char *b = (char *)dd.lpSurface;
+ int l = width * 4, l2 = dd.lPitch;
+ int ladj = l;
+ if (flip)
+ {
+ a += l * (height - 1); ladj = -ladj;
+ }
+ for (int i = 0;i < height;i++)
+ {
+ short *dest = (short *)b;
+ int *src = (int *)a;
+ for (int j = 0;j < width;j++)
+ {
+ //FUCKO: optimize here
+ int c = *(src++);
+ int r = c >> 16;
+ int g = (c >> 8) & 0xff;
+ int b = (c) & 0xff;
+ *(dest++) = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+ }
+ a += ladj; b += l2;
+ }
+ }
+ break;
+ case 24:
+ { // convert RGB32 -> RGB24
+ const char *a = buf;
+ char *b = (char *)dd.lpSurface;
+ int l = width * 4, l2 = dd.lPitch;
+ int ladj = l;
+ if (flip)
+ {
+ a += l * (height - 1); ladj = -ladj;
+ }
+ for (int i = 0;i < height;i++)
+ {
+ char *dest = (char *)b;
+ int *src = (int *)a;
+ for (int j = 0;j < width;j++)
+ {
+ //FUCKO: optimize here
+ int c = *(src++);
+ int r = c >> 16;
+ int g = (c >> 8) & 0xff;
+ int b = (c) & 0xff;
+ *dest++ = b;
+ *dest++ = g;
+ *dest++ = r;
+ }
+ a += ladj; b += l2;
+ }
+ }
+ break;
+ case 32:
+ { // straight RGB32 copy
+ if (flip)
+ nsutil_image_CopyFlipped_U8((uint8_t *)dd.lpSurface, dd.lPitch, (const uint8_t *)buf, width*4, width, height);
+ else
+ nsutil_image_Copy_U8((uint8_t *)dd.lpSurface, dd.lPitch, (const uint8_t *)buf, width*4, width, height);
+ }
+ break;
+ }
+ }
+ else if (type == VIDEO_MAKETYPE('Y', 'U', 'Y', '2') || type == VIDEO_MAKETYPE('U', 'Y', 'V', 'Y'))
+ {
+ //const char *a = buf;
+ char *b = (char *)dd.lpSurface;
+ int /*l = width * 2, */l2 = dd.lPitch;
+ if (flip)
+ {
+ b += (height - 1) * l2;
+ l2 = -l2;
+ }
+ switch (m_depth)
+ {
+ case 15:
+ {
+ // yuy2->rgb16 (555) conversion
+ unsigned char *src = (unsigned char *)buf;
+ unsigned short *dst = (unsigned short *)dd.lpSurface;
+ int line, col; //, linewidth;
+ int y, yy;
+ int u, v;
+ int vr, ug, vg, ub;
+ unsigned char *py, *pu, *pv;
+
+ //linewidth = width - (width >> 1);
+ py = src;
+ pu = src + 1;
+ pv = src + 3;
+
+ int pitchadd = dd.lPitch / 2 - width;
+
+ for (line = 0; line < height; line++)
+ {
+ for (col = 0; col < width; col++)
+ {
+#undef LIMIT
+#define LIMIT(x) ( (x) > 0xffff ? 0xff : ( (x) <= 0xff ? 0 : ( (x) >> 8 ) ) )
+
+ y = *py;
+ yy = y << 8;
+ u = *pu - 128;
+ ug = 88 * u;
+ ub = 454 * u;
+ v = *pv - 128;
+ vg = 183 * v;
+ vr = 359 * v;
+
+ unsigned char b = LIMIT(yy + ub);
+ unsigned char g = LIMIT(yy - ug - vg);
+ unsigned char r = LIMIT(yy + vr);
+ *(dst++) = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+
+ py += 2;
+ if ((col & 1) == 1)
+ {
+ pu += 4; // skip yvy every second y
+ pv += 4; // skip yuy every second y
+ }
+ } // ..for col
+ dst += pitchadd;
+ } /* ..for line */
+ }
+ break;
+ case 16:
+ {
+ // yuy2->rgb16 conversion
+ //FUCKO: only supports 565
+ unsigned char *src = (unsigned char *)buf;
+ unsigned short *dst = (unsigned short *)dd.lpSurface;
+ int line, col; //, linewidth;
+ int y, yy;
+ int u, v;
+ int vr, ug, vg, ub;
+ unsigned char *py, *pu, *pv;
+
+ //linewidth = width - (width >> 1);
+ py = src;
+ pu = src + 1;
+ pv = src + 3;
+
+ int pitchadd = dd.lPitch / 2 - width;
+
+ for (line = 0; line < height; line++)
+ {
+ for (col = 0; col < width; col++)
+ {
+#undef LIMIT
+#define LIMIT(x) ( (x) > 0xffff ? 0xff : ( (x) <= 0xff ? 0 : ( (x) >> 8 ) ) )
+
+ y = *py;
+ yy = y << 8;
+ u = *pu - 128;
+ ug = 88 * u;
+ ub = 454 * u;
+ v = *pv - 128;
+ vg = 183 * v;
+ vr = 359 * v;
+
+ unsigned char b = LIMIT(yy + ub);
+ unsigned char g = LIMIT(yy - ug - vg);
+ unsigned char r = LIMIT(yy + vr);
+ *(dst++) = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+
+ py += 2;
+ if ((col & 1))
+ {
+ pu += 4; // skip yvy every second y
+ pv += 4; // skip yuy every second y
+ }
+ } // ..for col
+ dst += pitchadd;
+ } /* ..for line */
+ }
+ break;
+ case 24:
+ {
+ // yuy2->rgb24 conversion
+ unsigned char *src = (unsigned char *)buf;
+ unsigned char *dst = (unsigned char *)dd.lpSurface;
+ int line, col; //, linewidth;
+ int y, yy;
+ int u, v;
+ int vr, ug, vg, ub;
+ unsigned char *py, *pu, *pv;
+
+ //linewidth = width - (width >> 1);
+ py = src;
+ pu = src + 1;
+ pv = src + 3;
+
+ int pitchadd = dd.lPitch - (width * 3);
+
+ for (line = 0; line < height; line++)
+ {
+ for (col = 0; col < width; col++)
+ {
+#undef LIMIT
+#define LIMIT(x) ( (x) > 0xffff ? 0xff : ( (x) <= 0xff ? 0 : ( (x) >> 8 ) ) )
+
+ y = *py;
+ yy = y << 8;
+ u = *pu - 128;
+ ug = 88 * u;
+ ub = 454 * u;
+ v = *pv - 128;
+ vg = 183 * v;
+ vr = 359 * v;
+
+ *(dst++) = LIMIT(yy + ub);
+ *(dst++) = LIMIT(yy - ug - vg);
+ *(dst++) = LIMIT(yy + vr);
+
+ py += 2;
+ if ((col & 1) == 1)
+ {
+ pu += 4; // skip yvy every second y
+ pv += 4; // skip yuy every second y
+ }
+ } // ..for col
+ dst += pitchadd;
+ } /* ..for line */
+ }
+ break;
+ case 32:
+ {
+ // yuy2->rgb32 conversion
+ unsigned char *src = (unsigned char *)buf;
+ unsigned char *dst = (unsigned char *)dd.lpSurface;
+ int line, col; //, linewidth;
+ int y, yy;
+ int u, v;
+ int vr, ug, vg, ub;
+ unsigned char *py, *pu, *pv;
+
+ //linewidth = width - (width >> 1);
+ py = src;
+ pu = src + 1;
+ pv = src + 3;
+
+ int pitchadd = dd.lPitch - (width * 4);
+
+ for (line = 0; line < height; line++)
+ {
+ for (col = 0; col < width; col++)
+ {
+#undef LIMIT
+#define LIMIT(x) ( (x) > 0xffff ? 0xff : ( (x) <= 0xff ? 0 : ( (x) >> 8 ) ) )
+
+ y = *py;
+ yy = y << 8;
+ u = *pu - 128;
+ ug = 88 * u;
+ ub = 454 * u;
+ v = *pv - 128;
+ vg = 183 * v;
+ vr = 359 * v;
+
+ *dst++ = LIMIT(yy + ub); // b
+ *dst++ = LIMIT(yy - ug - vg); // g
+ *dst++ = LIMIT(yy + vr); // r
+ dst++;
+
+ py += 2;
+ if ((col & 1) == 1)
+ {
+ pu += 4; // skip yvy every second y
+ pv += 4; // skip yuy every second y
+ }
+ } // ..for col
+ dst += pitchadd;
+ } /* ..for line */
+ }
+ break;
+ }
+ }
+ else if (type == VIDEO_MAKETYPE('R', 'G', '2', '4'))
+ {
+ //FUCKO: only ->RGB32 conversion supported
+ switch (m_depth)
+ {
+ case 32:
+ {
+ if (flip)
+ nsutil_image_ConvertFlipped_RGB24_RGB32((RGB32 *)dd.lpSurface, dd.lPitch, (const uint8_t *)buf, width*3, width, height);
+ else
+ nsutil_image_Convert_RGB24_RGB32((RGB32 *)dd.lpSurface, dd.lPitch, (const uint8_t *)buf, width*3, width, height);
+
+ }
+ break;
+ }
+ }
+ else if (type == VIDEO_MAKETYPE('R', 'G', 'B', '8') && m_palette)
+ {
+ unsigned char *d = (unsigned char *)dd.lpSurface;
+ int pitch = dd.lPitch;
+ unsigned char *src = (unsigned char *)buf;
+ int newwidth = (width + 3) & 0xfffc;
+ src += newwidth * height - 1;
+ for (int j = 0;j < height;j++)
+ {
+ switch (m_depth)
+ {
+ case 15:
+ case 16:
+ {
+ unsigned short *dest = (unsigned short *)d;
+ for (int i = 0;i < newwidth;i++)
+ {
+ unsigned char c = src[ -newwidth + 1 + i];
+ RGBQUAD *rgb = &m_palette[c];
+ switch (m_depth)
+ {
+ case 15: *(dest++) = ((rgb->rgbRed >> 3) << 10) | ((rgb->rgbGreen >> 3) << 5) | (rgb->rgbBlue >> 3); break;
+ case 16: *(dest++) = ((rgb->rgbRed >> 3) << 11) | ((rgb->rgbGreen >> 2) << 5) | (rgb->rgbBlue >> 3); break;
+ }
+ }
+ }
+ break;
+ case 24:
+ {
+ unsigned char *dest = d;
+ for (int i = 0;i < newwidth;i++)
+ {
+ unsigned char c = src[ -newwidth + 1 + i];
+ RGBQUAD *rgb = &m_palette[c];
+ *dest++ = rgb->rgbBlue;
+ *dest++ = rgb->rgbGreen;
+ *dest++ = rgb->rgbRed;
+ if (m_depth == 32) dest++;
+ }
+ }
+ break;
+ case 32:
+ if (flip)
+ nsutil_image_PaletteFlipped_RGB32((RGB32 *)dd.lpSurface, dd.lPitch, (const uint8_t *)buf, width, width, height, (RGB32 *)m_palette);
+ else
+ nsutil_image_Palette_RGB32((RGB32 *)dd.lpSurface, dd.lPitch, (const uint8_t *)buf, width, width, height, (RGB32 *)m_palette);
+ break;
+ }
+ d += pitch;
+ src -= newwidth;
+ }
+ }
+
+ lpddsOverlay->Unlock(&dd);
+
+
+ HWND hwnd = this->parent;
+ if (!IsWindow(hwnd)) return ;
+
+ // if(GetParent(hwnd)) hwnd=GetParent(hwnd);
+
+ Paint(hwnd);
+}
+
+
+
+void DDrawVideoOutput::timerCallback()
+{
+ //check if the video has been dragged to another monitor
+ RECT curRect;
+
+ getViewport(&curRect, parent, 1, NULL);
+ if (memcmp(&curRect, &m_monRect, sizeof(RECT)))
+ needchange = 1;
+}
+
+
+void DDrawVideoOutput::resetSubtitle()
+{
+ m_lastsubtitle = 0;
+}
+
+
+
+void DDrawVideoOutput::Refresh()
+{
+ // do nothing, we'll refresh on the next frame
+} \ No newline at end of file
diff --git a/Src/Winamp/vid_ddraw.h b/Src/Winamp/vid_ddraw.h
new file mode 100644
index 00000000..be437a1a
--- /dev/null
+++ b/Src/Winamp/vid_ddraw.h
@@ -0,0 +1,56 @@
+#ifndef _VIDEO_DDRAW_H
+#define _VIDEO_DDRAW_H
+
+#include <ddraw.h>
+#include "VideoOutputChildDDraw.h"
+
+class SubsItem;
+
+class DDrawVideoOutput : public VideoOutputChildDDraw
+{
+public:
+ DDrawVideoOutput();
+ virtual ~DDrawVideoOutput();
+ int create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int ptype, int flipit, double aspectratio);
+ int needChange() { return needchange; }
+ int onPaint(HWND hwnd);
+ void displayFrame(const char *buf, int size, int time);
+ void timerCallback();
+ void setPalette(RGBQUAD *pal) { m_palette = pal; }
+ void drawSubtitle(SubsItem *item);
+ void resetSubtitle();
+ void setVFlip(int on) { flip = on; }
+ void Refresh();
+ void close();
+private:
+ bool LockSurface(DDSURFACEDESC *dd);
+ bool Paint(HWND hwnd);
+
+ int width, height, flip;
+ int needchange;
+ unsigned int type;
+ LPDIRECTDRAW lpDD;
+ LPDIRECTDRAWSURFACE lpddsOverlay, lpddsPrimary, lpddsSTTemp;
+ int sttmp_w, sttmp_h;
+ DDCAPS capsDrv;
+ unsigned int uDestSizeAlign, uSrcSizeAlign;
+ DWORD dwUpdateFlags;
+ RECT rs, rd;
+ RECT lastresizerect;
+ bool initing;
+
+ LPDIRECTDRAWCLIPPER lpddsClipper;
+ DDPIXELFORMAT m_ddpf;
+ int m_depth;
+ RGBQUAD *m_palette;
+ HFONT subFont;
+ RECT subRect;
+ SubsItem *m_lastsubtitle;
+ int m_sub_needremeasure;
+ RECT winRect;
+ int m_fontsize;
+ RECT m_monRect;
+};
+
+extern DDrawVideoOutput ddrawVideo;
+#endif
diff --git a/Src/Winamp/vid_gdi+.cpp b/Src/Winamp/vid_gdi+.cpp
new file mode 100644
index 00000000..49eb903f
--- /dev/null
+++ b/Src/Winamp/vid_gdi+.cpp
@@ -0,0 +1,359 @@
+#include "main.h"
+#include "vid_subs.h"
+#include "vid_gdi+.h"
+#include "WinampAttributes.h"
+#include "../nu/AutoWide.h"
+#include "../nsutil/image.h"
+
+GDIPVideoOutput gdiplusVideo;
+
+static void colorspace_convert(UINT inputtype, const char * inputbuf, char * output, int flip, int width, int height);
+
+void GDIPVideoOutput::SetupGraphics()
+{
+ // create new canvas
+ if (graphics) delete graphics;
+ graphics = new Graphics(parent, FALSE);
+ graphics->Clear(Color(0));
+
+ HDC h = graphics->GetHDC();
+
+ // recreate back device context
+ if (graphicsback) delete graphicsback; // we must delete this before deleting backdc
+ if (backdc) DeleteDC(backdc);
+ backdc = CreateCompatibleDC(h);
+
+ // make sure back device context has right size and color depth
+ HBITMAP memBM = CreateCompatibleBitmap(h, winw, winh);
+ SelectObject(backdc, memBM);
+ DeleteObject(memBM);
+
+ // create back graphics canvas
+ graphicsback = new Graphics(backdc);
+ graphicsback->Clear(Color(0));
+
+ graphics->ReleaseHDC(h);
+
+ // set parameters
+ /* fuck it, all default for now.
+ graphicsback->SetInterpolationMode(InterpolationModeBilinear);
+ graphicsback->SetCompositingQuality(CompositingQualityHighSpeed);
+ graphicsback->SetCompositingMode(CompositingModeSourceCopy);
+ graphicsback->SetSmoothingMode(SmoothingModeNone);
+ */
+}
+
+GDIPVideoOutput::GDIPVideoOutput() : graphics(0), frame(0), type(0), graphicsback(0), backdc(0), w(0), h(0), flip(0), winw(0), winh(0), gdiplusToken(0), subs(0), needschange(0), parent(0), adjuster(0)
+{
+}
+
+GDIPVideoOutput::~GDIPVideoOutput()
+{
+}
+
+int GDIPVideoOutput::create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int type, int flipit, double aspectratio) //return 1 if ok
+{
+ GdiplusStartupInput gdiplusStartupInput;
+ GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+ needschange = 1;
+ adjuster = _adjuster;
+ needschange = 0;
+ RECT r;
+ GetWindowRect(parent, &r);
+ winw = r.right - r.left;
+ winh = r.bottom = r.top;
+ this->parent = parent;
+ this->flip = flipit;
+ this->w = w;
+ this->h = h;
+ this->type = type;
+ SetupGraphics();
+ frame = new Bitmap(w, h, graphicsback);
+ ZeroMemory(&lastrect, sizeof(RECT));
+ return 1;
+}
+
+// TODO: verify that this works
+bool GDIPVideoOutput::FillFrame(Bitmap * frame, void *buf)
+{
+ switch (type)
+ {
+ case VIDEO_MAKETYPE('R', 'G', '3', '2'):
+ {
+ BITMAPINFO info;
+ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info.bmiHeader.biWidth = w;
+ info.bmiHeader.biHeight = h;
+ info.bmiHeader.biPlanes = 1;
+ info.bmiHeader.biBitCount = 32;
+ info.bmiHeader.biCompression = BI_RGB;
+ info.bmiHeader.biSizeImage = 0;
+ info.bmiHeader.biXPelsPerMeter = 0;
+ info.bmiHeader.biYPelsPerMeter = 0;
+ info.bmiHeader.biXPelsPerMeter = 0;
+ info.bmiHeader.biYPelsPerMeter = 0;
+ info.bmiHeader.biClrUsed = 0;
+ info.bmiHeader.biClrImportant = 0;
+
+ frame->FromBITMAPINFO(&info, buf);
+
+ }
+ return true;
+ case VIDEO_MAKETYPE('R', 'G', '2', '4'):
+ {
+ BITMAPINFO info;
+ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info.bmiHeader.biWidth = w;
+ info.bmiHeader.biHeight = h;
+ info.bmiHeader.biPlanes = 1;
+ info.bmiHeader.biBitCount = 24;
+ info.bmiHeader.biCompression = BI_RGB;
+ info.bmiHeader.biSizeImage = 0;
+ info.bmiHeader.biXPelsPerMeter = 0;
+ info.bmiHeader.biYPelsPerMeter = 0;
+ info.bmiHeader.biXPelsPerMeter = 0;
+ info.bmiHeader.biYPelsPerMeter = 0;
+ info.bmiHeader.biClrUsed = 0;
+ info.bmiHeader.biClrImportant = 0;
+
+ frame->FromBITMAPINFO(&info, buf);
+
+ }
+ return true;
+ }
+ return false;
+}
+
+void GDIPVideoOutput::displayFrame(const char *buf, int size, int time)
+{
+ // TODO: verify that this works before uncommenting if (!FillFrame(frame, const_cast<char *>(buf)))
+ {
+ BitmapData d;
+ d.Width = w;
+ d.Height = h;
+ d.PixelFormat = PixelFormat32bppRGB;
+ d.Stride = 4 * w;
+ d.Scan0 = 0;
+
+ // write the frame to our bitmap object
+ if (frame->LockBits(&Rect(0, 0, w, h), ImageLockModeWrite, PixelFormat32bppRGB, &d) != Ok)
+ {
+ needschange = 1; return;
+ }
+ colorspace_convert(type, buf, (char*)d.Scan0, flip, w, h);
+ frame->UnlockBits(&d);
+ }
+
+ // fix aspect ratio
+ RECT r = {0, 0, winw, winh};
+ adjuster->adjustAspect(r);
+ if (memcmp(&r, &lastrect, sizeof(RECT))) graphicsback->Clear(Color(0));
+ lastrect = r;
+
+ // draw the image
+ graphicsback->DrawImage(frame, r.left, r.top, r.right - r.left, r.bottom - r.top);
+ if (subs)
+ { // draw subtitles
+ //graphicsback->DrawString(AutoWide(subs->text),-1,&Font(L"Arial.ttf",36),PointF(subs->xPos,subs->yPos),&SolidBrush(Color(subs->colorRed,subs->colorGreen,subs->colorBlue)));
+ }
+
+ // flip graphics and graphicsback
+ HDC h = graphics->GetHDC();
+ HDC b = graphicsback->GetHDC();
+ BitBlt(h, r.left, r.top, r.right - r.left, r.bottom - r.top, b, r.left, r.top, SRCCOPY);
+ graphicsback->ReleaseHDC(b);
+ graphics->ReleaseHDC(h);
+}
+
+int GDIPVideoOutput::needChange()
+{
+ return needschange;
+}
+
+void GDIPVideoOutput::close()
+{
+ if (graphics) delete graphics; graphics = 0;
+ if (frame) delete frame; frame = 0;
+ if (graphicsback) delete graphicsback; graphicsback = 0;
+ if (backdc) DeleteDC(backdc); backdc = 0;
+ subs = 0;
+ type = 0;
+
+ GdiplusShutdown(gdiplusToken);
+}
+
+void GDIPVideoOutput::Refresh()
+{}
+
+void GDIPVideoOutput::timerCallback()
+{
+ RECT r;
+ GetWindowRect(parent, &r);
+ UINT w, h;
+ w = r.right - r.left;
+ h = r.bottom - r.top;
+ bool change = (w != winw || h != winh);
+ if (change)
+ {
+ winw = w;
+ winh = h;
+ // sizes have changed, we must reset the graphics
+ SetupGraphics();
+ }
+}
+
+//mmm. ctrl+c ctrl+v.
+static void colorspace_convert(UINT type, const char * buf, char * lpSurface, int flip, int width, int height)
+{
+ const int lPitch = width * 4;
+ if (type == VIDEO_MAKETYPE('Y', 'V', '1', '2'))
+ {
+ const YV12_PLANES *planes = (YV12_PLANES *)buf;
+ // convert yv12 to rgb
+ const int bytes = 4;
+ int i, j, y00, y01, y10, y11, u, v;
+ unsigned char *pY = (unsigned char *)planes->y.baseAddr;
+ unsigned char *pU = (unsigned char *)planes->u.baseAddr;
+ unsigned char *pV = (unsigned char *)planes->v.baseAddr;
+ unsigned char *pOut = (unsigned char*)lpSurface;
+ const int rvScale = (int)(2.017 * 65536.0); //91881;
+ const int gvScale = - (int)(0.392 * 65536.0); // -22553;
+ const int guScale = - (int)(0.813 * 65536.0); // -46801;
+ const int buScale = (int)(1.596 * 65536.0); //116129;
+ const int yScale = (int)(1.164 * 65536.0); //(1.164*65536.0);
+ int addOut = lPitch * 2 - width * bytes;
+ int yrb = planes->y.rowBytes;
+ int addL = lPitch;
+
+ /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
+#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
+
+ if (flip)
+ {
+ pOut += (lPitch) * (height - 1);
+ addOut = -lPitch * 2 - width * bytes;
+ addL = -addL;
+ }
+
+ for (j = 0; j <= height - 2; j += 2)
+ {
+ for (i = 0; i <= width - 2; i += 2)
+ {
+ y00 = *pY - 16;
+ y01 = *(pY + 1) - 16;
+ y10 = *(pY + yrb) - 16;
+ y11 = *(pY + yrb + 1) - 16;
+ u = (*pU++) - 128;
+ v = (*pV++) - 128;
+
+ {
+ int r, g, b;
+
+ g = guScale * v + gvScale * u;
+ r = buScale * v;
+ b = rvScale * u;
+
+ y00 *= yScale; y01 *= yScale;
+ y10 *= yScale; y11 *= yScale;
+
+ {
+ {
+ unsigned char *rgb = pOut;
+ /* Write out top two pixels */
+ rgb[0] = LIMIT(b + y00); rgb[1] = LIMIT(g + y00); rgb[2] = LIMIT(r + y00);
+ rgb[4] = LIMIT(b + y01); rgb[5] = LIMIT(g + y01); rgb[6] = LIMIT(r + y01);
+
+ /* Skip down to next line to write out bottom two pixels */
+ rgb += addL;
+ rgb[0] = LIMIT(b + y10); rgb[1] = LIMIT(g + y10); rgb[2] = LIMIT(r + y10);
+ rgb[4] = LIMIT(b + y11); rgb[5] = LIMIT(g + y11); rgb[6] = LIMIT(r + y11);
+ }
+ }
+ }
+
+ pY += 2;
+ pOut += 2 * bytes;
+ }
+ pY += yrb + yrb - width;
+ pU += planes->u.rowBytes - width / 2;
+ pV += planes->v.rowBytes - width / 2;
+ pOut += addOut;
+ }
+ }
+ else if (type == VIDEO_MAKETYPE('R', 'G', '3', '2'))
+ {
+ if (flip)
+ nsutil_image_CopyFlipped_U8((uint8_t *)lpSurface, lPitch, (const uint8_t *)buf, width*4, width, height);
+ else
+ nsutil_image_Copy_U8((uint8_t *)lpSurface, lPitch, (const uint8_t *)buf, width*4, width, height);
+ }
+ else if (type == VIDEO_MAKETYPE('Y', 'U', 'Y', '2') || type == VIDEO_MAKETYPE('U', 'Y', 'V', 'Y'))
+ {
+ char *b = (char *)lpSurface;
+ int l2 = lPitch;
+ if (flip)
+ {
+ b += (height - 1) * l2;
+ l2 = -l2;
+ }
+ {
+ {
+ // yuy2->rgb32 conversion
+ unsigned char *src = (unsigned char *)buf;
+ unsigned char *dst = (unsigned char *)lpSurface;
+ int line, col; //, linewidth;
+ int y, yy;
+ int u, v;
+ int vr, ug, vg, ub;
+ unsigned char *py, *pu, *pv;
+
+ //linewidth = width - (width >> 1);
+ py = src;
+ pu = src + 1;
+ pv = src + 3;
+
+ int pitchadd = lPitch - (width * 4);
+
+ for (line = 0; line < height; line++)
+ {
+ for (col = 0; col < width; col++)
+ {
+#undef LIMIT
+#define LIMIT(x) ( (x) > 0xffff ? 0xff : ( (x) <= 0xff ? 0 : ( (x) >> 8 ) ) )
+
+ y = *py;
+ yy = y << 8;
+ u = *pu - 128;
+ ug = 88 * u;
+ ub = 454 * u;
+ v = *pv - 128;
+ vg = 183 * v;
+ vr = 359 * v;
+
+ *dst++ = LIMIT(yy + ub); // b
+ *dst++ = LIMIT(yy - ug - vg); // g
+ *dst++ = LIMIT(yy + vr); // r
+ dst++;
+
+ py += 2;
+ if ((col & 1) == 1)
+ {
+ pu += 4; // skip yvy every second y
+ pv += 4; // skip yuy every second y
+ }
+ } // ..for col
+ dst += pitchadd;
+ } /* ..for line */
+ }
+ }
+ }
+ else if (type == VIDEO_MAKETYPE('R', 'G', '2', '4'))
+ {
+ if (flip)
+ nsutil_image_ConvertFlipped_RGB24_RGB32((RGB32 *)lpSurface, lPitch, (const uint8_t *)buf, width*3, width, height);
+ else
+ nsutil_image_Convert_RGB24_RGB32((RGB32 *)lpSurface, lPitch, (const uint8_t *)buf, width*3, width, height);
+
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/vid_gdi+.h b/Src/Winamp/vid_gdi+.h
new file mode 100644
index 00000000..449f87c3
--- /dev/null
+++ b/Src/Winamp/vid_gdi+.h
@@ -0,0 +1,44 @@
+#ifndef _VID_GDIPLUS_H_
+#define _VID_GDIPLUS_H_
+
+#include <windows.h>
+#include <gdiplus.h>
+#include "VideoOutputChild.h"
+
+using namespace Gdiplus;
+
+class GDIPVideoOutput : public VideoRenderer {
+public:
+ GDIPVideoOutput();
+ virtual ~GDIPVideoOutput();
+ virtual int create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int type, int flipit, double aspectratio); //return 1 if ok
+ virtual int needChange(); //return 1 if need to renegociate video output
+ virtual int onPaint(HWND hwnd) { return 0; } //return 1 if override
+ virtual void displayFrame(const char *buf, int size, int time);
+ virtual void close(); // hides any output of the video
+ virtual void timerCallback();
+ virtual void drawSubtitle(SubsItem *item) { subs=item; }
+ virtual void resetSubtitle() { subs=NULL; }
+ virtual void setVFlip(int on) { flip=on; }
+ virtual void Refresh();
+
+protected:
+ bool FillFrame(Bitmap *frame, void *buf);
+
+ unsigned int type, w, h, flip, winw, winh;
+ Graphics * graphics; // on screen canvas
+ Graphics * graphicsback; // off screen canvas
+ Bitmap * frame;
+ HWND parent;
+ int needschange;
+ VideoAspectAdjuster *adjuster;
+ RECT lastrect;
+ HDC backdc;
+ void SetupGraphics();
+ ULONG_PTR gdiplusToken;
+ SubsItem *subs;
+};
+
+extern GDIPVideoOutput gdiplusVideo;
+
+#endif // _VID_GDIPLUS_H_
diff --git a/Src/Winamp/vid_none.cpp b/Src/Winamp/vid_none.cpp
new file mode 100644
index 00000000..9271c2c9
--- /dev/null
+++ b/Src/Winamp/vid_none.cpp
@@ -0,0 +1,4 @@
+#include "main.h"
+#include "vid_none.h"
+
+NoneVideoOutput noneVideo; \ No newline at end of file
diff --git a/Src/Winamp/vid_none.h b/Src/Winamp/vid_none.h
new file mode 100644
index 00000000..655b71de
--- /dev/null
+++ b/Src/Winamp/vid_none.h
@@ -0,0 +1,21 @@
+#ifndef _VIDEO_NONE_H
+#define _VIDEO_NONE_H
+
+#include "wa_ipc.h"
+#include "VideoOutputChild.h"
+
+class NoneVideoOutput : public VideoRenderer
+{
+public:
+ int create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int type, int flipit, double aspectratio)
+ {
+ if (type == VIDEO_MAKETYPE('N', 'O', 'N', 'E')) return 1;
+ return 0;
+ }
+ void close() { }
+ int needChange() { return 0; }
+ void displayFrame(const char *buf, int size, int time) { }
+ void Refresh() {}
+};
+extern NoneVideoOutput noneVideo;
+#endif
diff --git a/Src/Winamp/vid_overlay.cpp b/Src/Winamp/vid_overlay.cpp
new file mode 100644
index 00000000..402f2159
--- /dev/null
+++ b/Src/Winamp/vid_overlay.cpp
@@ -0,0 +1,843 @@
+#include "main.h"
+#include <multimon.h>
+#include "vid_overlay.h"
+#include "vid_subs.h"
+#include "directdraw.h"
+#include "WinampAttributes.h"
+#include "../nsutil/image.h"
+#include <api.h>
+
+OverlayVideoOutput overlayVideo;
+extern "C" void getViewport(RECT *r, HWND wnd, int full, RECT *sr);
+
+#if 0
+
+#include <math.h>
+
+
+_inline long int lrintf(float flt)
+{
+ int intgr;
+
+ _asm
+ {
+ fld flt
+ fistp intgr
+ }
+
+ return intgr;
+}
+
+static float clip(float x, float a, float b)
+{
+ float x1 = fabs(x - a);
+ float x2 = fabs(x - b);
+ x = x1 + (a + b);
+ x -= x2;
+ x *= 0.5f;
+ return (x);
+}
+void DoGamma(YV12_PLANES *planes, int height)
+{
+ if (config_video_brightness != 128 || config_video_contrast != 128)
+ {
+ int x, y = height * planes->y.rowBytes;
+ float add = config_video_brightness - 128;
+ float mult = config_video_contrast / 128.f;
+
+ unsigned char *pix = planes->y.baseAddr;
+ for (x = 0; x < y; x++)
+ {
+ float value = (float) * pix;
+ value = clip(value * mult + add, 0.0f, 255.0f);
+ *pix++ = lrintf(value);
+ }
+ }
+}
+#else
+#define DoGamma(a,b)
+#endif
+
+void YV12_to_YUY2(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip)
+{
+ const unsigned char *yi = planes->y.baseAddr;
+ const unsigned char *ui = planes->u.baseAddr;
+ const unsigned char *vi = planes->v.baseAddr;
+ if (flip)
+ output += pitch * (height - 1);
+ while (height > 0)
+ {
+ int x = width;
+ unsigned char *oo = output;
+
+ while (x > 0)
+ {
+ output[0] = *yi++; output[1] = *ui++; output[2] = *yi++; output[3] = *vi++;
+ output += 4; x -= 2;
+ }
+ ui -= width / 2;
+ vi -= width / 2;
+ yi += planes->y.rowBytes - width;
+ x = width;
+ if (flip) output = oo - pitch;
+ else output += pitch - width * 2;
+ oo = output;
+ while (x > 0)
+ {
+ output[0] = *yi++; output[1] = *ui++; output[2] = *yi++; output[3] = *vi++;
+ output += 4; x -= 2;
+ }
+ if (flip) output = oo - pitch;
+ else output += pitch - width * 2;
+ ui += planes->u.rowBytes - (width / 2);
+ vi += planes->v.rowBytes - (width / 2);
+ yi += planes->y.rowBytes - width;
+ height -= 2;
+ }
+}
+
+void YV12_to_UYVY(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip)
+{
+ const unsigned char *yi = planes->y.baseAddr;
+ const unsigned char *ui = planes->u.baseAddr;
+ const unsigned char *vi = planes->v.baseAddr;
+
+ if (flip) output += pitch * (height - 1);
+ while (height > 0)
+ {
+ int x = width;
+ unsigned char *oo = output;
+
+ while (x > 0)
+ {
+ output[0] = *ui++; output[1] = *yi++; output[2] = *vi++; output[3] = *yi++;
+ output += 4; x -= 2;
+ }
+
+ ui -= width / 2;
+ vi -= width / 2;
+ yi += planes->y.rowBytes - width;
+ x = width;
+ if (flip) output = oo - pitch;
+ else output += pitch - width * 2;
+ oo = output;
+ while (x > 0)
+ {
+ output[0] = *ui++; output[1] = *yi++; output[2] = *vi++; output[3] = *yi++;
+ output += 4; x -= 2;
+ }
+
+ if (flip) output = oo - pitch;
+ else output += pitch - width * 2;
+ ui += planes->u.rowBytes - (width / 2);
+ vi += planes->v.rowBytes - (width / 2);
+ yi += planes->y.rowBytes - width;
+ height -= 2;
+ }
+}
+
+void YV12_to_YV12(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip)
+{ // woo native YV12 copy
+ if (flip)
+ {
+ nsutil_image_CopyFlipped_U8(output, pitch, planes->y.baseAddr, planes->y.rowBytes, width, height);
+ unsigned char *o = output + height * pitch;
+ nsutil_image_CopyFlipped_U8(o, pitch/2, planes->v.baseAddr, planes->v.rowBytes, width/2, height/2);
+ o = output + (height * pitch) + (height/2) * (pitch/2); // benski> because height might be an odd number, it is important NOT to simplify this equation!
+ nsutil_image_CopyFlipped_U8(o, pitch/2, planes->u.baseAddr, planes->u.rowBytes, width/2, height/2);
+ }
+ else
+ {
+ nsutil_image_Copy_U8(output, pitch, planes->y.baseAddr, planes->y.rowBytes, width, height);
+ unsigned char *o = output + height * pitch;
+ nsutil_image_Copy_U8(o, pitch/2, planes->v.baseAddr, planes->v.rowBytes, width/2, height/2);
+ o = output + (height * pitch) + (height/2) * (pitch/2); // benski> because height might be an odd number, it is important NOT to simplify this equation!
+ nsutil_image_Copy_U8(o, pitch/2, planes->u.baseAddr, planes->u.rowBytes, width/2, height/2);
+ }
+}
+
+void YUY2_to_YUY2(unsigned char *output, const char *buf, int pitch, int width, int height, int flip)
+{
+ const char *a = buf;
+ unsigned char *b = output;
+ int l = width * 2, l2 = pitch;
+ if (flip)
+ {
+ b += (height - 1) * l2;
+ l2 = -l2;
+ }
+
+ //wee straight YUY2 copy
+ for (int i = 0;i < height;i++)
+ {
+ memcpy(b, a, l);
+ b += l2;
+ a += l;
+ }
+}
+
+void YUY2_to_UYVY(unsigned char *output, const char *buf, int pitch, int width, int height, int flip)
+{
+ const char *a = buf;
+ unsigned char *b = output;
+ int l = width * 2, l2 = pitch;
+ if (flip)
+ {
+ b += (height - 1) * l2;
+ l2 = -l2;
+ }
+
+ for (int i = 0;i < height;i++)
+ {
+ int x = width / 2;
+ while (x-- > 0)
+ {
+ b[0] = a[1];
+ b[1] = a[0];
+ b[2] = a[3];
+ b[3] = a[2];
+ a += 4;
+ b += 4;
+ }
+ memcpy(b, a, l);
+ b += l2;
+ a += l;
+ }
+}
+
+#define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
+// I like to set these to 255,0,255 to test that we arent drawing this color too many playces
+#define OV_COL_R 16
+#define OV_COL_G 0
+#define OV_COL_B 16
+
+OverlayVideoOutput::OverlayVideoOutput()
+{
+ lpDD = NULL;
+ m_closed = 0;
+ overlay_color = RGB(OV_COL_R, OV_COL_G, OV_COL_B);
+ lpddsOverlay = NULL;
+ lpddsPrimary = NULL;
+ lpBackBuffer = NULL;
+
+ width = height = flip = 0;
+ type = VIDEO_MAKETYPE('Y', 'V', '1', '2');
+
+ uDestSizeAlign = 0;
+ uSrcSizeAlign = 0;
+ dwUpdateFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
+ curSubtitle = NULL;
+
+ yuy2_output = uyvy_output = 0;
+ initing = false;
+ needchange = 0;
+ memset(&m_oldrd, 0, sizeof(m_oldrd));
+ memset(&winRect, 0, sizeof(winRect));
+ subFont = NULL;
+ m_fontsize = 0;
+ resetSubtitle();
+}
+
+OverlayVideoOutput::~OverlayVideoOutput()
+{
+ OverlayVideoOutput::close();
+}
+
+static DWORD DD_ColorMatch(LPDIRECTDRAWSURFACE pdds, COLORREF rgb)
+{
+ COLORREF rgbT = CLR_INVALID;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC ddsd;
+ HRESULT hres;
+
+ //
+ // use GDI SetPixel to color match for us
+ //
+ if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // save current pixel value
+ SetPixel(hdc, 0, 0, rgb); // set our value
+ pdds->ReleaseDC(hdc);
+ }
+
+ // now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) ==
+ DDERR_WASSTILLDRAWING)
+ ;
+
+ if (hres == DD_OK)
+ {
+ dw = *(DWORD *)ddsd.lpSurface; // get DWORD
+ if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
+ dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; // mask it to bpp
+ pdds->Unlock(NULL);
+ }
+
+ // now put the color that was there back.
+ if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
+ {
+ SetPixel(hdc, 0, 0, rgbT);
+ pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+int OverlayVideoOutput::create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int ptype, int flipit, double aspectratio)
+{
+ OverlayVideoOutput::close();
+ this->parent = parent;
+ type = ptype;
+ width = w;
+ height = h;
+ flip = flipit;
+
+ adjuster = _adjuster;
+
+ initing = true;
+ HWND hwnd = this->parent;
+
+ if (lpDD) lpDD->Release();
+ lpDD = NULL;
+
+ update_monitor_coords();
+
+ if (_DirectDrawCreate)
+ {
+ if (!foundGUID) _DirectDrawCreate(NULL, &lpDD, NULL);
+ else _DirectDrawCreate(&m_devguid, &lpDD, NULL);
+ }
+
+ if (!lpDD)
+ {
+ initing = false;
+ return 0;
+ }
+
+ lpDD->SetCooperativeLevel(hwnd, DDSCL_NOWINDOWCHANGES | DDSCL_NORMAL);
+
+ DDSURFACEDESC ddsd;
+ INIT_DIRECTDRAW_STRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ lpDD->CreateSurface(&ddsd, &lpddsPrimary, NULL);
+
+ if (!lpddsPrimary)
+ {
+ if (lpDD) lpDD->Release();
+ lpDD = NULL;
+ initing = false;
+ return 0;
+ }
+
+ // init overlay
+ DDSURFACEDESC ddsdOverlay;
+ INIT_DIRECTDRAW_STRUCT(ddsdOverlay);
+ ddsdOverlay.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+ ddsdOverlay.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_BACKBUFFERCOUNT;
+ ddsdOverlay.dwBackBufferCount = 1;
+ ddsdOverlay.dwWidth = w;
+ ddsdOverlay.dwHeight = h;
+ ddsdOverlay.lPitch = w * 4;
+ DDPIXELFORMAT pf[] =
+ {
+ {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0},
+ {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0}, // UYVY
+ {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0},
+ // TODO:
+ // {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('N','V','1','2'), 12, 0, 0, 0, 0}, // NV12
+ // {sizeof(DDPIXELFORMAT), DDPF_RGB,0,16,0xf800,0x07e0,0x001f,0} // RGB565
+ };
+ int tab[5];
+ if (type == VIDEO_MAKETYPE('Y', 'U', 'Y', '2'))
+ {
+ tab[0] = 0; // default is YUY2
+ tab[1] = 1;
+ tab[2] = -1;
+ }
+ else if (type == VIDEO_MAKETYPE('U', 'Y', 'V', 'Y'))
+ {
+ tab[0] = 1; // make UYVY default
+ tab[1] = 0;
+ tab[2] = -1;
+ }
+ else if (type == VIDEO_MAKETYPE('Y', 'V', '1', '2'))
+ {
+ if (config_video_yv12)
+ {
+ tab[0] = 2;
+ tab[1] = 0;
+ tab[2] = 1;
+ tab[3] = -1;
+ }
+ else
+ {
+ //use YUY2
+ tab[0] = 0; // default is YUY2
+ tab[1] = 1;
+ tab[2] = -1;
+ }
+ }
+ else
+ {
+ tab[0] = -1; // default is RGB
+ }
+
+ int x = 4096;
+ HRESULT v = -1;
+ for (x = 0; x < sizeof(tab) / sizeof(tab[0]) && tab[x] >= 0; x ++)
+ {
+ ddsdOverlay.ddpfPixelFormat = pf[tab[x]];
+ v = lpDD->CreateSurface(&ddsdOverlay, &lpddsOverlay, NULL);
+ if (!FAILED(v)) break;
+ }
+ if (FAILED(v) || x >= sizeof(tab) / sizeof(tab[0]) || tab[x] < 0)
+ {
+ initing = false;
+ return 0;
+ }
+
+ yuy2_output = (tab[x] == 0);
+ uyvy_output = (tab[x] == 1);
+
+ //get the backbuffer surface
+ DDSCAPS ddscaps;
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+ v = lpddsOverlay->GetAttachedSurface(&ddscaps, &lpBackBuffer);
+ if (v != DD_OK || lpBackBuffer == 0)
+ {
+ //FUCKO: make it use normal vsync
+ lpBackBuffer = 0;
+ initing = FALSE;
+ return 0;
+ }
+
+ INIT_DIRECTDRAW_STRUCT(capsDrv);
+ lpDD->GetCaps(&capsDrv, NULL);
+
+ uDestSizeAlign = capsDrv.dwAlignSizeDest;
+ uSrcSizeAlign = capsDrv.dwAlignSizeSrc;
+
+ dwUpdateFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
+
+ DEVMODE d;
+ d.dmSize = sizeof(d);
+ d.dmDriverExtra = 0;
+ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &d);
+
+ int rv = OV_COL_R, gv = OV_COL_G, bv = OV_COL_B;
+ overlay_color = RGB(rv, gv, bv);
+
+ if (d.dmBitsPerPel == 8)
+ {
+ overlay_color = RGB(255, 0, 255);
+ }
+
+ INIT_DIRECTDRAW_STRUCT(ovfx);
+ ovfx.dwDDFX = 0;
+ switch (d.dmBitsPerPel)
+ {
+ case 8:
+ ovfx.dckDestColorkey.dwColorSpaceLowValue = 253;
+ break;
+ case 16:
+ ovfx.dckDestColorkey.dwColorSpaceLowValue = ((rv >> 3) << 11) | ((gv >> 2) << 5) | (bv >> 3);
+ break;
+ case 15:
+ ovfx.dckDestColorkey.dwColorSpaceLowValue = ((rv >> 3) << 10) | ((gv >> 3) << 5) | (bv >> 3);
+ break;
+ case 24: case 32:
+ ovfx.dckDestColorkey.dwColorSpaceLowValue = (rv << 16) | (gv << 8) | bv;
+ break;
+ }
+
+ //try to get the correct bit depth thru directdraw (for fucked up 16 bits displays for ie.)
+ {
+ DDSURFACEDESC DDsd = {sizeof(DDsd), };
+ lpddsPrimary->GetSurfaceDesc(&ddsd);
+ DDsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; //create the surface at screen depth
+ DDsd.dwWidth = 8;
+ DDsd.dwHeight = 8;
+ DDsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
+ LPDIRECTDRAWSURFACE tempsurf;
+ if (lpDD->CreateSurface(&DDsd, &tempsurf, NULL) == DD_OK)
+ {
+ int res = DD_ColorMatch(tempsurf, overlay_color);
+ if (res != CLR_INVALID) ovfx.dckDestColorkey.dwColorSpaceLowValue = res;
+ tempsurf->Release();
+ }
+ }
+
+ ovfx.dckDestColorkey.dwColorSpaceHighValue = ovfx.dckDestColorkey.dwColorSpaceLowValue;
+
+ getRects(&rs, &rd);
+ if (FAILED(lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx)))
+ {
+ initing = false;
+ return 0;
+ }
+ initing = false;
+
+ DDSURFACEDESC dd = {sizeof(dd), };
+ if (lpddsOverlay->Lock(NULL, &dd, DDLOCK_WAIT, NULL) != DD_OK) return 0;
+ unsigned char *o = (unsigned char*)dd.lpSurface;
+ if (uyvy_output || yuy2_output)
+ {
+ int x = dd.lPitch * height / 2;
+ while (x--)
+ {
+ if (uyvy_output)
+ {
+ *o++ = 128;
+ *o++ = 0;
+ }
+ else
+ {
+ *o++ = 0;
+ *o++ = -128;
+ }
+ }
+ }
+ else
+ {
+ memset(o, 0, dd.lPitch*height); o += dd.lPitch * height;
+ memset(o, 128, dd.lPitch*height / 2);
+ }
+ lpddsOverlay->Unlock(&dd);
+
+ m_closed = 0;
+ needchange = 0;
+ InvalidateRect(hwnd, NULL, TRUE);
+ return 1;
+}
+
+void OverlayVideoOutput::close()
+{
+ m_closed = 1;
+ if (lpddsOverlay) lpddsOverlay->UpdateOverlay(NULL, lpddsPrimary, NULL, DDOVER_HIDE , NULL);
+ if (lpBackBuffer) lpBackBuffer->Release(); lpBackBuffer = 0;
+ if (lpddsOverlay) lpddsOverlay->Release(); lpddsOverlay = 0;
+ if (lpddsPrimary) lpddsPrimary->Release(); lpddsPrimary = 0;
+ if (lpDD) lpDD->Release(); lpDD = 0; // BU added NULL check in response to talkback
+ if (subFont) DeleteObject(subFont); subFont = 0;
+}
+
+void OverlayVideoOutput::getRects(RECT *drs, RECT *drd, int fixmultimon) const
+{
+ //if(GetParent(hwnd)) hwnd=GetParent(hwnd);
+
+ RECT rd, rs;
+ GetClientRect(parent, &rd);
+ ClientToScreen(parent, (LPPOINT)&rd);
+ ClientToScreen(parent, ((LPPOINT)&rd) + 1);
+
+ adjuster->adjustAspect(rd);
+
+ rd.left -= m_mon_x;
+ rd.right -= m_mon_x;
+ rd.top -= m_mon_y;
+ rd.bottom -= m_mon_y;
+
+ memset(&rs, 0, sizeof(rs));
+ rs.right = width;
+ rs.bottom = height;
+
+ if (fixmultimon)
+ {
+ //resize overlay for off-screen
+ RECT rfull;
+ getViewport(&rfull, parent, 1, NULL);
+
+ rfull.left -= m_mon_x;
+ rfull.right -= m_mon_x;
+ rfull.top -= m_mon_y;
+ rfull.bottom -= m_mon_y;
+
+ if (rd.right > rfull.right)
+ {
+ int diff = rd.right - rfull.right;
+ float sc = (float)(width) / (float)(rd.right - rd.left);
+ rd.right = rfull.right;
+ rs.right = width - (int)(diff * sc);
+ }
+ if (rd.left < rfull.left)
+ {
+ int diff = rfull.left - rd.left;
+ float sc = (float)(width) / (float)(rd.right - rd.left);
+ rd.left = rfull.left;
+ rs.left = (int)(diff * sc);
+ }
+ if (rd.bottom > rfull.bottom)
+ {
+ int diff = rd.bottom - rfull.bottom;
+ float sc = (float)(height) / (float)(rd.bottom - rd.top);
+ rd.bottom = rfull.bottom;
+ rs.bottom = height - (int)(diff * sc);
+ }
+ if (rd.top < rfull.top)
+ {
+ int diff = rfull.top - rd.top;
+ float sc = (float)(height) / (float)(rd.bottom - rd.top);
+ rd.top = rfull.top;
+ rs.top = (int)(diff * sc);
+ }
+ }
+
+ if (capsDrv.dwCaps & DDCAPS_ALIGNSIZESRC && uDestSizeAlign)
+ {
+ rs.left = (int)((rs.left + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
+ rs.right = (int)((rs.right + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
+ }
+ if (capsDrv.dwCaps & DDCAPS_ALIGNSIZEDEST && uDestSizeAlign)
+ {
+ rd.left = (int)((rd.left + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
+ rd.right = (int)((rd.right + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
+ }
+
+ *drd = rd;
+ *drs = rs;
+}
+
+void OverlayVideoOutput::timerCallback()
+{
+ if (!adjuster)
+ return ;
+ RECT rd, rs;
+ getRects(&rs, &rd);
+
+ if (memcmp(&m_oldrd, &rd, sizeof(RECT)))
+ {
+ if ((m_oldrd.right - m_oldrd.left) != (rd.right - rd.left) || (m_oldrd.bottom - m_oldrd.top) != (rd.bottom - rd.top))
+ {
+ resetSubtitle();
+ }
+ m_oldrd = rd;
+ if (!initing && lpddsOverlay)
+ if (FAILED(lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx)))
+ {
+ needchange = 1;
+ }
+ InvalidateRect(parent, NULL, FALSE);
+ }
+}
+
+int OverlayVideoOutput::onPaint(HWND hwnd)
+{
+ PAINTSTRUCT p;
+ BeginPaint(hwnd, &p);
+
+ if (!m_closed)
+ {
+ RECT r, rs, rfull, clientRect;
+ RECT drawRect;
+ getRects(&rs, &r, 0); // we don't just fill the entire client rect, cause that looks gross
+
+ getViewport(&rfull, hwnd, 1, NULL);
+
+ // go from this screen coords to global coords
+ r.left += rfull.left;
+ r.top += rfull.top;
+ r.right += rfull.left;
+ r.bottom += rfull.top;
+
+ // go from global back to client
+ ScreenToClient(hwnd, (LPPOINT)&r);
+ ScreenToClient(hwnd, ((LPPOINT)&r) + 1);
+
+ HBRUSH br = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ GetClientRect(hwnd, &clientRect);
+
+ // left black box
+ drawRect.left = clientRect.left;
+ drawRect.right = r.left;
+ drawRect.top = clientRect.top;
+ drawRect.bottom = clientRect.bottom;
+ FillRect(p.hdc, &drawRect, br);
+
+ // right black box
+ drawRect.left = r.right;
+ drawRect.right = clientRect.right;
+ drawRect.top = clientRect.top;
+ drawRect.bottom = clientRect.bottom;
+ FillRect(p.hdc, &drawRect, br);
+
+ // top black box
+ drawRect.left = clientRect.left;
+ drawRect.right = clientRect.right;
+ drawRect.top = clientRect.top;
+ drawRect.bottom = r.top;
+ FillRect(p.hdc, &drawRect, br);
+
+ // bottom black box
+ drawRect.left = clientRect.left;
+ drawRect.right = clientRect.right;
+ drawRect.top = r.bottom;
+ drawRect.bottom = clientRect.bottom;
+ FillRect(p.hdc, &drawRect, br);
+
+ LOGBRUSH lb = {BS_SOLID, (COLORREF)overlay_color, };
+ br = CreateBrushIndirect(&lb);
+
+ FillRect(p.hdc, &r, br);
+ DeleteObject(br);
+ }
+
+ SubsItem *cst = curSubtitle;
+
+ if (cst)
+ {
+ int m_lastsubxp = cst->xPos;
+ int m_lastsubyp = cst->yPos;
+
+ HDC out = p.hdc;
+
+ HGDIOBJ oldobj = SelectObject(out, subFont);
+
+ SetBkMode(out, TRANSPARENT);
+ int centerflags = 0;
+ if (m_lastsubxp < 127) centerflags |= DT_LEFT;
+ else if (m_lastsubxp > 127) centerflags |= DT_RIGHT;
+ else centerflags |= DT_CENTER;
+
+ if (m_lastsubyp < 127) centerflags |= DT_TOP;
+ else if (m_lastsubyp > 127) centerflags |= DT_BOTTOM;
+
+ // draw outline
+ SetTextColor(out, RGB(0, 0, 0));
+ for (int y = -1; y < 2; y++)
+ for (int x = -1; x < 2; x++)
+ {
+ if (!y && !x) continue;
+ RECT r2 = {subRect.left + x, subRect.top + y, subRect.right + x, subRect.bottom + y};
+ DrawTextA(out, cst->text, -1, &r2, centerflags | DT_NOCLIP | DT_NOPREFIX);
+ }
+ // draw text
+ SetTextColor(out, RGB(cst->colorRed, cst->colorGreen, cst->colorBlue));
+ DrawTextA(out, cst->text, -1, &subRect, centerflags | DT_NOCLIP | DT_NOPREFIX);
+ SelectObject(out, oldobj);
+ }
+
+ EndPaint(hwnd, &p);
+ return 1;
+}
+bool OverlayVideoOutput::LockSurface(DDSURFACEDESC *dd)
+{
+ for (;;Sleep(0))
+ {
+ HRESULT hr = lpBackBuffer->Lock(0, dd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
+
+ if (dd->lpSurface)
+ break;
+
+ if (hr == DDERR_SURFACELOST)
+ {
+ lpddsPrimary->Restore();
+ lpBackBuffer->Restore();
+ hr = lpddsOverlay->Lock(0, dd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
+ if (hr == DDERR_SURFACELOST)
+ return false;
+ }
+ else if (hr != DDERR_WASSTILLDRAWING)
+ return false;
+ }
+
+ return true;
+}
+
+void OverlayVideoOutput::displayFrame(const char *buf, int size, int time)
+{
+ DDSURFACEDESC dd = {sizeof(dd), };
+ //CT> vsync wait not used anymore
+ //if (config_video_vsync) lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);
+ if (!LockSurface(&dd))
+ {
+ needchange = 1;
+ return ;
+ }
+
+ if (type == VIDEO_MAKETYPE('Y', 'V', '1', '2'))
+ {
+ YV12_PLANES *planes = (YV12_PLANES *)buf;
+ DoGamma(planes, height);
+ if (uyvy_output)
+ YV12_to_UYVY((unsigned char*)dd.lpSurface, planes, dd.lPitch, width, height, flip);
+ else if (yuy2_output)
+ YV12_to_YUY2((unsigned char*)dd.lpSurface, planes, dd.lPitch, width, height, flip);
+ else
+ YV12_to_YV12((unsigned char*)dd.lpSurface, planes, dd.lPitch, width, height, flip);
+ }
+ else if (type == VIDEO_MAKETYPE('Y', 'U', 'Y', '2'))
+ {
+ if (yuy2_output)
+ YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
+ else if (uyvy_output)
+ YUY2_to_UYVY((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
+ else
+ YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip); // is this right?
+ }
+ else if (type == VIDEO_MAKETYPE('U', 'Y', 'V', 'Y'))
+ {
+ if (yuy2_output)
+ YUY2_to_UYVY((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
+ else if (uyvy_output) // TODO check this is correct i.e. dup YUY2_to_YUY2(..) calls
+ YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
+ else
+ YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip); // is this right?
+ }
+
+ lpBackBuffer->Unlock(&dd);
+ lpddsOverlay->Flip(lpBackBuffer, DDFLIP_WAIT);
+}
+
+void OverlayVideoOutput::drawSubtitle(SubsItem *item)
+{
+ curSubtitle = item;
+ RECT oldrect = subRect;
+ GetClientRect(parent, &subRect);
+
+ if (item)
+ {
+ RECT oldwinRect = winRect;
+ GetClientRect(parent, &winRect);
+ if (!subFont || ((winRect.bottom - winRect.top) != (oldwinRect.bottom - oldwinRect.top)) || m_fontsize != item->fontSize)
+ {
+ if (subFont)
+ DeleteObject(subFont);
+ m_fontsize = item->fontSize;
+ subFont = CreateFontA(14 + item->fontSize + 18 * (winRect.bottom - winRect.top) / 768, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
+ }
+
+ HDC out = GetDC(parent);
+ SelectObject(out, subFont);
+ SIZE s;
+ GetTextExtentPoint32A(out, item->text, lstrlenA(item->text), &s);
+ {
+ // calcul for multiline text
+ const char *p = item->text;
+ int n = 0;
+ while (*p != 0) if (*p++ == '\n') n++;
+ if (n) s.cy *= (n + 1);
+ }
+
+ if (item->xPos > 127) // towards the right
+ subRect.right -= ((subRect.right - subRect.left) * (255 - item->xPos)) / 256;
+ else if (item->xPos < 127)
+ subRect.left += ((subRect.right - subRect.left) * item->xPos) / 256;
+ subRect.top += ((subRect.bottom - s.cy - subRect.top) * item->yPos) / 255;
+ subRect.bottom = subRect.top + s.cy;
+
+ ReleaseDC(parent, out);
+ }
+
+ //just redraw the correct portion
+ InvalidateRect(parent, &oldrect, TRUE);
+ InvalidateRect(parent, &subRect, TRUE);
+}
+
+void OverlayVideoOutput::resetSubtitle()
+{
+ curSubtitle = NULL;
+ subRect.top = 65536;
+} \ No newline at end of file
diff --git a/Src/Winamp/vid_overlay.h b/Src/Winamp/vid_overlay.h
new file mode 100644
index 00000000..3e93b173
--- /dev/null
+++ b/Src/Winamp/vid_overlay.h
@@ -0,0 +1,56 @@
+#ifndef _VIDEO_OVERLAY_H
+#define _VIDEO_OVERLAY_H
+
+#include <ddraw.h>
+#include <multimon.h>
+#include "VideoOutputChildDDraw.h"
+
+class SubsItem;
+
+class OverlayVideoOutput : public VideoOutputChildDDraw {
+
+public:
+ OverlayVideoOutput();
+ virtual ~OverlayVideoOutput();
+ int create(HWND parent,VideoAspectAdjuster *_adjuster, int w, int h, unsigned int type, int flipit, double aspectratio); //return 1 if ok
+ int needChange() { return needchange; }
+ int onPaint(HWND hwnd);
+ void displayFrame(const char *buf, int size, int time);
+ void timerCallback();
+ void close();
+
+ void drawSubtitle(SubsItem *item);
+ void resetSubtitle();
+ void setVFlip(int on) { flip=on; }
+ void Refresh() { InvalidateRect(parent, NULL, TRUE); }
+private:
+ bool LockSurface(DDSURFACEDESC *dd);
+ int width, height, flip;
+ int m_closed;
+ int needchange;
+ unsigned int type;
+ LPDIRECTDRAW lpDD;
+ LPDIRECTDRAWSURFACE lpddsOverlay, lpddsPrimary;
+ LPDIRECTDRAWSURFACE lpBackBuffer;
+
+ DDCAPS capsDrv;
+ unsigned int uDestSizeAlign, uSrcSizeAlign;
+ DWORD dwUpdateFlags;
+ DDOVERLAYFX ovfx;
+ RECT rs,rd;
+ RECT m_oldrd;
+ RECT winRect;
+
+ int overlay_color;
+ bool initing;
+ int yuy2_output, uyvy_output;
+
+ void getRects(RECT *drs, RECT *drd, int fixmultimon=1) const;
+
+ HFONT subFont;
+ RECT subRect;
+ SubsItem *curSubtitle;
+ int m_fontsize;
+};
+extern OverlayVideoOutput overlayVideo;
+#endif \ No newline at end of file
diff --git a/Src/Winamp/vid_subs.cpp b/Src/Winamp/vid_subs.cpp
new file mode 100644
index 00000000..20776c57
--- /dev/null
+++ b/Src/Winamp/vid_subs.cpp
@@ -0,0 +1,222 @@
+#include "main.h"
+#include "vid_subs.h"
+
+Subtitles::Subtitles(const char *filename)
+{
+ m_frame_based=0;
+ m_last_sub=-1;
+ m_font_size_mod=0;
+
+#ifdef SUBTITLES_READER
+ if(!filename) return;
+
+ IDataReader *file_reader=CreateReader((char *)filename);
+ if(file_reader) {
+ char *text=NULL;
+ int textpos=0;
+ int allocsize=0;
+ char buf[1024] = {0};
+ unsigned aborttime=GetTickCount()+20000;
+ for (;;)
+ {
+ int l=file_reader->read(buf,1024);
+ if (l <= 0)
+ {
+ if (file_reader->iseof()) break;
+ if (file_reader->geterror() || GetTickCount() > aborttime)
+ {
+ free(text);
+ return;
+ }
+ Sleep(100);
+ }
+ else
+ {
+ if (textpos+l+1 >= allocsize)
+ {
+ allocsize = textpos+l+1+8192;
+ text=(char*)realloc(text,allocsize);
+ }
+ memcpy(text+textpos,buf,l);
+ textpos+=l;
+ }
+ }
+ if (text) {
+ text[textpos]=0;
+ //fucko: check for case
+ if(strstr(filename,".srt")) decodeSrtFile(text);
+ else if(strstr(filename,".sub")) decodeSubFile(text);
+ free(text);
+ }
+ }
+ delete(file_reader);
+#endif
+}
+
+#ifdef SUBTITLES_READER
+void Subtitles::decodeSrtFile(char *text) {
+ // parse subtitle file (.srt format)
+ char *p=text;
+
+ //for(int i=0;;i++) {
+ while(1) {
+ unsigned int time_start,time_end;
+
+ // parse title nb
+ char *p2=p;
+ while(p2 && *p2 && *p2!='\n') p2++;
+ *p2++=0;
+ //if(atoi(p)!=i+1) break;
+ if(atoi(p)<=0) break;
+
+ // parse start time
+ p=p2;
+ while(p2 && *p2 && *p2!=' ') p2++;
+ *p2++=0;
+ time_start=getTimeFromSrtText(p);
+
+ // parse "-->"
+ while(p2 && *p2 && *p2!=' ') p2++;
+ p2++;
+
+ // parse end time
+ p=p2;
+ while(p2 && *p2 && *p2!='\n') p2++;
+ *p2++=0;
+ time_end=getTimeFromSrtText(p);
+
+ // parse text
+ p=p2;
+ while(p2 && *p2 && !(*p2=='\r' || *p=='\n')) {
+ while(p2 && *p2 && *p2!='\n') p2++;
+ p2++;
+ }
+ *p2++=0;
+
+ //remove trailing CR
+ {
+ int l=lstrlen(p);
+ if(l) {
+ if(p[l-1]=='\r' || p[l-1]=='\n') p[l-1]=0;
+ }
+ }
+
+ m_subs.put(new SubsItem(time_start,time_end,p));
+
+ if(*p2=='\n') p2++;
+ p=p2;
+ }
+ m_frame_based=0;
+}
+
+unsigned int Subtitles::getTimeFromSrtText(const char *text) {
+ int hours,mins,secs,mills;
+ const char *p=text;
+ hours=atoi(p);
+ while(p && *p && *p!=':') p++;
+ if (p) p++;
+ mins=atoi(p);
+ while(p && *p && *p!=':') p++;
+ if (p) p++;
+ secs=atoi(p);
+ while(p && *p && *p!=',') p++;
+ if (p) p++;
+ mills=atoi(p);
+ return mills+(secs*1000)+(mins*60000)+(hours*60*60000);
+}
+
+void Subtitles::decodeSubFile(char *text)
+{
+ char *p=text;
+ while(p && *p && *p=='{') {
+ int framestart,frameend;
+ p++;
+ char *p2=p;
+ while(p2 && *p2 && *p2!='}') p2++;
+ if (p2) *p2++=0;
+ framestart=atoi(p);
+
+ p2+=1;
+ p=p2;
+ while(p2 && *p2 && *p2!='}') p2++;
+ if (p2) *p2++=0;
+ frameend=atoi(p);
+
+ p=p2;
+ while(p2 && *p2 && *p2!='\r' && *p2!='\n') {
+ //replace pipes with CR
+ if(*p2=='|') *p2='\n';
+ p2++;
+ }
+ *p2++=0;
+
+ m_subs.put(new SubsItem(framestart,frameend,p));
+
+ if(*p2=='\n') p2++;
+ p=p2;
+ }
+ m_frame_based=1;
+}
+#endif
+
+SubsItem *Subtitles::getSubtitle(unsigned int time, unsigned int frame)
+{
+ //FUCKO
+#if 0
+ unsigned int ref=m_frame_based?frame:time;
+
+ //check with lastsub
+ if(m_last_sub!=-1) {
+ SubsItem *item=m_subs.get(m_last_sub);
+ if(ref>=item->timestart && ref<=item->timeend)
+ {
+ item->fontSize=item->origFontSize+m_font_size_mod;
+ return item;
+ }
+ SubsItem *item2=m_subs.get(m_last_sub+1);
+ if(item2) {
+ if(ref>=item->timeend && ref<=item2->timestart) return NULL;
+ if(ref>=item2->timestart && ref<=item2->timeend) {
+ m_last_sub++;
+ item2->fontSize=item2->origFontSize+m_font_size_mod;
+ return item2;
+ }
+ }
+ }
+
+ int l=m_subs.getlen();
+ for(int i=0;i<l;i++) {
+ SubsItem *item=m_subs.get(i);
+ if(ref<item->timestart) break;
+ if(ref>=item->timestart && ref<=item->timeend) {
+ m_last_sub=i;
+ item->fontSize=item->origFontSize+m_font_size_mod;
+ return item;
+ }
+ }
+ m_last_sub=-1;
+#endif
+ return NULL;
+}
+
+void Subtitles::addSubtitlePacket(SUBTITLE_INFO *sti)
+{
+ //FUCKO
+#if 0
+ m_frame_based=1; //FUCKO: put this in subsitem struct
+ SubsItem *i=new SubsItem(sti->start_frame,sti->end_frame,sti->utf8_text);
+ i->xPos=sti->xPos;
+ i->yPos=sti->yPos;
+ i->colorBlue=sti->colorBlue;
+ i->colorGreen=sti->colorGreen;
+ i->colorRed=sti->colorRed;
+ i->extraDataSize=sti->extraDataSize;
+ i->origFontSize=sti->fontSize;
+ if(sti->extraDataSize) {
+ i->extraData=malloc(sti->extraDataSize);
+ memcpy((void *)i->extraData,sti->extraData,sti->extraDataSize);
+ }
+ i->muxed_subtitle=1;
+ m_subs.put(i);
+#endif
+} \ No newline at end of file
diff --git a/Src/Winamp/vid_subs.h b/Src/Winamp/vid_subs.h
new file mode 100644
index 00000000..b467696d
--- /dev/null
+++ b/Src/Winamp/vid_subs.h
@@ -0,0 +1,75 @@
+#ifndef NSVPLAY_SUBTITLES_H
+#define NSVPLAY_SUBTITLES_H
+
+#include "wa_ipc.h"
+//#include "main.h"
+//#include "../nsvbs.h"
+
+typedef struct
+{
+ const char *language;
+ const char *utf8_text;
+ unsigned int start_frame, end_frame;
+ unsigned char xPos, yPos;
+ unsigned char colorRed, colorGreen, colorBlue;
+ signed char fontSize;
+ int extraDataSize;
+ const void *extraData;
+} SUBTITLE_INFO;
+
+class SubsItem {
+public:
+ SubsItem(unsigned int ptimestart, unsigned int ptimeend, const char *ptext) :
+ timestart(ptimestart) , timeend(ptimeend) {
+ text=_strdup(ptext);
+ xPos=128;
+ yPos=255;
+ colorRed=colorGreen=colorBlue=0xff;
+ extraDataSize=0;
+ extraData=0;
+ muxed_subtitle=0;
+ fontSize=origFontSize=0;
+ }
+ ~SubsItem() {
+ free((void*)text);
+ if(extraDataSize) free((void *)extraData);
+ }
+
+ unsigned int timestart;
+ unsigned int timeend;
+ const char *text;
+
+ unsigned char xPos, yPos;
+ unsigned char colorRed, colorGreen, colorBlue;
+ int extraDataSize;
+ const void *extraData;
+
+ int muxed_subtitle; //so we free it when we seek/display
+
+ int fontSize;
+
+ int origFontSize;
+};
+
+class Subtitles {
+public:
+ Subtitles(const char *filename);
+
+ SubsItem *getSubtitle(unsigned int time, unsigned int frame); // time in ms
+ void addSubtitlePacket(SUBTITLE_INFO *sti);
+
+ void setFontSizeModifier(int size) { m_font_size_mod=size; }
+
+private:
+ void decodeSrtFile(char *text);
+ unsigned int getTimeFromSrtText(const char *text);
+
+ void decodeSubFile(char *text);
+
+ //ClassList<SubsItem> m_subs; //FUCKO
+ int m_frame_based;
+ int m_last_sub;
+ int m_font_size_mod;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/video.cpp b/Src/Winamp/video.cpp
new file mode 100644
index 00000000..bb061809
--- /dev/null
+++ b/Src/Winamp/video.cpp
@@ -0,0 +1,858 @@
+#include <windowsx.h>
+
+#include "main.h"
+#include <ddraw.h>
+#include <multimon.h>
+#include "api.h"
+#include "vid_overlay.h"
+#include "vid_ddraw.h"
+#include "vid_subs.h"
+#include "vid_none.h"
+#include "VideoOutput.h"
+
+#include "Browser.h"
+#include "video.h"
+#include "../nu/AutoWide.h"
+#include "WinampAttributes.h"
+#include "resource.h"
+
+#define WM_VIDEO_UPDATE_STATUS_TEXT WM_USER+0x874
+#define WM_VIDEO_OPEN WM_USER+0x875
+#define WM_VIDEO_CLOSE WM_USER+0x876
+#define WM_VIDEO_RESIZE WM_USER+0x877
+#define WM_VIDEO_CREATE WM_USER+0x900
+
+#define VIDEO_GENFF_SIZEREQUEST (WM_USER+2048)
+#undef GetSystemMetrics
+
+#define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
+
+VideoOutput *m_videooutput = NULL;
+
+static int VW_OnLButtonUp(HWND hwnd, int x, int y, UINT flags);
+static int VW_OnRButtonUp(HWND hwnd, int x, int y, UINT flags);
+static int VW_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
+static int VW_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
+static int VW_OnLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
+static BOOL VW_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized);
+extern "C" int g_video_numaudiotracks;
+extern "C" int is_fullscreen_video = 0;
+extern "C" int no_notify_play;
+extern "C" int last_no_notify_play;
+#undef GetSystemMetrics
+
+bool sizeOnOpen = false;
+int widthOnOpen, heightOnOpen;
+#define VideoClassicWidth() 19
+#define VideoClassicHeight() 58
+static void VideoClose();
+
+/* Resizes the windows (parent and children) based on what the size of the video should be */
+static void SetVideoSize(int width, int height)
+{
+ if (m_videooutput && m_videooutput->is_fullscreen()) // fullscreen
+ {
+ m_videooutput->SetVideoPosition(0, 0, config_video_width, config_video_height);
+ }
+ else // not fullscreen
+ {
+ // send out ideal video size message (in case anyone wants it)
+ PostMessageW(hMainWindow, WM_WA_IPC, (((width) & 0xFFFF) << 16) | ((height) & 0xFFFF), IPC_SETIDEALVIDEOSIZE);
+ if (GetParent(hVideoWindow)) // if gen_ff owns the window, then signal it about the video size
+ PostMessageW(GetParent(hVideoWindow), VIDEO_GENFF_SIZEREQUEST, width, height);
+ else // classic skin
+ SetWindowPos(hVideoWindow, 0, 0, 0, width + VideoClassicWidth(), height + VideoClassicHeight(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+}
+
+/* Resizes the windows (parent and children) based on what the size of the parent should be */
+void SetExteriorSize(int width, int height)
+{
+ // calculate interior size
+ width -= VideoClassicWidth();
+ height -= VideoClassicHeight();
+
+ // pass our calculated value onto the size routine
+ SetVideoSize(width, height);
+}
+
+/* lays out children (video and ad) based on a given parent window size */
+static void LayoutChildren(int width, int height)
+{
+ if (m_videooutput && m_videooutput->is_fullscreen()) // fullscreen
+ {
+ m_videooutput->SetVideoPosition(0, 0, config_video_width, config_video_height);
+ }
+ else // not fullscreen
+ {
+ // calculate interior size
+ width -= VideoClassicWidth();
+ height -= VideoClassicHeight();
+
+ // size the video
+ if (m_videooutput)
+ {
+ m_videooutput->SetVideoPosition(11, 20, width, height);
+ InvalidateRect(m_videooutput->getHwnd(), 0, TRUE); // force repaint of video
+ }
+ InvalidateRect(hVideoWindow, 0, TRUE); // force repaint of parent window
+ }
+}
+
+/* Resizes the windows (parent and children) based on what the size of the parent should be
+Sets the position of the parent window */
+static void SetExteriorSizeAndPosition(int x, int y, int width, int height)
+{
+ config_video_wx = x;
+ config_video_wy = y;
+ SetExteriorSize(width, height);
+}
+
+void updateTrackSubmenu()
+{
+ HMENU menu = GetSubMenu(GetSubMenu(top_menu, 3), 13);
+ HMENU audiomenu = GetSubMenu(menu, 6);
+ HMENU videomenu = GetSubMenu(menu, 7);
+ static int audioadded = 0;
+ static int videoadded = 0;
+ static int first = 1;
+ if (first)
+ {
+ RemoveMenu(audiomenu, ID_VID_AUDIO0, MF_BYCOMMAND);
+ RemoveMenu(videomenu, ID_VID_VIDEO0, MF_BYCOMMAND);
+ first = 1;
+ }
+
+ if (audioadded)
+ {
+ for (int i = 0;i < 16;i++)
+ {
+ RemoveMenu(audiomenu, ID_VID_AUDIO0 + i, MF_BYCOMMAND);
+ }
+ audioadded = 0;
+ }
+ if (videoadded)
+ {
+ for (int i = 0;i < 16;i++)
+ {
+ RemoveMenu(videomenu, ID_VID_VIDEO0 + i, MF_BYCOMMAND);
+ }
+ videoadded = 0;
+ }
+
+ VideoOutput *out = (VideoOutput *)video_getIVideoOutput();
+ if (!out || !out->getTrackSelector())
+ {
+ EnableMenuItem(menu, 8, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(menu, 9, MF_GRAYED | MF_BYPOSITION);
+ return ;
+ }
+
+ ITrackSelector *sel = out->getTrackSelector();
+
+ int numaudiotracks = sel->getNumAudioTracks();
+ if (numaudiotracks < 2)
+ {
+ EnableMenuItem(menu, 8, MF_GRAYED | MF_BYPOSITION);
+ }
+ else
+ {
+ audioadded = 1;
+ int curtrack = sel->getCurAudioTrack();
+ for (int i = 0;i < numaudiotracks;i++)
+ {
+ char t[256] = {0};
+ sel->enumAudioTrackName(i, t, 255);
+ InsertMenuA(audiomenu, i, MF_BYPOSITION, ID_VID_AUDIO0 + i, t);
+ CheckMenuItem(audiomenu, ID_VID_AUDIO0 + i, ((i == curtrack) ? MF_CHECKED : MF_UNCHECKED) | MF_BYCOMMAND);
+ }
+ EnableMenuItem(menu, 8, MF_ENABLED | MF_BYPOSITION);
+ }
+
+ int numvideotracks = sel->getNumVideoTracks();
+ if (numvideotracks < 2)
+ {
+ EnableMenuItem(menu, 9, MF_GRAYED | MF_BYPOSITION);
+ }
+ else
+ {
+ videoadded = 1;
+ int curtrack = sel->getCurVideoTrack();
+ for (int i = 0;i < numvideotracks;i++)
+ {
+ char t[256] = {0};
+ sel->enumVideoTrackName(i, t, 255);
+ InsertMenuA(videomenu, i, MF_BYPOSITION, ID_VID_VIDEO0 + i, t);
+ CheckMenuItem(videomenu, ID_VID_VIDEO0 + i, ((i == curtrack) ? MF_CHECKED : MF_UNCHECKED) | MF_BYCOMMAND);
+ }
+ EnableMenuItem(menu, 9, MF_ENABLED | MF_BYPOSITION);
+ }
+}
+
+int ShowVideoWindow(int init_state)
+{
+ sizeOnOpen = false;
+
+ if (config_video_open // if we're already open
+ || !hVideoWindow // or we havn't made the video window yet
+ || !g_has_video_plugin // or we're configured to not have video
+ || !Ipc_WindowToggle(IPC_CB_WND_VIDEO, 1)) // or some plugin doesn't want us to open the video window
+ return 0; // then bail out
+
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_VIDEO, MF_CHECKED);
+ if(!init_state && !config_minimized) ShowWindow(hVideoWindow, SW_SHOWNA);
+ //ad->show(true);
+ config_video_open = 1;
+ set_aot(1);
+ return 1;
+}
+
+void HideVideoWindow(int autoStop)
+{
+ sizeOnOpen = false;
+
+ if (!config_video_open // if we're not even open
+ || !hVideoWindow // or we havn't made the video window yet
+ // || !g_has_video_plugin // or we're configured to not have video
+ || !Ipc_WindowToggle(IPC_CB_WND_VIDEO, !config_video_open)) // or some plugin doesn't want us to close the video window
+ return ; // then bail out
+
+ if (GetForegroundWindow() == hVideoWindow || IsChild(hVideoWindow, GetForegroundWindow()))
+ {
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_NEXT_WINDOW, 0);
+ }
+ CheckMenuItem(main_menu, WINAMP_OPTIONS_VIDEO, MF_UNCHECKED);
+ ShowWindow(hVideoWindow, SW_HIDE);
+
+ config_video_open = 0;
+
+ if (autoStop && config_video_stopclose && !(GetAsyncKeyState(VK_SHIFT)&0x8000) && video_isVideoPlaying())
+ {
+ PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);
+ }
+}
+
+HMENU BuildPopupMenu();
+
+void Vid_Cmd(windowCommand *wc)
+{
+ switch (wc->cmd)
+ {
+ case VIDCMD_FULLSCREEN:
+ videoGoFullscreen();
+ break;
+ case VIDCMD_1X:
+ SendMessageW(videoGetHwnd(), WM_COMMAND, ID_VIDEOWND_ZOOM100, 0);
+ break;
+ case VIDCMD_2X:
+ SendMessageW(videoGetHwnd(), WM_COMMAND, ID_VIDEOWND_ZOOM200, 0);
+ break;
+ case VIDCMD_LIB:
+ SendMessageW(videoGetHwnd(), WM_COMMAND, WINAMP_VIDEO_TVBUTTON, 0);
+ break;
+ case VIDPOPUP_MISC:
+ DoTrackPopup(BuildPopupMenu(), wc->align, wc->x, wc->y, videoGetHwnd());
+ break;
+ case VIDCMD_EXIT_FS:
+ videoForceFullscreenOff();
+ break;
+ }
+}
+
+static int VW_OnRButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ POINT p;
+ extern HMENU top_menu;
+ GetCursorPos(&p);
+ DoTrackPopup(main_menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hMainWindow);
+ return 1;
+}
+
+static int VW_OnLButtonUp(HWND hwnd, int x, int y, UINT flags)
+{
+ ReleaseCapture();
+ videoui_handlemouseevent(x, y, -1, flags);
+ return 1;
+}
+
+static int VW_OnLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags )
+{
+ SetCapture( hwnd );
+ videoui_handlemouseevent( x, y, 1, keyFlags );
+ SetFocus( hwnd );
+
+ return 1;
+}
+
+static int VW_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
+{
+ videoui_handlemouseevent(x, y, 0, keyFlags);
+
+ return 1;
+}
+
+static BOOL VW_OnNCActivate( HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized )
+{
+ if ( !m_videooutput || ( m_videooutput && !m_videooutput->is_fullscreen() ) )
+ {
+ if ( fActive == FALSE )
+ draw_vw_tbar( config_hilite ? 0 : 1 );
+ else
+ draw_vw_tbar( 1 );
+ }
+
+ return TRUE;
+}
+
+static int VW_OnLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
+{
+ return 1;
+}
+
+/*Turns off and on the screensaver*/
+VOID CALLBACK ResetScreenSaver(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ // benski> this seems less hackish. only win2k and up
+ if (config_video_noss && video_isVideoPlaying())
+ SetThreadExecutionState(ES_DISPLAY_REQUIRED);
+ // TODO: maybe we should do the same thing with ES_SYSTEM_REQUIRED to keep the system from snoozing
+
+ // benski> old code was here
+ /*
+ BOOL b;
+ if (config_video_noss && video_isVideoPlaying() && SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &b, 0) && b)
+ {
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0); // turn off
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, 0, 0); // turn back on
+ // this is just a hack
+ // basically by toggling off and on we reset the timeout count
+ }
+*/
+}
+
+static void VideoOpen(HWND hwnd, int width, int height)
+{
+ sizeOnOpen=false;
+
+ // check if we appear to be doing a resume from a tag edit
+ // and if so then we need to ignore the show window option
+ if (config_video_autoopen &&
+ ((no_notify_play != last_no_notify_play && !last_no_notify_play) || (no_notify_play == last_no_notify_play)))
+ ShowVideoWindow(0);
+ last_no_notify_play = no_notify_play;
+
+ HWND skinVidWindow = GetParent(hwnd) ? GetParent(hwnd) : hwnd;
+
+ if (m_videooutput->is_fullscreen() || config_video_auto_fs) // go fullscreen
+ {
+ videoGoFullscreen();
+ InvalidateRect(m_videooutput->getHwnd(), 0, TRUE);
+ }
+ else // not fullscreen
+ {
+ if (config_video_updsize)
+ {
+ widthOnOpen = width;
+ heightOnOpen = height;
+ sizeOnOpen = true;
+ SetVideoSize(width, height);
+ }
+ LayoutChildren(config_video_width, config_video_height);
+
+ if (!IsIconic(skinVidWindow))
+ BringWindowToTop(skinVidWindow);
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+}
+
+LRESULT CALLBACK video_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == g_scrollMsg) { wParam <<= 16; uMsg = WM_MOUSEWHEEL; }
+
+ if (uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONUP || uMsg == WM_MOUSEMOVE)
+ if (!m_videooutput || !m_videooutput->is_fullscreen())
+ {
+ switch (uMsg)
+ {
+ HANDLE_MSG(hwnd, WM_LBUTTONUP, VW_OnLButtonUp);
+ HANDLE_MSG(hwnd, WM_LBUTTONDOWN, VW_OnLButtonDown);
+ HANDLE_MSG(hwnd, WM_MOUSEMOVE, VW_OnMouseMove);
+ HANDLE_MSG(hwnd, WM_RBUTTONUP, VW_OnRButtonUp);
+ }
+ }
+
+ switch (uMsg)
+ {
+ case WM_USER + 1:
+ if (m_videooutput)
+ SendMessageW(m_videooutput->getHwnd(), uMsg, wParam, lParam);
+ break;
+
+ case WM_USER + 2:
+ if (sizeOnOpen)
+ {
+ // sizeOnOpen=false;
+ PostMessageW(hwnd, WM_VIDEO_RESIZE, widthOnOpen, heightOnOpen);
+ }
+ if (m_videooutput)
+ SendMessageW(m_videooutput->getHwnd(), uMsg, wParam, lParam);
+ break;
+
+ case WM_USER + 0x100:
+ if (wParam == 1 && lParam)
+ {
+ config_video_wx = ((POINT *)lParam)->x;
+ config_video_wy = ((POINT *)lParam)->y;
+ if ((!!config_snap) ^ (!!(GetKeyState(VK_SHIFT) & 0x8000)))
+ {
+ RECT outrc;
+ EstVidWindowRect(&outrc);
+ SnapWindowToAllWindows(&outrc, hVideoWindow);
+ SetVidWindowRect(&outrc);
+ }
+ SetWindowPos(hVideoWindow, 0, config_video_wx, config_video_wy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ return 0;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 12345: // signal from elsewhere
+ if (m_videooutput)
+ SendMessageW(m_videooutput->getHwnd(), WM_TIMER, 0, 0);
+ break;
+ }
+ return 0;
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED: // we trap both windowposchanging and windowposchanged incase someone uses SetWindowPos(..., SWP_NOSENDCHANGING)
+ {
+ LPWINDOWPOS windowPos = (LPWINDOWPOS) lParam;
+ if (windowPos->flags & SWP_NOSIZE)
+ {
+ break;
+ }
+
+ if (uMsg == WM_WINDOWPOSCHANGED)
+ {
+ config_video_width = windowPos->cx;
+ config_video_height = windowPos->cy;
+ LayoutChildren(config_video_width, config_video_height);
+ // update the position of the tooltips on window resize
+ set_vid_wnd_tooltip();
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPTOOLTIPTEXT tt = (LPTOOLTIPTEXT)lParam;
+ if(tt->hdr.hwndFrom = hVideoTooltipWindow)
+ {
+ switch (tt->hdr.code)
+ {
+ case TTN_SHOW:
+ SetWindowPos(tt->hdr.hwndFrom,HWND_TOPMOST,0,0,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
+ break;
+ }
+ }
+ }
+ break;
+
+ case WM_GETMINMAXINFO:
+ {
+ MINMAXINFO *p = (MINMAXINFO *)lParam;
+ p->ptMaxTrackSize.x = 16384;
+ p->ptMaxTrackSize.y = 16384;
+ }
+ return 0;
+
+ case WM_VIDEO_RESIZE:
+ //ReplyMessage(0); // if IVideoOutput::open() was called on a different thread, this will unblock it.
+ {
+ int width = wParam;
+ int height = lParam;
+ // idealWidth = wParam;
+ SetVideoSize(width, height);
+ LayoutChildren(config_video_width, config_video_height);
+ }
+ return 0;
+
+ case WM_DESTROY:
+ if (NULL != WASABI_API_APP) WASABI_API_APP->app_unregisterGlobalWindow(hwnd);
+ if (vw_init)
+ draw_vw_kill();
+ break;
+
+ case WM_DISPLAYCHANGE:
+ InvalidateRect(hwnd, NULL, TRUE);
+ break;
+
+ case WM_VIDEO_OPEN:
+ VideoOpen(hwnd, wParam, lParam);
+ // set_aot(1);
+ return 0;
+ break;
+
+ case WM_VIDEO_CREATE:
+ m_videooutput->mainthread_Create();
+ break;
+
+ case WM_VIDEO_CLOSE:
+ VideoClose();
+ InvalidateRect(hwnd, NULL, TRUE); //repaint
+ return 0;
+
+ case WM_VIDEO_UPDATE_STATUS_TEXT:
+ if (m_videooutput && !m_videooutput->is_fullscreen())
+ draw_vw_info((wchar_t*)wParam, 1);
+ videoTextFeed->UpdateText((const wchar_t*)wParam, 1024);
+ return 0;
+
+ case WM_MOUSEWHEEL:
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+
+ HANDLE_MSG(hwnd, WM_QUERYNEWPALETTE, Main_OnQueryNewPalette);
+ HANDLE_MSG(hwnd, WM_PALETTECHANGED, Main_OnPaletteChanged);
+ HANDLE_MSG(hwnd, WM_NCACTIVATE, VW_OnNCActivate);
+ HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, VW_OnLButtonDblClk);
+
+ case WM_CONTEXTMENU:
+ {
+ if (lParam == MAKELONG(-1, -1))
+ {
+ extern HMENU top_menu;
+ RECT r;
+ GetWindowRect(videoGetHwnd(), &r);
+ DoTrackPopup(BuildPopupMenu(), TPM_LEFTALIGN | TPM_RIGHTBUTTON, r.left, r.top, videoGetHwnd());
+ }
+ }
+ return 0;
+
+ case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP:
+ if ((GetAsyncKeyState(VK_CONTROL)&0x8000) && wParam == VK_F4)
+ {
+ if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)
+ SendMessageW(hMainWindow, WM_COMMAND, WINAMP_OPTIONS_VIDEO, 0);
+ }
+ /* else if(uMsg==WM_SYSKEYDOWN && (LPARAM&(1<<29)) && wParam == VK_RETURN)
+ {
+ if (m_videooutput)
+ {
+ if(!m_videooutput->is_fullscreen()) m_videooutput->fullscreen();
+ else m_videooutput->remove_fullscreen();
+ }
+ }*/
+ else
+ {
+ if (SendMessageW(m_videooutput->getHwnd(), uMsg, wParam, lParam)) return 0;
+ if (wParam != VK_RETURN && m_videooutput->is_fullscreen() && ((GetAsyncKeyState(VK_CONTROL) | GetAsyncKeyState(VK_MENU))&0x8000)) return 0;
+ {
+ MSG winmsg;
+ winmsg.message = uMsg;
+ winmsg.hwnd = hMainWindow;
+ winmsg.wParam = wParam;
+ winmsg.lParam = lParam;
+ if (WASABI_API_APP->app_translateAccelerators(&winmsg)) return 0;
+ //if (transAccel(hwnd,uMsg,wParam,lParam)) return 0;
+ //transAccelStruct tas = {hwnd, uMsg, wParam, lParam};
+ //if (SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&tas, IPC_TRANSLATEACCELERATOR)) return 0;
+ }
+ }
+ break;
+
+ case WM_DROPFILES:
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+
+ case WM_SHOWWINDOW:
+ if (wParam == TRUE) // showing
+ {
+ if (sizeOnOpen)
+ {
+ //sizeOnOpen=false;
+ PostMessageW(hwnd, WM_VIDEO_RESIZE, widthOnOpen, heightOnOpen);
+ }
+
+ if (!IsIconic(hwnd))
+ BringWindowToTop(hwnd);
+ LayoutChildren(config_video_width, config_video_height);
+ }
+
+ RefreshIconicThumbnail();
+
+ /*
+ {
+ // if extra_data[EMBED_STATE_EXTRA_REPARENTING] is set, we are being reparented by the freeform lib, so we should
+ // just ignore this message because our visibility will not change once the freeform
+ // takeover/restoration is complete
+ embedWindowState *ws = (embedWindowState *)GetWindowLongW(hwnd, GWL_USERDATA);
+ if (ws != NULL && ws->extra_data[EMBED_STATE_EXTRA_REPARENTING])
+ {
+ }
+ }
+ */
+ break;
+
+ case WM_CLOSE:
+ if (!m_videooutput || !m_videooutput->is_fullscreen())
+ WASABI_API_APP->main_shutdown();
+ else
+ m_videooutput->remove_fullscreen();
+ return 0;
+
+ case WM_PAINT:
+ if (!m_videooutput || !m_videooutput->is_fullscreen())
+ {
+ draw_paint_vw(hwnd);
+ return 0;
+ }
+ break;
+
+ case WM_CREATE:
+ hVideoWindow = hwnd;
+ SetTimer(hwnd, 32, 15000, ResetScreenSaver);
+ SetWindowLongPtrW(hwnd, GWLP_USERDATA, (config_keeponscreen&2) ? 0x49474541 : 0);
+ SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE)&~(WS_CAPTION));
+ SetWindowPos(hVideoWindow, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+ //ad->CreateHWND(hwnd);
+ m_videooutput = new VideoOutput(hwnd);
+ if (!config_minimized)
+ ShowWindow(m_videooutput->getHwnd(), SW_SHOWNA);
+ SetExteriorSizeAndPosition(config_video_wx, config_video_wy, config_video_width, config_video_height);
+ LayoutChildren(config_video_width, config_video_height);
+
+ if (NULL != WASABI_API_APP) WASABI_API_APP->app_registerGlobalWindow(hwnd);
+
+ return 0;
+
+ case WM_COMMAND:
+ return SendMessageW(hMainWindow, uMsg, wParam, lParam);
+
+ case WM_MOVE:
+ if (m_videooutput)
+ SendMessageW(m_videooutput->getHwnd(), WM_MOVE, 0, 0);
+ return 0;
+
+ case WM_SETCURSOR:
+ if (config_usecursors && !disable_skin_cursors)
+ {
+#define inreg(x,y,x2,y2) \
+ ((mouse_x <= ( x2 ) && mouse_x >= ( x ) && \
+ mouse_y <= ( y2 ) && mouse_y >= ( y )))
+
+ if (((HWND)wParam == hVideoWindow || IsChild(hVideoWindow, (HWND)wParam)) && HIWORD(lParam) == WM_MOUSEMOVE)
+ {
+ int mouse_x, mouse_y;
+ POINT p;
+ static RECT b[] =
+ {
+ { -(275 - 264), 3, -(275 - 272), 12}, //close
+ {0, 0, -1, 13}, // titelbar
+ { -20, -20, -1, -1},
+ };
+
+ int iconoffs[] = {15 + 1, 15 + 2, 15 + 4, 15 + 5};
+ int b_len = 3;
+ int x;
+ GetCursorPos(&p);
+ ScreenToClient(hVideoWindow, &p);
+ mouse_x = p.x;
+ mouse_y = p.y;
+
+ for (x = 0; x < b_len; x ++)
+ {
+ int l, r, t, bo;
+ l = b[x].left;r = b[x].right;t = b[x].top;bo = b[x].bottom;
+ if (l < 0) l += config_video_width;
+ if (r < 0) r += config_video_width;
+ if (t < 0) t += config_video_height;
+ if (bo < 0) bo += config_video_height;
+ if (inreg(l, t, r, bo)) break;
+ }
+
+ if (Skin_Cursors[iconoffs[x]]) SetCursor(Skin_Cursors[iconoffs[x]]);
+ else SetCursor(LoadCursorW(NULL, IDC_ARROW));
+ }
+ return TRUE;
+ }
+ else SetCursor(LoadCursorW(NULL, IDC_ARROW));
+ return TRUE;
+
+ case WM_SYSCOMMAND:
+ // eat screen saver message when fullscreen
+ if (((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER) && config_video_noss &&
+ video_isVideoPlaying())
+ {
+ return -1;
+ }
+ break;
+ }
+
+ if (FALSE != IsDirectMouseWheelMessage(uMsg))
+ {
+ SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static void VideoClose()
+{
+ sizeOnOpen=false;
+ if (!g_has_video_plugin)
+ return ;
+
+ if (m_videooutput && m_videooutput->is_fullscreen() && config_video_remove_fs_on_stop)
+ videoForceFullscreenOff();
+
+ if ((!m_videooutput && (bool)config_video_autoclose)
+ || (m_videooutput && !m_videooutput->is_fullscreen() && (bool)config_video_autoclose))
+ HideVideoWindow(false);
+}
+
+extern "C"
+{
+ void videoAdSizeChanged()
+ {
+ LayoutChildren(config_video_width, config_video_height);
+ }
+
+ void *video_getIVideoOutput()
+ {
+ return (void *)m_videooutput;
+ }
+
+ int video_isVideoPlaying()
+ {
+ if (!m_videooutput) return 0;
+ return m_videooutput->isVideoPlaying();
+ }
+
+ void videoGoFullscreen()
+ {
+ if (m_videooutput)
+ {
+ m_videooutput->fullscreen();
+ }
+ }
+
+ int videoIsFullscreen()
+ {
+ if (m_videooutput) return !!m_videooutput->is_fullscreen();
+ return 0;
+ }
+
+ void videoReinit()
+ {
+ if (m_videooutput)
+ PostMessageW(m_videooutput->getHwnd(), WM_USER + 0x1, 0, 0);
+ }
+
+ void videoForceFullscreenOff()
+ {
+ if (m_videooutput)
+ {
+ m_videooutput->remove_fullscreen();
+ LayoutChildren(config_video_width, config_video_height);
+ }
+ }
+
+ void videoToggleFullscreen()
+ {
+ if (m_videooutput)
+ {
+ if (!m_videooutput->is_fullscreen())
+ videoGoFullscreen();
+ else
+ videoForceFullscreenOff();
+ }
+ }
+
+ void videoSetFlip(int on)
+ {
+ if (m_videooutput)
+ {
+ m_videooutput->extended(VIDUSER_SET_VFLIP, on, 0);
+ }
+ // for consistency we need to update the state on the prefs page
+ if(prefs_last_page == 24 && IsWindow(prefs_hwnd))
+ {
+ SendMessageW(prefs_hwnd, WM_USER + 33, IDC_PREFS_VIDEO_FLIPRGB, on);
+ }
+ CheckMenuItem(GetSubMenu(GetSubMenu(top_menu, 3), 13), ID_VIDEOWND_VERTICALLYFLIP, (on ? MF_CHECKED: MF_UNCHECKED));
+ }
+
+ DWORD videoGetWidthHeightDWORD()
+ {
+ if (!m_videooutput) return 0;
+ return m_videooutput->GetWidthHeightDWORD();
+ }
+
+ HWND videoGetHwnd()
+ {
+ if (m_videooutput) return m_videooutput->getHwnd();
+ return NULL;
+ }
+
+ int video_getNumAudioTracks()
+ {
+ VideoOutput *vid = (VideoOutput *)video_getIVideoOutput();
+ if (!vid) return 1;
+ ITrackSelector *sel = vid->getTrackSelector();
+ if (!sel) return 1;
+ return sel->getNumAudioTracks();
+ }
+
+ int video_getNumVideoTracks()
+ {
+ VideoOutput *vid = (VideoOutput *)video_getIVideoOutput();
+ if (!vid) return 1;
+ ITrackSelector *sel = vid->getTrackSelector();
+ if (!sel) return 1;
+ return sel->getNumVideoTracks();
+ }
+
+ int video_getCurAudioTrack()
+ {
+ VideoOutput *vid = (VideoOutput *)video_getIVideoOutput();
+ if (!vid) return 0;
+ ITrackSelector *sel = vid->getTrackSelector();
+ if (!sel) return 0;
+ return sel->getCurAudioTrack();
+ }
+
+ int video_getCurVideoTrack()
+ {
+ VideoOutput *vid = (VideoOutput *)video_getIVideoOutput();
+ if (!vid) return 0;
+ ITrackSelector *sel = vid->getTrackSelector();
+ if (!sel) return 0;
+ return sel->getCurVideoTrack();
+ }
+
+ int video_setCurAudioTrack(int track)
+ {
+ VideoOutput *vid = (VideoOutput *)video_getIVideoOutput();
+ if (!vid) return 0;
+ ITrackSelector *sel = vid->getTrackSelector();
+ if (!sel) return 0;
+ sel->setAudioTrack(track);
+ return sel->getCurAudioTrack();
+ }
+
+ int video_setCurVideoTrack(int track)
+ {
+ VideoOutput *vid = (VideoOutput *)video_getIVideoOutput();
+ if (!vid) return 0;
+ ITrackSelector *sel = vid->getTrackSelector();
+ if (!sel) return 0;
+ sel->setVideoTrack(track);
+ return sel->getCurVideoTrack();
+ }
+
+ HWND video_Create()
+ {
+ return CreateWindowExW(WS_EX_ACCEPTFILES, L"Winamp Video", getStringW(IDS_VIDEOCAPTION, NULL, 0), (WS_OVERLAPPED | WS_CLIPCHILDREN)&(~WS_CAPTION),
+ config_video_wx, config_video_wy, config_video_width, config_video_height,
+ hMainWindow, NULL, GetModuleHandle(NULL), NULL);
+ }
+} \ No newline at end of file
diff --git a/Src/Winamp/video.h b/Src/Winamp/video.h
new file mode 100644
index 00000000..fb101a4e
--- /dev/null
+++ b/Src/Winamp/video.h
@@ -0,0 +1,28 @@
+#ifndef _VIDEO_H
+#define _VIDEO_H
+#include "main.h"
+#include "wa_ipc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void SetExteriorSize(int width, int height);
+ int video_getNumAudioTracks();
+ int video_getNumVideoTracks();
+ int video_getCurAudioTrack();
+ int video_getCurVideoTrack();
+ int video_setCurAudioTrack(int track);
+ int video_setCurVideoTrack(int track);
+ void Vid_Cmd( windowCommand *wc);
+ HWND videoGetHwnd();
+ DWORD videoGetWidthHeightDWORD();
+ void *video_getIVideoOutput();
+ void videoAdSizeChanged();
+ void videoReinit();
+ void videoGoFullscreen();
+ void videoSetFlip(int on);
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/video_ipc.cpp b/Src/Winamp/video_ipc.cpp
new file mode 100644
index 00000000..154b6d64
--- /dev/null
+++ b/Src/Winamp/video_ipc.cpp
@@ -0,0 +1,111 @@
+#include "Main.h"
+#include "video.h"
+extern "C"
+{
+ extern wchar_t vidoutbuf_save[];
+}
+int WINAPI VideoIPCProcedure(int which, WPARAM data, LRESULT *returnValue)
+{
+ switch (which)
+ {
+ case IPC_GETNUMAUDIOTRACKS:
+ *returnValue = video_getNumAudioTracks();
+ return 1;
+
+ case IPC_GETNUMVIDEOTRACKS:
+ *returnValue = video_getNumVideoTracks();
+ return 1;
+
+ case IPC_GETAUDIOTRACK:
+ *returnValue = video_getCurAudioTrack();
+ return 1;
+
+ case IPC_GETVIDEOTRACK:
+ *returnValue = video_getCurVideoTrack();
+ return 1;
+
+ case IPC_SETAUDIOTRACK:
+ *returnValue = video_setCurAudioTrack(data);
+ return 1;
+
+ case IPC_SETVIDEOTRACK:
+ *returnValue = video_setCurVideoTrack(data);
+ return 1;
+
+ case IPC_SETSTOPONVIDEOCLOSE:
+ config_video_stopclose = data;
+ *returnValue = 0;
+ return 1;
+
+ case IPC_GETSTOPONVIDEOCLOSE:
+ *returnValue = config_video_stopclose;
+ return 1;
+
+ case IPC_GETVIDEORESIZE:
+ *returnValue = config_video_updsize;
+ return 1;
+
+ case IPC_SETVIDEORESIZE:
+ config_video_updsize = data;
+ *returnValue = 0;
+ return 1;
+
+ case IPC_GETWND:
+ if (data == IPC_GETWND_VIDEO)
+ {
+ *returnValue = (LRESULT)hVideoWindow;
+ return 1;
+ }
+ break;
+
+ case IPC_ISWNDVISIBLE:
+ if (data == IPC_GETWND_VIDEO)
+ {
+ *returnValue = config_video_open;
+ return 1;
+ }
+ break;
+
+ case IPC_ENABLEDISABLE_ALL_WINDOWS:
+ EnableWindow(hVideoWindow, data != 0xdeadbeef);
+ break;
+
+ case IPC_GETINFO:
+ if (data == 3)
+ {
+ *returnValue = videoGetWidthHeightDWORD();
+ return 1;
+ }
+ if (data == 4)
+ {
+ *returnValue = (LRESULT) vidoutbuf_save;
+ return 1;
+ }
+ break;
+
+ case IPC_HAS_VIDEO_SUPPORT:
+ *returnValue = g_has_video_plugin;
+ return 1;
+
+ case IPC_IS_PLAYING_VIDEO:
+ *returnValue = video_isVideoPlaying() ? 2 : 0;
+ return 1;
+
+ case IPC_IS_FULLSCREEN:
+ if (is_fullscreen_video)
+ {
+ *returnValue = 1;
+ return 1;
+ }
+ break;
+
+ case IPC_GET_IVIDEOOUTPUT:
+ *returnValue = (LRESULT)video_getIVideoOutput();
+ return 1;
+
+ case IPC_VIDCMD:
+ Vid_Cmd((windowCommand*)data);
+ break;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Winamp/videoui.cpp b/Src/Winamp/videoui.cpp
new file mode 100644
index 00000000..3911705b
--- /dev/null
+++ b/Src/Winamp/videoui.cpp
@@ -0,0 +1,203 @@
+#include "Main.h"
+#include "video.h"
+#include "resource.h"
+
+
+
+#define inreg(x,y,x2,y2) \
+ ((mouse_x <= ( x2 ) && mouse_x >= ( x ) && \
+ mouse_y <= ( y2 ) && mouse_y >= ( y )))
+
+static int mouse_x, mouse_y, mouse_type, mouse_stats;
+
+static int which_cap=0;
+enum { NO_CAP,TITLE_CAP,TB_CAP, SZ_CAP,VW_CAP};
+
+static void do_titlebar();
+static void do_titlebuttons();
+static void do_size();
+static void do_vw();
+
+void videoui_handlemouseevent(int x, int y, int type, int stats)
+{
+ mouse_x = x;
+ mouse_y = y;
+ mouse_type = type;
+ mouse_stats = stats;
+ switch (which_cap)
+ {
+ case VW_CAP: do_vw(); return;
+ case TITLE_CAP: do_titlebar();return;
+ case TB_CAP: do_titlebuttons();return;
+ case SZ_CAP: do_size(); return;
+ default: break;
+ }
+ do_vw();
+ do_titlebuttons();
+ do_size();
+ do_titlebar();
+}
+
+static void do_titlebar()
+{
+ if (which_cap == TITLE_CAP || (!which_cap && (config_easymove || mouse_y < 14)))
+ {
+ static int clickx, clicky;
+ switch (mouse_type)
+ {
+ case 1:
+ {
+ which_cap=TITLE_CAP;
+ clickx=mouse_x;
+ clicky=mouse_y;
+ }
+ break;
+ case -1:
+ which_cap=0;
+ break;
+ case 0:
+ if (which_cap == TITLE_CAP && mouse_stats & MK_LBUTTON)
+ {
+ POINT p = { mouse_x, mouse_y};
+ ClientToScreen(hVideoWindow,&p);
+ p.x-=clickx;
+ p.y-=clicky;
+ SendMessageW(hVideoWindow,WM_USER+0x100,1,(LPARAM)&p);
+ }
+ break;
+ }
+ }
+}
+
+static void do_titlebuttons()
+{
+ int w=0;
+ w=inreg(config_video_width-10,3,config_video_width-1,3+9)?1:0;
+
+ if (w) // kill button
+ {
+ if (mouse_type == -1 && which_cap == TB_CAP)
+ {
+ which_cap=0;
+ draw_vw_tbutton(0);
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_VIDEO,0);
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ which_cap=TB_CAP;
+ draw_vw_tbutton(w?1:0);
+ }
+ }
+ else if (which_cap == TB_CAP)
+ {
+ which_cap=0;
+ draw_vw_tbutton(0);
+ }
+
+}
+
+static void do_vw()
+{
+ HWND videoGetHwnd();
+ int w=0;
+ w=inreg(9,config_video_height-29,89,config_video_height-11)?1:0;
+
+ if (w)
+ {
+ w=(mouse_x-9)/15;
+ if (mouse_type == -1 && which_cap == VW_CAP)
+ {
+ which_cap=0;
+ draw_vw_mbuts(-1);
+ switch (w)
+ {
+ case 0:
+ videoGoFullscreen();
+ break;
+ case 1:
+ if (videoGetHwnd()) SendMessageW(videoGetHwnd(),WM_COMMAND,ID_VIDEOWND_ZOOM100,0);
+ break;
+ case 2:
+ if (videoGetHwnd()) SendMessageW(videoGetHwnd(),WM_COMMAND,ID_VIDEOWND_ZOOM200,0);
+ break;
+ case 3:
+ SendMessageW(hMainWindow,WM_COMMAND,WINAMP_VIDEO_TVBUTTON,0);
+ break;
+ case 4:
+ // menu
+ if (videoGetHwnd()) SendMessageW(videoGetHwnd(),WM_RBUTTONUP,0,0);
+ break;
+ }
+ }
+ else if (mouse_stats & MK_LBUTTON)
+ {
+ which_cap=VW_CAP;
+ draw_vw_mbuts(w);
+ }
+ }
+ else if (which_cap == VW_CAP)
+ {
+ which_cap=0;
+ draw_vw_mbuts(-1);
+ }
+}
+
+
+static void do_size()
+{
+ if (which_cap == SZ_CAP || (!which_cap &&
+ mouse_x > config_video_width-20 && mouse_y > config_video_height-20 &&
+ ((config_video_width-mouse_x + config_video_height-mouse_y) <= 30)))
+ {
+ static int dx,dy;
+ if (!which_cap && mouse_type == 1)
+ {
+ dx=config_video_width-mouse_x;
+ dy=config_video_height-mouse_y;
+ which_cap=SZ_CAP;
+ }
+ if (which_cap == SZ_CAP)
+ {
+ int x,y;
+ if (mouse_type == -1)
+ {
+ which_cap=0;
+ }
+ x=mouse_x + dx;
+ y=mouse_y + dy;
+ int old_x = x;
+ int old_y = y;
+ if (config_video_width != x || config_video_height != y) // don't bother resizing if we're at the current size already.
+ {
+ if (x >= GetSystemMetrics(SM_CXSCREEN)) x = GetSystemMetrics(SM_CXSCREEN)-24;
+ if (y >= GetSystemMetrics(SM_CYSCREEN)) y = GetSystemMetrics(SM_CYSCREEN)-28;
+
+
+ if (!config_embedwnd_freesize)
+ {
+ x += 24;
+ x -= x%25;
+ y += 28;
+ y -= y%29;
+ }
+ if (x < 275) x = 275;
+ if (y < 20+38+29+29) y = 20+38+29+29;
+ //config_video_width = x;
+ //config_video_height= y;
+
+ if (!((old_x < config_video_width && x > config_video_width)
+ || (old_y < config_video_height && y > config_video_height))) // don't snap out a size if we're moving the mouse inward (video might not have started snapped)
+ {
+
+ SetExteriorSize(x,y);
+ //SetWindowPos(hVideoWindow,0,0,0,x,y,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
+ {
+ HDC hdc=GetWindowDC(hVideoWindow);
+ draw_vw(hdc);
+ ReleaseDC(hVideoWindow,hdc);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Src/Winamp/vu.cpp b/Src/Winamp/vu.cpp
new file mode 100644
index 00000000..602f098b
--- /dev/null
+++ b/Src/Winamp/vu.cpp
@@ -0,0 +1,238 @@
+#include "main.h"
+#include "../nu/AutoLock.h"
+#include <math.h>
+#include "WinampAttributes.h"
+#include "../nsutil/stats.h"
+using namespace Nullsoft::Utility;
+
+struct VU_list
+{
+ int timestamp;
+ unsigned char data[2]; // two channels for now, we'll worry about more later
+};
+
+static VU_list *vu_bufs;
+static int vu_position, vu_length, vu_size;
+static int last_pos;
+
+LockGuard VU_guard GUARDNAME("VU Guard");
+
+void vu_init(int numframes, int srate)
+{
+ AutoLock lock (VU_guard LOCKNAME("vu_init"));
+
+ vu_length = 0;
+ if (numframes < 1) numframes = 1;
+
+ if (numframes > vu_size)
+ {
+ free(vu_bufs);
+ vu_bufs = (VU_list *)calloc(numframes, sizeof(VU_list));
+ vu_size = numframes;
+ }
+ vu_position = 0;
+ vu_length = numframes;
+ last_pos = 0;
+}
+
+void vu_deinit(void)
+{
+ AutoLock lock (VU_guard LOCKNAME("vu_deinit"));
+ vu_length = 0;
+}
+
+void VU_Create()
+{
+ vu_length = vu_size = 0;
+}
+
+void VU_Destroy()
+{
+ free(vu_bufs);
+ vu_bufs = 0;
+ vu_size = 0;
+}
+
+int vu_add(char *values, int timestamp)
+{
+ AutoLock lock (VU_guard LOCKNAME("vu_add"));
+
+ if (!vu_bufs || vu_length == 0)
+ return 1;
+
+ if (vu_length < 2)
+ {
+ vu_position = 0;
+ }
+
+ vu_bufs[vu_position].timestamp = timestamp;//+600;
+
+ memcpy(vu_bufs[vu_position].data, values, 2);
+
+ vu_position++;
+ if (vu_position >= vu_length)
+ vu_position -= vu_length;
+
+ return 0;
+}
+
+bool vu_get(int timestamp, unsigned char data[2])
+{
+ int x, closest = 1000000, closest_v = -1;
+ int i;
+
+ AutoLock lock (VU_guard LOCKNAME("vu_get"));
+
+ if (!vu_bufs || vu_length==0)
+ return false;
+
+ if (vu_length < 2)
+ {
+ memcpy(data, vu_bufs[0].data, 2);
+ return true;
+ }
+
+ i = last_pos;
+ for (x = 0; x < vu_length; x ++)
+ {
+ int d;
+ if (i >= vu_length) i = 0;
+ d = timestamp - vu_bufs[i].timestamp;
+ if (d < 0) d = -d;
+ if (d < closest)
+ {
+ closest = d;
+ closest_v = i;
+ }
+ else if (closest < 200) break;
+ i++;
+ }
+
+ if (closest < 200 && closest_v >= 0)
+ {
+ last_pos = closest_v;
+ memcpy(data, vu_bufs[closest_v].data, 2);
+ return true;
+ }
+
+ return false;
+}
+
+int export_vu_get(int channel)
+{
+ if (channel>2 || channel<0)
+ return -1;
+ unsigned char data[2];
+ int now = in_getouttime();
+ if (vu_get(now, data))
+ return data[channel];
+ else
+ return -1;
+}
+
+float historyL=0, historyR=0;
+static void FillFloat(float *floatBuf, void *samples, size_t bps, size_t numSamples, size_t numChannels, float preamp)
+{
+ switch(bps)
+ {
+ case 8:
+ {
+ preamp /= 256.0f;
+ unsigned __int8 *samples8 = (unsigned __int8 *)samples;
+ for (size_t x = 0; x != numSamples; x ++)
+ {
+ floatBuf[x] = (float)(samples8[x*numChannels]-128) * preamp;
+ }
+ }
+ break;
+ case 16:
+ {
+ preamp/=32768.0f;
+ short *samples16 = (short *)samples;
+ for (size_t x = 0; x != numSamples; x ++)
+ {
+ floatBuf[x] = (float)samples16[x*numChannels] * preamp;
+ }
+ }
+ break;
+ case 24:
+ {
+ preamp/=2147483648.0f;
+ unsigned __int8 *samples8 = (unsigned __int8 *)samples;
+ for (size_t x = 0; x != numSamples; x ++)
+ {
+ long temp = (((long)samples8[0]) << 8);
+ temp = temp | (((long)samples8[1]) << 16);
+ temp = temp | (((long)samples8[2]) << 24);
+ floatBuf[x] = (float)temp * preamp;
+ samples8+=3*numChannels;
+ }
+ }
+ break;
+ case 32:
+ {
+ preamp /= 2147483648.0f;
+ int32_t *samples32 = (int32_t *)samples;
+ for (size_t x = 0; x != numSamples; x ++)
+ {
+ floatBuf[x] = (float)samples32[x*numChannels] * preamp;
+ }
+ }
+ break;
+ }
+}
+
+void calcVuData(unsigned char *out, char *data, const int channels, const int bits)
+{
+ static float left_peak=10.0f, left_history=0.0f;
+ static float right_peak=10.0f, right_history=0.0f;
+
+ float left[576] = {0}, right[576] = {0};
+ float left_rms, right_rms;
+
+ float scale = 1.0;
+ if (config_replaygain)
+ scale= 1.0f/pow(10.0f, config_replaygain_non_rg_gain.GetFloat() / 20.0f);
+
+ FillFloat(left, data, bits, 576, channels, scale);
+ if (channels > 1)
+ FillFloat(right, data+(bits/8), bits, 576, channels, scale);
+ else
+ memcpy(right, left, 576*sizeof(float));
+
+ nsutil_stats_RMS_F32(left, 576, &left_rms);
+ nsutil_stats_RMS_F32(right, 576, &right_rms);
+
+ // use a simple one-pole IIR to 'adjust' the vu meter to the songs loudness level
+ // the small constant
+ left_peak = 0.855f*left_peak + 0.095f*left_rms + 0.5f;
+ left_rms = 10.0f*left_rms /left_peak;
+
+ right_peak = 0.855f*right_peak + 0.095f*right_rms + 0.5f;
+ right_rms = 10.0f*right_rms /right_peak;
+
+ float left_db=left_rms*left_rms;
+ float right_db=right_rms*right_rms;
+
+
+
+ if (left_db < left_history)
+ left_db = left_db*0.2f + left_history*0.8f;
+ else
+ left_db = left_db*0.75f + left_history*0.25f;
+
+ if (right_db < right_history)
+ right_db = right_db*0.2f + right_history*0.8f;
+ else
+ right_db = right_db*0.75f + right_history*0.25f;
+
+ left_history = left_db;
+ right_history = right_db;
+ left_db = min(left_db, 255);
+ left_db = max(left_db, 0);
+ right_db = min(right_db, 255);
+ right_db = max(right_db, 0);
+
+ out[0] = (unsigned char)(left_db );
+ out[1] = (unsigned char)(right_db);
+} \ No newline at end of file
diff --git a/Src/Winamp/wa_dlg.h b/Src/Winamp/wa_dlg.h
new file mode 100644
index 00000000..62fb63da
--- /dev/null
+++ b/Src/Winamp/wa_dlg.h
@@ -0,0 +1,458 @@
+/*
+** Copyright © 2003-2014 Winamp SA
+**
+** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
+** liable for any damages arising from the use of this software.
+**
+** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
+** alter it and redistribute it freely, subject to the following restrictions:
+**
+** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
+** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+**
+** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+**
+** 3. This notice may not be removed or altered from any source distribution.
+**
+*/
+
+#ifndef _WA_DLG_H_
+#define _WA_DLG_H_
+
+#include "wa_ipc.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ 1) gen.bmp has a generic window frame for plugins to use.
+ its format is similar to the minibrowser's.
+ In addition gen.bmp includes a font for the titlebar, in both
+ highlight and no-highlight modes. The font is variable width,
+ and it uses the first color before the letter A as the delimiter.
+ The no-highlight form of letter must be the same width as the
+ highlight form.
+ 2) genex.bmp has button and scrollbar images, as well as some individual
+ pixels that describe the colors for the dialog. The button and
+ scrollbar images should be self explanatory (note that the buttons
+ have 4 pixel sized edges that are not stretched, and the center is
+ stretched), and the scrollbars do something similar.
+ The colors start at (48,0) and run every other pixel. The meaning
+ of each pixel is:
+ x=48: item background (background to edits, listviews etc)
+ x=50: item foreground (text color of edit/listview, etc)
+ x=52: window background (used to set the bg color for the dialog)
+ x=54: button text color
+ x=56: window text color
+ x=58: color of dividers and sunken borders
+ x=60: selection color for playlists
+ x=62: listview header background color
+ x=64: listview header text color
+ x=66: listview header frame top color
+ x=68: listview header frame middle color
+ x=70: listview header frame bottom color
+ x=72: listview header empty color
+ x=74: scrollbar foreground color
+ x=76: scrollbar background color
+ x=78: inverse scrollbar foreground color
+ x=80: inverse scrollbar background color
+ x=82: scrollbar dead area color
+ x=84: listview/treeview selection bar text color (active)
+ x=86: listview/treeview selection bar back color (active)
+ x=88: listview/treeview selection bar text color (inactive)
+ x=90: listview/treeview selection bar back color (inactive)
+ x=92: listview header alternating background color (added with 5.55+ or will revert to x=48)
+ x=94: listview header alternating text color (added with 5.55+ or will revert to x=50)
+*/
+
+#define DCW_SUNKENBORDER 0x00010000
+#define DCW_DIVIDER 0x00020000
+
+enum
+{
+ WADLG_ITEMBG,
+ WADLG_ITEMFG,
+ WADLG_WNDBG,
+ WADLG_BUTTONFG,
+ WADLG_WNDFG,
+ WADLG_HILITE,
+ WADLG_SELCOLOR,
+ WADLG_LISTHEADER_BGCOLOR,
+ WADLG_LISTHEADER_FONTCOLOR,
+ WADLG_LISTHEADER_FRAME_TOPCOLOR,
+ WADLG_LISTHEADER_FRAME_MIDDLECOLOR,
+ WADLG_LISTHEADER_FRAME_BOTTOMCOLOR,
+ WADLG_LISTHEADER_EMPTY_BGCOLOR,
+ WADLG_SCROLLBAR_FGCOLOR,
+ WADLG_SCROLLBAR_BGCOLOR,
+ WADLG_SCROLLBAR_INV_FGCOLOR,
+ WADLG_SCROLLBAR_INV_BGCOLOR,
+ WADLG_SCROLLBAR_DEADAREA_COLOR,
+ WADLG_SELBAR_FGCOLOR,
+ WADLG_SELBAR_BGCOLOR,
+ WADLG_INACT_SELBAR_FGCOLOR,
+ WADLG_INACT_SELBAR_BGCOLOR,
+ WADLG_ITEMBG2, // added with 5.55+ (otherwise will revert to WADLG_ITEMBG)
+ WADLG_ITEMFG2, // added with 5.55+ (otherwise will revert to WADLG_ITEMBG)
+ WADLG_NUM_COLORS
+};
+
+typedef enum _WACURSOR // used in IPC_GETSKINCURSORS
+{
+ WACURSOR_VOLUME = 0, // volume & balane
+ WACURSOR_POSITION = 1, // position
+ WACURSOR_BTN_WINSHADE = 2, // winshade
+ WACURSOR_BTN_MINIMIZE = 3, // minimize
+ WACURSOR_BTN_CLOSE = 4, // close
+ WACURSOR_MENU = 5, // main menu
+ WACURSOR_TITLEBAR = 6, // title bar
+ WACURSOR_SONGNAME = 7,
+ WACURSOR_NORMAL = 8,
+ WACURSOR_WINSHADE_BTN_WINSHADE = 9,
+ WACURSOR_WINSHADE_BTN_MINIMIZE = 10,
+ WACURSOR_WINSHADE_POSITION = 11,
+ WACURSOR_WINSHADE_BTN_CLOSE = 12,
+ WACURSOR_WINSHADE_MENU = 13,
+ WACURSOR_WINSHADE_NORMAL = 14,
+ WACURSOR_PL_BTN_WINSHADE = 15,
+ WACURSOR_PL_BTN_CLOSE = 16,
+ WACURSOR_PL_TITLEBAR = 17,
+ WACURSOR_PL_VSCROLL = 18,
+ WACURSOR_PL_RESIZE = 19,
+ WACURSOR_PL_NORMAL = 20,
+ WACURSOR_PL_WINSHADE_BTN_WINSHADE = 21,
+ WACURSOR_PL_WINSHADE_BTN_CLOSE = 22,
+ WACURSOR_PL_WINSHADE_HSIZE = 23,
+ WACURSOR_PL_WINSHADE_NORMAL = 24,
+ WACURSOR_EQ_SLIDER = 25,
+ WACURSOR_EQ_BTN_CLOSE = 26,
+ WACURSOR_EQ_TITLEBAR = 27,
+ WACURSOR_EQ_NORMAL = 28,
+} WACURSOR;
+
+void WADlg_init(HWND hwndWinamp); // call this on init, or on WM_DISPLAYCHANGE
+int WADlg_initted();
+void WADlg_close();
+int WADlg_getColor(int idx);
+HBITMAP WADlg_getBitmap();
+void WADlg_setSolidBorder(int solidborder);
+
+LRESULT WADlg_handleDialogMsgs(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); //
+void WADlg_DrawChildWindowBorders(HWND hwndDlg, int *tab, int tabsize); // each entry in tab would be the id | DCW_*
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif//_WA_DLG_H_
+
+
+// define WA_DLG_IMPLEMENT in one of your source files before including this .h
+// if you are making a media library plugin, you dont need to do this, look at view_ex for
+// an example of how to get the function *'s via an IPC message.
+
+#if (defined WA_DLG_IMPLEMENT && !defined WA_DLG_IMPLEMENT_DONE)
+#define WA_DLG_IMPLEMENT_DONE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static int wadlg_solidborder=0;
+static HBRUSH wadlg_lastbrush=0;
+static HBITMAP wadlg_bitmap=0; // load this manually
+static int wadlg_colors[WADLG_NUM_COLORS];
+static int wadlg_defcolors[WADLG_NUM_COLORS]=
+{
+ RGB(0,0,0),
+ RGB(0,255,0),
+ RGB(36,36,60),
+ RGB(57,56,66),
+ RGB(255,255,255),
+ RGB(132,148,165),
+ RGB(0,0,198),
+ RGB(72,72,120),
+ RGB(255,255,255),
+ RGB(108,108,180),
+ RGB(36,36,60),
+ RGB(18,18,30),
+ RGB(36,36,60),
+ RGB(36,36,60),
+ RGB(36,36,60),
+ RGB(121,130,150),
+ RGB(78,88,110),
+ RGB(36,36,60),
+ RGB(255,255,255),
+ RGB(0,0,180),
+ RGB(0,255,0),
+ RGB(0,0,128),
+ RGB(0,0,0),
+ RGB(0,255,0),
+};
+
+int WADlg_initted()
+{
+ return !!wadlg_bitmap;
+}
+
+int WADlg_getColor(int idx)
+{
+ if (idx < 0 || idx >= WADLG_NUM_COLORS) return 0;
+ return wadlg_colors[idx];
+}
+
+HBITMAP WADlg_getBitmap()
+{
+ return wadlg_bitmap;
+}
+
+// set this to draw the border all the way around the control
+void WADlg_setSolidBorder(int solidborder)
+{
+ wadlg_solidborder = solidborder;
+}
+
+void WADlg_init(HWND hwndWinamp) // call this on init, or on WM_DISPLAYCHANGE
+{
+ if (wadlg_bitmap) DeleteObject(wadlg_bitmap);
+ wadlg_bitmap = (HBITMAP) SendMessage(hwndWinamp,WM_WA_IPC,0,IPC_GET_GENSKINBITMAP);
+ if (wadlg_bitmap)
+ {
+ HDC tmpDC=CreateCompatibleDC(NULL);
+ HGDIOBJ o=SelectObject(tmpDC,(HGDIOBJ)wadlg_bitmap);
+ int defbgcol=GetPixel(tmpDC,111,0);
+ for (int x = 0; x < WADLG_NUM_COLORS; x ++)
+ {
+ int a=GetPixel(tmpDC,48+x*2,0);
+ if (a == CLR_INVALID || a == RGB(0,198,255) || a == defbgcol)
+ {
+ //defaults for old skins
+ if (x == WADLG_SELBAR_FGCOLOR || x == WADLG_INACT_SELBAR_FGCOLOR) a=wadlg_colors[WADLG_WNDFG];
+ else if (x == WADLG_SELBAR_BGCOLOR || x == WADLG_INACT_SELBAR_BGCOLOR)
+ {
+ a=wadlg_colors[WADLG_SELCOLOR];
+ if (x == WADLG_INACT_SELBAR_BGCOLOR)
+ a=((a/2)&0x7F7F7F)+(((wadlg_colors[WADLG_WNDBG])/2)&0x7F7F7F);
+ }
+ else if (x == WADLG_ITEMBG2)
+ {
+ a=wadlg_colors[WADLG_ITEMBG];
+ }
+ else if (x == WADLG_ITEMFG2)
+ {
+ a=wadlg_colors[WADLG_ITEMFG];
+ }
+ else a=wadlg_defcolors[x];
+ }
+ wadlg_colors[x]=a;
+ }
+
+ SelectObject(tmpDC,o);
+ DeleteDC(tmpDC);
+ }
+}
+
+void WADlg_close()
+{
+ if (wadlg_bitmap) DeleteObject(wadlg_bitmap);
+ wadlg_bitmap=0;
+ if (wadlg_lastbrush) DeleteObject(wadlg_lastbrush);
+ wadlg_lastbrush=0;
+}
+
+void WADlg_dotLine(HDC hdc, int left, int top, int len, int vert)
+{
+ for (int i=(top&1);i<len-1;i+=2)
+ {
+ if (vert)
+ {
+ MoveToEx(hdc,left,top+i,NULL);
+ LineTo(hdc,left,top+i+1);
+ }
+ else
+ {
+ MoveToEx(hdc,left+i,top,NULL);
+ LineTo(hdc,left+i+1,top);
+ }
+ }
+}
+
+LRESULT WADlg_handleDialogMsgs(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_DRAWITEM)
+ {
+ DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
+ if (di->CtlType == ODT_BUTTON)
+ {
+ wchar_t wt[256] = {0};
+ GetDlgItemTextW(hwndDlg,(INT)wParam,wt,ARRAYSIZE(wt));
+
+ HDC hdc = CreateCompatibleDC(di->hDC);
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdc, wadlg_bitmap);
+
+ RECT r=di->rcItem;
+ SetStretchBltMode(di->hDC,COLORONCOLOR);
+
+ int yoffs = (di->itemState & ODS_SELECTED) ? 15 : 0;
+
+ BitBlt(di->hDC,r.left,r.top,4,4,hdc,0,yoffs,SRCCOPY); // top left
+ StretchBlt(di->hDC,r.left+4,r.top,r.right-r.left-4-4,4,hdc,4,yoffs,47-4-4,4,SRCCOPY); // top center
+ BitBlt(di->hDC,r.right-4,r.top,4,4,hdc,47-4,yoffs,SRCCOPY); // top right
+
+ StretchBlt(di->hDC,r.left,r.top+4,4,r.bottom-r.top-4-4,hdc,0,4+yoffs,4,15-4-4,SRCCOPY); // left edge
+ StretchBlt(di->hDC,r.right-4,r.top+4,4,r.bottom-r.top-4-4,hdc,47-4,4+yoffs,4,15-4-4,SRCCOPY); // right edge
+
+ // center
+ StretchBlt(di->hDC,r.left+4,r.top+4,r.right-r.left-4-4,r.bottom-r.top-4-4,hdc,4,4+yoffs,47-4-4,15-4-4,SRCCOPY);
+
+ BitBlt(di->hDC,r.left,r.bottom-4,4,4,hdc,0,15-4+yoffs,SRCCOPY); // bottom left
+ StretchBlt(di->hDC,r.left+4,r.bottom-4,r.right-r.left-4-4,4,hdc,4,15-4+yoffs,47-4-4,4,SRCCOPY); // bottom center
+ BitBlt(di->hDC,r.right-4,r.bottom-4,4,4,hdc,47-4,15-4+yoffs,SRCCOPY); // bottom right
+
+ // draw text
+ SetBkMode(di->hDC,TRANSPARENT);
+
+ // this will do a different style for the button text depending on enabled state of the button
+ COLORREF colour = wadlg_colors[WADLG_BUTTONFG];
+ if (!IsWindowEnabled(di->hwndItem))
+ {
+ COLORREF fg = wadlg_colors[WADLG_WNDFG],
+ bg = wadlg_colors[WADLG_WNDBG];
+ colour = RGB((GetRValue(fg)+GetRValue(bg))/2,
+ (GetGValue(fg)+GetGValue(bg))/2,
+ (GetBValue(fg)+GetBValue(bg))/2);
+ }
+ SetTextColor(di->hDC,colour);
+
+ if (di->itemState & ODS_SELECTED) {r.left+=2; r.top+=2;}
+
+ r.right -= 4; r.left += 5;
+ DrawTextW(di->hDC,wt,-1,&r,DT_VCENTER|DT_SINGLELINE|DT_CENTER|DT_END_ELLIPSIS);
+ r.right += 4; r.left -= 5;
+
+ SelectObject(hdc, hbmpOld);
+ DeleteDC(hdc);
+
+ if (GetFocus()==di->hwndItem)
+ {
+ HPEN hpen = CreatePen(PS_SOLID,0,RGB(0,0,0));
+ HPEN hpenOld = (HPEN)SelectObject(di->hDC, hpen);
+ WADlg_dotLine(di->hDC,r.left+2,r.top+2,r.right-r.left-3,0);
+ WADlg_dotLine(di->hDC,r.right-3,r.top+2,r.bottom-r.top-3,1);
+ WADlg_dotLine(di->hDC,r.left+2,r.top+2,r.bottom-r.top-3,1);
+ WADlg_dotLine(di->hDC,r.left+2,r.bottom-3,r.right-r.left-3,0);
+ SelectObject(di->hDC, hpenOld);
+ DeleteObject(hpen);
+ }
+ }
+ }
+
+ switch (uMsg)
+ {
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSTATIC:
+ case WM_CTLCOLOREDIT:
+ {
+ int bgcolor=(uMsg == WM_CTLCOLOREDIT || uMsg == WM_CTLCOLORLISTBOX) ? wadlg_colors[WADLG_ITEMBG] : (uMsg == WM_CTLCOLORBTN ? wadlg_colors[WADLG_ITEMBG] : wadlg_colors[WADLG_WNDBG]);
+ LOGBRUSH lb={BS_SOLID,GetNearestColor((HDC)wParam,bgcolor)};
+ if (wadlg_lastbrush) DeleteObject(wadlg_lastbrush);
+ wadlg_lastbrush=CreateBrushIndirect(&lb);
+ SetTextColor((HDC)wParam,uMsg == WM_CTLCOLORSTATIC ? wadlg_colors[WADLG_WNDFG] : wadlg_colors[WADLG_ITEMFG]);
+ SetBkColor((HDC)wParam,lb.lbColor);
+ return (LRESULT)wadlg_lastbrush;
+ }
+ }
+ return 0;
+}
+
+static int RectInRect(RECT *rect1, RECT *rect2)
+{
+ // this has a bias towards true
+ // this could probably be optimized a lot
+ return ((rect1->top >= rect2->top && rect1->top <= rect2->bottom) ||
+ (rect1->bottom >= rect2->top && rect1->bottom <= rect2->bottom) ||
+ (rect2->top >= rect1->top && rect2->top <= rect1->bottom) ||
+ (rect2->bottom >= rect1->top && rect2->bottom <= rect1->bottom)) // vertical intersect
+ &&
+ ((rect1->left >= rect2->left && rect1->left <= rect2->right) ||
+ (rect1->right >= rect2->left && rect1->right <= rect2->right) ||
+ (rect2->left >= rect1->left && rect2->left <= rect1->right) ||
+ (rect2->right >= rect1->left && rect2->right <= rect1->right)) // horiz intersect
+ ;
+}
+
+static void WADlg_removeFromRgn(HRGN hrgn, int left, int top, int right, int bottom)
+{
+ HRGN rgn2=CreateRectRgn(left,top,right,bottom);
+ CombineRgn(hrgn,hrgn,rgn2,RGN_DIFF);
+ DeleteObject(rgn2);
+}
+
+void WADlg_DrawChildWindowBorders(HWND hwndDlg, int *tab, int tabsize)
+{
+ PAINTSTRUCT ps={0};
+ BeginPaint(hwndDlg,&ps);
+ HRGN hrgn = (ps.fErase) ? CreateRectRgnIndirect(&ps.rcPaint) : NULL;
+ HPEN pen = CreatePen(PS_SOLID, 0, wadlg_colors[WADLG_HILITE]);
+ HGDIOBJ o = SelectObject(ps.hdc, pen);
+
+ while (tabsize--)
+ {
+ RECT r = {0};
+ int a = *tab++;
+ GetWindowRect(GetDlgItem(hwndDlg, a & 0xffff),&r);
+ MapWindowPoints(HWND_DESKTOP, hwndDlg, (LPPOINT)&r, 2);
+
+ if (RectInRect(&ps.rcPaint,&r))
+ {
+ if ((a & 0xffff0000) == DCW_SUNKENBORDER)
+ {
+ MoveToEx(ps.hdc,r.left,r.bottom,NULL);
+ LineTo(ps.hdc,r.right,r.bottom);
+ LineTo(ps.hdc,r.right,r.top-1);
+ if (hrgn)
+ {
+ WADlg_removeFromRgn(hrgn,r.left,r.bottom,r.right,r.bottom+1);
+ WADlg_removeFromRgn(hrgn,r.right,r.top,r.right+1,r.bottom);
+ }
+ }
+ else if ((a & 0xffff0000) == DCW_DIVIDER)
+ {
+ if (r.right - r.left < r.bottom - r.top) // vertical
+ {
+ int left=(r.left+r.right)/2;
+ MoveToEx(ps.hdc,left,r.top,NULL);
+ LineTo(ps.hdc,left,r.bottom+1);
+ if (hrgn) WADlg_removeFromRgn(hrgn,left,r.top,left+1,r.bottom);
+ }
+ else // horiz
+ {
+ int top=(r.top+r.bottom)/2;
+ MoveToEx(ps.hdc,r.left,top,NULL);
+ LineTo(ps.hdc,r.right+1,top);
+ if (hrgn) WADlg_removeFromRgn(hrgn,r.left,top,r.right,top+1);
+ }
+ }
+ }
+ }
+
+ SelectObject(ps.hdc, o);
+ DeleteObject(pen);
+
+ if(hrgn)
+ {
+ //erase bkgnd while clipping out our own drawn stuff (for flickerless display)
+ HBRUSH b = CreateSolidBrush(wadlg_colors[WADLG_WNDBG]);
+ FillRgn(ps.hdc,hrgn,b);
+ DeleteObject(b);
+ DeleteObject(hrgn);
+ }
+ EndPaint(hwndDlg,&ps);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // WA_DLG_IMPLEMENT \ No newline at end of file
diff --git a/Src/Winamp/wa_ipc.h b/Src/Winamp/wa_ipc.h
new file mode 100644
index 00000000..95939e8a
--- /dev/null
+++ b/Src/Winamp/wa_ipc.h
@@ -0,0 +1,3172 @@
+/*
+** Copyright (C) 1997-2014 Winamp SA
+**
+** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
+** liable for any damages arising from the use of this software.
+**
+** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
+** alter it and redistribute it freely, subject to the following restrictions:
+**
+** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
+** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+**
+** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+**
+** 3. This notice may not be removed or altered from any source distribution.
+**
+*/
+
+#ifndef _WA_IPC_H_
+#define _WA_IPC_H_
+
+#include <windows.h>
+#include <stddef.h>
+#if (_MSC_VER <= 1200)
+typedef int intptr_t;
+#endif
+/*
+** This is the modern replacement for the classic 'frontend.h'. Most of these
+** updates are designed for in-process use, i.e. from a plugin.
+**
+*/
+
+/* Most of the IPC_* messages involve sending the message in the form of:
+** result = SendMessageW(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*);
+** Where different then this is specified (typically with WM_COPYDATA variants)
+**
+** When you use SendMessageW(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*) and specify a IPC_*
+** which is not currently implemented/supported by the Winamp version being used then it
+** will return 1 for 'result'. This is a good way of helping to check if an api being
+** used which returns a function pointer, etc is even going to be valid.
+*/
+
+
+#define WM_WA_IPC WM_USER
+/* but some of them use WM_COPYDATA. be afraid.
+*/
+
+#define WINAMP_VERSION_MAJOR(winampVersion) ((winampVersion & 0x0000FF00) >> 12)
+#define WINAMP_VERSION_MINOR(winampVersion) (winampVersion & 0x000000FF) // returns, i.e. 0x12 for 5.12 and 0x10 for 5.1...
+
+
+#define IPC_GETVERSION 0
+/* int version = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION);
+**
+** The version returned will be 0x20yx for Winamp 2.yx.
+** Versions previous to Winamp 2.0 typically (but not always) use 0x1zyx for 1.zx.
+** Just a bit weird but that's the way it goes.
+**
+** For Winamp 5.x it uses the format 0x50yx for Winamp 5.yx
+** e.g. 5.01 -> 0x5001
+** 5.09 -> 0x5009
+** 5.1 -> 0x5010
+**
+** Notes: For 5.02 this api will return the same value as for a 5.01 build.
+** For 5.07 this api will return the same value as for a 5.06 build.
+*/
+
+
+#define IPC_GETVERSIONSTRING 1
+
+
+#define IPC_GETREGISTEREDVERSION 770
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETREGISTEREDVERSION);
+**
+** This will open the Winamp Preferences and show the Winamp Pro page.
+*/
+
+
+#define IPC_IS_SAFEMODE 999
+/* (requires Winamp 5.64+)
+** int res = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_IS_SAFEMODE);
+**
+** This will indicate if running in safe mode or not (only applies to native plugins).
+** This returns:
+** 0 if in safe mode
+** 1 if in normal mode
+** 2 if in safe mode and media library plug-ins are to be disabled
+**
+** Safe mode is used to disable 3rd party plugins to determine if they are the cause
+** of stability issues and crashes for users experiencing issues without having to
+** first remove plug-in dlls which is often found 'too hard' to do properly most times.
+*/
+
+
+typedef struct {
+ const char *filename;
+ const char *title;
+ const char *ext;
+ int length;
+} enqueueFileWithMetaStruct; // send this to a IPC_PLAYFILE in a non WM_COPYDATA,
+// and you get the nice desired result. if title is NULL, it is treated as a "thing",
+// otherwise it's assumed to be a file (for speed)
+
+typedef struct {
+ const wchar_t *filename;
+ const wchar_t *title;
+ const wchar_t *ext;
+ int length;
+} enqueueFileWithMetaStructW;
+
+#define IPC_PLAYFILE 100 // dont be fooled, this is really the same as enqueufile
+#define IPC_ENQUEUEFILE 100
+#define IPC_PLAYFILEW 1100
+#define IPC_ENQUEUEFILEW 1100
+/* This is sent as a WM_COPYDATA with IPC_PLAYFILE as the dwData member and the string
+** of the file / playlist to be enqueued into the playlist editor as the lpData member.
+** This will just enqueue the file or files since you can use this to enqueue a playlist.
+** It will not clear the current playlist or change the playback state.
+**
+** COPYDATASTRUCT cds = {0};
+** cds.dwData = IPC_ENQUEUEFILE;
+** cds.lpData = (void*)"c:\\test\\folder\\test.mp3";
+** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char
+** SendMessageW(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds);
+**
+**
+** With 2.9+ and all of the 5.x versions you can send this as a normal WM_WA_IPC
+** (non WM_COPYDATA) with an enqueueFileWithMetaStruct as the param.
+** If the title member is null then it is treated as a "thing" otherwise it will be
+** assumed to be a file (for speed).
+**
+** enqueueFileWithMetaStruct eFWMS = {0};
+** eFWMS.filename = "c:\\test\\folder\\test.mp3";
+** eFWMS.title = "Whipping Good";
+** eFWMS.length = 300; // this is the number of seconds for the track
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&eFWMS,IPC_ENQUEUEFILE);
+*/
+
+
+#define IPC_DELETE 101
+#define IPC_DELETE_INT 1101
+/* SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE);
+** Use this api to clear Winamp's internal playlist.
+** You should not need to use IPC_DELETE_INT since it is used internally by Winamp when
+** it is dealing with some lame Windows Explorer issues (hard to believe that!).
+*/
+
+
+#define IPC_STARTPLAY 102
+#define IPC_STARTPLAY_INT 1102
+/* SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_STARTPLAY);
+** Sending this will start playback and is almost the same as hitting the play button.
+** The IPC_STARTPLAY_INT version is used internally and you should not need to use it
+** since it won't be any fun.
+*/
+
+
+#define IPC_CHDIR 103
+/* This is sent as a WM_COPYDATA type message with IPC_CHDIR as the dwData value and the
+** directory you want to change to as the lpData member.
+**
+** COPYDATASTRUCT cds = {0};
+** cds.dwData = IPC_CHDIR;
+** cds.lpData = (void*)"c:\\download";
+** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char
+** SendMessageW(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds);
+**
+** The above example will make Winamp change to the directory 'C:\download'.
+*/
+
+
+#define IPC_ISPLAYING 104
+/* int res = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING);
+** This is sent to retrieve the current playback state of Winamp.
+** If it returns 1, Winamp is playing.
+** If it returns 3, Winamp is paused.
+** If it returns 0, Winamp is not playing.
+*/
+
+
+#define IPC_GETOUTPUTTIME 105
+/* int res = SendMessageW(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME);
+** This api can return two different sets of information about current playback status.
+**
+** If mode = 0 then it will return the position (in ms) of the currently playing track.
+** Will return -1 if Winamp is not playing.
+**
+** If mode = 1 then it will return the current track length (in seconds).
+** Will return -1 if there are no tracks (or possibly if Winamp cannot get the length).
+**
+** If mode = 2 then it will return the current track length (in milliseconds).
+** Will return -1 if there are no tracks (or possibly if Winamp cannot get the length).
+*/
+
+
+#define IPC_JUMPTOTIME 106
+/* (requires Winamp 1.60+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME);
+** This api sets the current position (in milliseconds) for the currently playing song.
+** The resulting playback position may only be an approximate time since some playback
+** formats do not provide exact seeking e.g. mp3
+** This returns -1 if Winamp is not playing, 1 on end of file, or 0 if it was successful.
+*/
+
+
+#define IPC_GETMODULENAME 109
+#define IPC_EX_ISRIGHTEXE 666
+/* usually shouldnt bother using these, but here goes:
+** send a WM_COPYDATA with IPC_GETMODULENAME, and an internal
+** flag gets set, which if you send a normal WM_WA_IPC message with
+** IPC_EX_ISRIGHTEXE, it returns whether or not that filename
+** matches. lame, I know.
+*/
+
+
+#define IPC_WRITEPLAYLIST 120
+/* (requires Winamp 1.666+)
+** int cur = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST);
+**
+** IPC_WRITEPLAYLIST will write the current playlist to winamp.m3u and on unicode clients
+** it will also write the current playlist to winamp.m3u8. This will also return the
+** current playlist position (see IPC_GETLISTPOS).
+**
+** Where the playlist(s) are saved to depends on the Winamp client version used though it
+** is simple to find the path using the correct location (when working in-process):
+**
+** Pre 2.90 -> '<winampdir>\\Winamp.m3u'
+** From 2.90 to 5.1 -> Use IPC_GETINIDIRECTORY
+** From 5.11 -> Use IPC_GETM3UDIRECTORY
+**
+** If working from an external program then it is possible to work out the location of the
+** playlist by reading relevant values out of paths.ini (if found) otherwise the pre 2.90
+** behaviour is what will be attempted to be used (as Winamp does if there is any failure).
+**
+** This is kinda obsoleted by some of the newer 2.x api items but it still is good for
+** use with a front-end program (instead of a plug-in) and you want to see what is in the
+** current playlist.
+**
+** This api will only save out extended file information in the #EXTINF entry if Winamp
+** has already read the data such as if the file was played of scrolled into view. If
+** Winamp has not read the data then you will only find the file with its filepath entry
+** (as is the base requirements for a m3u playlist).
+*/
+
+
+#define IPC_SETPLAYLISTPOS 121
+/* (requires Winamp 2.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS)
+** IPC_SETPLAYLISTPOS sets the playlist position to the specified 'position'.
+** It will not change playback status or anything else. It will just set the current
+** position in the playlist and will update the playlist view if necessary.
+**
+** If you use SendMessageW(hwnd_winamp,WM_COMMAND,MAKEWPARAM(WINAMP_BUTTON2,0),0);
+** after using IPC_SETPLAYLISTPOS then Winamp will start playing the file at 'position'.
+*/
+
+
+#define IPC_SETVOLUME 122
+/* (requires Winamp 2.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME);
+** IPC_SETVOLUME sets the volume of Winamp (between the range of 0 to 255).
+**
+** If you pass 'volume' as -666 then the message will return the current volume.
+** int curvol = SendMessageW(hwnd_winamp,WM_WA_IPC,-666,IPC_SETVOLUME);
+*/
+
+
+#define IPC_GETVOLUME(hwnd_winamp) SendMessageW(hwnd_winamp,WM_WA_IPC,-666,IPC_SETVOLUME)
+/* (requires Winamp 2.0+)
+** int curvol = IPC_GETVOLUME(hwnd_winamp);
+** This will return the current volume of Winamp (between the range of 0 to 255).
+*/
+
+
+#define IPC_SETPANNING 123
+#define IPC_SETBALANCE 123
+/* (requires Winamp 2.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING);
+** IPC_SETPANNING sets the panning of Winamp from 0 (left) to 255 (right).
+**
+** At least in 5.x+ this works from -127 (left) to 127 (right).
+**
+** If you pass 'panning' as -666 to this api then it will return the current panning.
+** int curpan = SendMessageW(hwnd_winamp,WM_WA_IPC,-666,IPC_SETPANNING);
+*/
+
+
+#define IPC_GETPANNING(hwnd_winamp) SendMessageW(hwnd_winamp,WM_WA_IPC,-666,IPC_SETPANNING)
+#define IPC_GETBALANCE(hwnd_winamp) SendMessageW(hwnd_winamp,WM_WA_IPC,-666,IPC_SETBALANCE)
+/* (requires Winamp 2.0+)
+** int curpan = IPC_GETPANNING(hwnd_winamp);
+** This will return the current panning level of Winamp (5.x) from -127 (left) to 127 (right)
+** or from 0 (left) to 255 (right) on older client versions.
+*/
+
+
+#define IPC_GETLISTLENGTH 124
+/* (requires Winamp 2.0+)
+** int length = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH);
+** IPC_GETLISTLENGTH returns the length of the current playlist as the number of tracks.
+*/
+
+
+#define IPC_GETLISTPOS 125
+/* (requires Winamp 2.05+)
+** int pos=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS);
+** IPC_GETLISTPOS returns the current playlist position (which is shown in the playlist
+** editor as a differently coloured text entry e.g is yellow for the classic skin).
+**
+** This api is a lot like IPC_WRITEPLAYLIST but a lot faster since it does not have to
+** write out the whole of the current playlist first.
+*/
+
+
+#define IPC_GETNEXTLISTPOS 136
+/* (requires Winamp 5.61+)
+** int pos=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETNEXTLISTPOS);
+** IPC_GETNEXTLISTPOS returns the next playlist position expected to be played from the
+** current playlist and allows for determining the next playlist item to be played even
+** if shuffle mode (see IPC_GET_SHUFFLE) is enabled at the time of using this api.
+**
+** If there is no known next playlist item then this will return -1 i.e. if there's only
+** one playlist item or at the end of the current playlist and repeat is disabled.
+**
+** Notes: If a plug-in (like the JTFE plug-in) uses IPC_GET_NEXT_PLITEM to override the
+** playlist order then you will need to query the plug-in directly (via api_queue
+** for the JTFE plug-in) to get the correct next playlist item to be played.
+**
+** If a change is made to the internal shuffle table, the value returned by prior
+** use of this api is likely to be different and so will need to be re-queried.
+**
+** The returned playlist item position is zero-based.
+*/
+
+
+#define IPC_GETINFO 126
+/* (requires Winamp 2.05+)
+** int inf=SendMessageW(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO);
+** IPC_GETINFO returns info about the current playing song. The value
+** it returns depends on the value of 'mode'.
+** Mode Meaning
+** ------------------
+** 0 Samplerate, in kilohertz (i.e. 44)
+** 1 Bitrate (i.e. 128)
+** 2 Channels (i.e. 2)
+** 3 (5+) Video LOWORD=w HIWORD=h
+** 4 (5+) > 65536, string (video description)
+** 5 (5.25+) Samplerate, in hertz (i.e. 44100)
+*/
+
+
+#define IPC_GETEQDATA 127
+/* (requires Winamp 2.05+)
+** int data=SendMessageW(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
+** IPC_GETEQDATA queries the status of the EQ.
+** The value returned depends on what 'pos' is set to:
+** Value Meaning
+** ------------------
+** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db)
+** 10 The preamp value. 0-63 (+20db - -20db)
+** 11 Enabled. zero if disabled, nonzero if enabled.
+** 12 Autoload. zero if disabled, nonzero if enabled.
+*/
+
+
+#define IPC_SETEQDATA 128
+/* (requires Winamp 2.05+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA);
+** IPC_SETEQDATA sets the value of the last position retrieved
+** by IPC_GETEQDATA. This is pretty lame, and we should provide
+** an extended version that lets you do a MAKELPARAM(pos,value).
+** someday...
+
+ new (2.92+):
+ if the high byte is set to 0xDB, then the third byte specifies
+ which band, and the bottom word specifies the value.
+*/
+
+
+#define IPC_ADDBOOKMARK 129
+#define IPC_ADDBOOKMARKW 131
+/* (requires Winamp 2.4+)
+** This is sent as a WM_COPYDATA using IPC_ADDBOOKMARK as the dwData value and the
+** directory you want to change to as the lpData member. This will add the specified
+** file / url to the Winamp bookmark list.
+**
+** COPYDATASTRUCT cds = {0};
+** cds.dwData = IPC_ADDBOOKMARK;
+** cds.lpData = (void*)"http://www.blah.com/listen.pls";
+** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char
+** SendMessageW(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds);
+**
+**
+** In Winamp 5.0+ we use this as a normal WM_WA_IPC and the string is null separated as
+** the filename and then the title of the entry.
+**
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(char*)"filename\0title\0",IPC_ADDBOOKMARK);
+**
+** This will notify the library / bookmark editor that a bookmark was added.
+** Note that using this message in this context does not actually add the bookmark.
+** Do not use, it is essentially just a notification type message :)
+**
+** Additional Notes:
+**
+** If IPC_ADDBOOKMARK is called with wParam as zero then it returns the bookmark filepath
+** as an ansi string.
+**
+** As of 5.58+, calling IPC_ADDBOOKMARKW with wParam as zero will return the bookmark
+** filepath as a unicode string and IPC_ADDBOOKMARK will behave as prior to 5.58.
+** Passing wParam as 666 will return the winamp.bm8 filepath and is valid for both apis.
+*/
+
+
+#define IPC_INSTALLPLUGIN 130
+/* This is not implemented (and is very unlikely to be done due to safety concerns).
+** If it was then you could do a WM_COPYDATA with a path to a .wpz and it would then
+** install the plugin for you.
+**
+** COPYDATASTRUCT cds = {0};
+** cds.dwData = IPC_INSTALLPLUGIN;
+** cds.lpData = (void*)"c:\\path\\to\\file.wpz";
+** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char
+** SendMessageW(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds);
+*/
+
+
+#define IPC_RESTARTWINAMP 135
+/* (requires Winamp 2.2+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP);
+** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :) )
+** If this fails to make Winamp start after closing then there is a good chance one (or
+** more) of the currently installed plugins caused Winamp to crash on exit (either as a
+** silent crash or a full crash log report before it could call itself start again.
+*/
+
+
+#define IPC_RESTARTSAFEWINAMP 1135
+/* (requires Winamp 5.64+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTSAFEWINAMP);
+** IPC_RESTARTSAFEWINAMP will restart Winamp (isn't that obvious ? :) ) in safe mode.
+** If this fails to make Winamp start after closing then there is a good chance one (or
+** more) of the currently installed plugins caused Winamp to crash on exit (either as a
+** silent crash or a full crash log report before it could call itself start again.
+*/
+
+
+#define IPC_ISFULLSTOP 400
+/* (requires winamp 2.7+ I think)
+** int ret=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISFULLSTOP);
+** This is useful for when you're an output plugin and you want to see if the stop/close
+** happening is a full stop or if you are just between tracks. This returns zero if it is
+** a full stop (such as the user pressing stop) or non-zero if it is just the end of a
+** file or other internal events.
+*/
+
+
+#define IPC_INETAVAILABLE 242
+/* (requires Winamp 2.05+)
+** int val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE);
+** IPC_INETAVAILABLE will return 1 if an Internet connection is available for Winamp and
+** relates to the internet connection type setting on the main general preferences page
+** in the Winamp preferences.
+*/
+
+
+#define IPC_UPDTITLE 243
+/* (requires Winamp 2.2+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE);
+** IPC_UPDTITLE will ask Winamp to update the information about the current title and
+** causes GetFileInfo(..) in the input plugin associated with the current playlist entry
+** to be called. This can be called such as when an input plugin is buffering a file so
+** that it can cause the buffer percentage to appear in the playlist.
+*/
+
+
+#define IPC_REFRESHPLCACHE 247
+/* (requires Winamp 2.2+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE);
+** IPC_REFRESHPLCACHE will flush the playlist cache buffer and you send this if you want
+** Winamp to go refetch the titles for all of the entries in the current playlist.
+**
+** 5.3+:
+** If you pass a wchar_t * string in wParam then it will be be found using strnicmp() and
+** the cache for that entry only will be cleared unlike passing nothing which clears all.
+*/
+
+
+#define IPC_GET_SHUFFLE 250
+/* (requires Winamp 2.4+)
+** int val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE);
+** IPC_GET_SHUFFLE returns the status of the shuffle option.
+** If set then it will return 1 and if not set then it will return 0.
+*/
+
+
+#define IPC_GET_REPEAT 251
+/* (requires Winamp 2.4+)
+** int val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT);
+** IPC_GET_REPEAT returns the status of the repeat option.
+** If set then it will return 1 and if not set then it will return 0.
+*/
+
+
+#define IPC_SET_SHUFFLE 252
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE);
+** IPC_SET_SHUFFLE sets the status of the shuffle option.
+** If 'value' is 1 then shuffle is turned on.
+** If 'value' is 0 then shuffle is turned off.
+*/
+
+
+#define IPC_SET_REPEAT 253
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT);
+** IPC_SET_REPEAT sets the status of the repeat option.
+** If 'value' is 1 then shuffle is turned on.
+** If 'value' is 0 then shuffle is turned off.
+*/
+
+
+#define IPC_ENABLEDISABLE_ALL_WINDOWS 259 // 0xdeadbeef to disable
+/* (requires Winamp 2.9+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(enable?0:0xdeadbeef),IPC_ENABLEDISABLE_ALL_WINDOWS);
+** Sending this message with 0xdeadbeef as the param will disable all winamp windows and
+** any other values will enable all of the Winamp windows again. When disabled you won't
+** get any response on clicking or trying to do anything to the Winamp windows. If the
+** taskbar icon is shown then you may still have control ;)
+*/
+
+
+#define IPC_GETWND 260
+/* (requires Winamp 2.9+)
+** HWND h=SendMessageW(hwnd_winamp,WM_WA_IPC,IPC_GETWND_xxx,IPC_GETWND);
+** returns the HWND of the window specified.
+*/
+ #define IPC_GETWND_EQ 0 // use one of these for the param
+ #define IPC_GETWND_PE 1
+ #define IPC_GETWND_MB 2
+ #define IPC_GETWND_VIDEO 3
+#define IPC_ISWNDVISIBLE 261 // same param as IPC_GETWND
+
+
+/************************************************************************
+***************** in-process only (WE LOVE PLUGINS)
+************************************************************************/
+
+#define IPC_SETSKINW 199
+#define IPC_SETSKIN 200
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN);
+** IPC_SETSKIN sets the current skin to "skinname". Note that skinname
+** can be the name of a skin, a skin .zip file, with or without path.
+** If path isn't specified, the default search path is the winamp skins
+** directory.
+*/
+
+
+#define IPC_GETSKIN 201
+#define IPC_GETSKINW 1201
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN);
+** IPC_GETSKIN puts the directory where skin bitmaps can be found
+** into skinname_buffer.
+** skinname_buffer must be MAX_PATH characters in length.
+** When using a .zip'd skin file, it'll return a temporary directory
+** where the ZIP was decompressed.
+*/
+
+
+#define IPC_EXECPLUG 202
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG);
+** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM.
+** the format of this string can be:
+** "vis_whatever.dll"
+** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir)
+** "C:\\dir\\vis_whatever.dll,1"
+*/
+
+
+#define IPC_GETPLAYLISTFILE 211
+#define IPC_GETPLAYLISTFILEW 214
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** char *name=SendMessageW(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE);
+** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index].
+** returns a pointer to it. returns NULL on error.
+*/
+
+
+#define IPC_GETPLAYLISTTITLE 212
+#define IPC_GETPLAYLISTTITLEW 213
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** char *name=SendMessageW(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE);
+**
+** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index].
+** returns a pointer to it. returns NULL on error.
+*/
+
+
+#define IPC_GETHTTPGETTER 240
+/* retrieves a function pointer to a HTTP retrieval function.
+** if this is unsupported, returns 1 or 0.
+** the function should be:
+** int (*httpRetrieveFile)(HWND hwnd, char *url, char *file, char *dlgtitle);
+** if you call this function, with a parent window, a URL, an output file, and a dialog title,
+** it will return 0 on successful download, 1 on error.
+*/
+
+
+#define IPC_GETHTTPGETTERW 1240
+/* int (*httpRetrieveFileW)(HWND hwnd, char *url, wchar_t *file, wchar_t *dlgtitle); */
+
+
+#define IPC_MBOPEN 241
+/* (requires Winamp 2.05+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN);
+** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window.
+*/
+
+
+#define IPC_CHANGECURRENTFILE 245
+/* (requires Winamp 2.05+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE);
+** IPC_CHANGECURRENTFILE will set the current playlist item.
+*/
+
+
+#define IPC_CHANGECURRENTFILEW 1245
+/* (requires Winamp 5.3+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILEW);
+** IPC_CHANGECURRENTFILEW will set the current playlist item.
+*/
+
+
+#define IPC_GETMBURL 246
+/* (requires Winamp 2.2+)
+** char buffer[4096]; // Urls can be VERY long
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL);
+** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer.
+** buffer must be at least 4096 bytes long.
+*/
+
+
+#define IPC_MBBLOCK 248
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK);
+**
+** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1
+*/
+
+
+#define IPC_MBOPENREAL 249
+/* (requires Winamp 2.4+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL);
+**
+** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if
+** IPC_MBBLOCK has been set to 1
+*/
+
+
+#define IPC_ADJUST_OPTIONSMENUPOS 280
+/* (requires Winamp 2.9+)
+** int newpos=SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_OPTIONSMENUPOS);
+** This moves where Winamp expects the Options menu to be in the main menu.
+** This is useful if you wish to insert a menu item above the options/skins/vis menus for a window.
+** If you pass adjust_offset as zero then it will return the current offset without adjusting it.
+*/
+
+
+#define IPC_GET_HMENU 281
+/* (requires Winamp 2.9+)
+** HMENU hMenu=SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU);
+**
+** For 2.9x installs the following values are valid:
+** 0 : main popup menu (mapped to -1 in 5.x installs)
+** 1 : main menubar file menu
+** 2 : main menubar options menu
+** 3 : main menubar windows menu
+** 4 : main menubar help menu
+**
+** For 5.x client versions the following values are valid (changed due to Modern skin support):
+** -1 : the main winamp menu resource (same as doing LoadMenu(winamp_module_or_lng_file,101)
+** 0 : main popup menu
+** 1 : main menubar file menu
+** 2 : main menubar play menu
+** 3 : main menubar options menu
+** 4 : main menubar windows menu
+** 5 : main menubar windows help
+** 6 : playlist editor menubar file menu
+** 7 : playlist editor menubar playlist menu
+** 8 : playlist editor menubar sort menu
+** 9 : media library menubar file menu
+** 10 : media library menubar view menu
+**
+** In all client versions, unsupported values will return NULL.
+**
+** e.g. (psuedo code to add an item to the end of the main window 'view' menu)
+** HMENU windows_menu = (HMENU)SendMessageW(hwnd_winamp,WM_WA_IPC,4,IPC_GET_HMENU);
+** if(windows_menu)
+** {
+** // WA_MENUITEM_ID is obtained from IPC_REGISTER_WINAMP_IPCMESSAGE or a predefined
+** // value if that api is not supported on the client version you are working with.
+**
+** int window_visible = 1; // this would be updated as needed for the window view state
+** MENUITEMINFO i = {sizeof(i), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING,
+** window_visible ? MFS_CHECKED : 0, WA_MENUITEM_ID};
+** i.dwTypeData = "My Menu Item";
+** InsertMenuItem(windows_menu, GetMenuItemCount(windows_menu), TRUE, &i);
+** }
+*/
+
+
+#define IPC_GET_EXTENDED_FILE_INFO 290 //pass a pointer to the following struct in wParam
+#define IPC_GET_EXTENDED_FILE_INFO_HOOKABLE 296
+/* (requires Winamp 2.9+)
+** to use, create an extendedFileInfoStruct, point the values filename and metadata to the
+** filename and metadata field you wish to query, and ret to a buffer, with retlen to the
+** length of that buffer, and then SendMessageW(hwnd_winamp,WM_WA_IPC,&struct,IPC_GET_EXTENDED_FILE_INFO);
+** the results should be in the buffer pointed to by ret.
+** returns 1 if the decoder supports a getExtendedFileInfo method
+*/
+typedef struct {
+ const char *filename;
+ const char *metadata;
+ char *ret;
+ size_t retlen;
+} extendedFileInfoStruct;
+
+
+#define IPC_GET_BASIC_FILE_INFO 291 //pass a pointer to the following struct in wParam
+typedef struct {
+ const char *filename;
+
+ int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used)
+
+ // filled in by winamp
+ int length;
+ char *title;
+ int titlelen;
+} basicFileInfoStruct;
+
+
+#define IPC_GET_BASIC_FILE_INFOW 1291 //pass a pointer to the following struct in wParam
+typedef struct {
+ const wchar_t *filename;
+
+ int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used)
+
+ // filled in by winamp
+ int length;
+ wchar_t *title;
+ int titlelen;
+} basicFileInfoStructW;
+
+
+#define IPC_GET_EXTLIST 292
+#define IPC_GET_EXTLISTW 1292
+/* (requires Winamp 5.0+)
+** char* ext_list = (char*)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)mode,IPC_GET_EXTLIST);
+** wchar_t* ext_list = (wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)mode,IPC_GET_EXTLISTW);
+** These return a double null delimited string based on the mode passed.
+** Ensure you GlobalFree() the result when done.
+**
+** mode = 0 - returns raw extlist of all loadable formats
+** mode = 1 - returns something suitable for getopenfilename of all loadable formats
+**
+** update 5.66+
+** these now de-duplicate file extensions reported by the input plug-ins as well as capitalising.
+*/
+
+#define IPC_GET_PLAYLIST_EXTLISTW 282
+/* (requires Winamp 5.66+)
+** wchar_t* pl_ext_list = (wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)mode,IPC_GET_PLAYLIST_EXTLISTW);
+** These just return playlist extensions / file types instead of all
+** extensions / file types like the prior IPC_GET_EXTLIST(W) methods.
+** There is no need to GlobalFree() the result unlike the IPC_GET_EXTLIST(W) behaviour.
+**
+** mode = 0 - returns raw extlist of loadable playlist formats
+** mode = 1 - returns something suitable for getopenfilename of loadable playlist formats
+** mode = 2 - returns raw extlist of writeable playlist formats
+** mode = 3 - returns something suitable for getopenfilename of writeable playlist formats
+*/
+
+typedef struct {
+ HWND parent;
+ char *filename;
+} infoBoxParam;
+
+#define IPC_INFOBOX 293
+/* (requires Winamp 5.0+)
+** infoBoxParam infoBox = {parent_hwnd,"c:\\test\\folder\\test.mp3"};
+** int ret_val = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&infoBox,IPC_INFOBOX);
+**
+** ret_val is 0 if OK was pressed and is 1 if CANCEL was pressed
+** The standard behaviour is to abort any loops used with this api if a cancel occurs.
+*/
+
+
+typedef struct {
+ HWND parent;
+ const wchar_t *filename;
+} infoBoxParamW;
+
+#define IPC_INFOBOXW 1293
+/* (requires Winamp 5.3+)
+** infoBoxParamW infoBoxW = {parent_hwnd,L"c:\\test\\folder\\test.mp3"};
+** int ret_val = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&infoBoxW,IPC_INFOBOXW);
+**
+** ret_val is 0 if OK was pressed and is 1 if CANCEL was pressed
+** The standard behaviour is to abort any loops used with this api if a cancel occurs.
+*/
+
+
+#define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam
+/* (requires Winamp 2.9+)
+** to use, create an extendedFileInfoStruct, point the values filename and metadata to the
+** filename and metadata field you wish to write in ret. (retlen is not used). and then
+** SendMessageW(hwnd_winamp,WM_WA_IPC,&struct,IPC_SET_EXTENDED_FILE_INFO);
+** returns 1 if the metadata is supported
+** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update
+*/
+
+
+#define IPC_WRITE_EXTENDED_FILE_INFO 295
+/* (requires Winamp 2.9+)
+** writes all the metadata set thru IPC_SET_EXTENDED_FILE_INFO to the file
+** returns 1 if the file has been successfully updated, 0 if error
+*/
+
+
+#define IPC_FORMAT_TITLE 297
+typedef struct
+{
+ char *spec; // NULL=default winamp spec
+ void *p;
+
+ char *out;
+ int out_len;
+
+ char * (*TAGFUNC)(const char * tag, void * p); //return 0 if not found
+ void (*TAGFREEFUNC)(char * tag,void * p);
+} waFormatTitle;
+
+
+#define IPC_FORMAT_TITLE_EXTENDED 298 // similiar to IPC_FORMAT_TITLE, but falls back to Winamp's %tags% if your passed tag function doesn't handle it
+typedef struct
+{
+ const wchar_t *filename;
+ int useExtendedInfo; // set to 1 if you want the Title Formatter to query the input plugins for any tags that your tag function fails on
+ const wchar_t *spec; // NULL=default winamp spec
+ void *p;
+
+ wchar_t *out;
+ int out_len;
+
+ wchar_t * (*TAGFUNC)(const wchar_t * tag, void * p); //return 0 if not found, -1 for empty tag
+ void (*TAGFREEFUNC)(wchar_t *tag, void *p);
+} waFormatTitleExtended;
+
+
+#define IPC_COPY_EXTENDED_FILE_INFO 299
+typedef struct
+{
+ const char *source;
+ const char *dest;
+} copyFileInfoStruct;
+
+
+#define IPC_COPY_EXTENDED_FILE_INFOW 1299
+typedef struct
+{
+ const wchar_t *source;
+ const wchar_t *dest;
+} copyFileInfoStructW;
+
+
+typedef struct {
+ int (*inflateReset)(void *strm);
+ int (*inflateInit_)(void *strm,const char *version, int stream_size);
+ int (*inflate)(void *strm, int flush);
+ int (*inflateEnd)(void *strm);
+ unsigned long (*crc32)(unsigned long crc, const unsigned char *buf, unsigned int len);
+} wa_inflate_struct;
+
+#define IPC_GETUNCOMPRESSINTERFACE 331
+/* returns a function pointer to uncompress().
+** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen);
+** right out of zlib, useful for decompressing zlibbed data.
+** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API.
+*/
+
+
+typedef struct _prefsDlgRec {
+ HINSTANCE hInst; // dll instance containing the dialog resource
+ int dlgID; // resource identifier of the dialog
+ void *proc; // window proceedure for handling the dialog defined as
+ // LRESULT CALLBACK PrefsPage(HWND,UINT,WPARAM,LPARAM)
+
+ char *name; // name shown for the prefs page in the treelist
+ intptr_t where; // section in the treelist the prefs page is to be added to
+ // 0 for General Preferences
+ // 1 for Plugins
+ // 2 for Skins
+ // 3 for Bookmarks (no longer in the 5.0+ prefs)
+ // 4 for Prefs (the old 'Setup' section - no longer in 5.0+)
+ // 6 for Media Library
+
+ intptr_t _id;
+ struct _prefsDlgRec *next; // no longer implemented as a linked list, now used by Winamp for other means
+} prefsDlgRec;
+
+typedef struct _prefsDlgRecW {
+ HINSTANCE hInst; // dll instance containing the dialog resource
+ int dlgID; // resource identifier of the dialog
+ void *proc; // window proceedure for handling the dialog defined as
+ // LRESULT CALLBACK PrefsPage(HWND,UINT,WPARAM,LPARAM)
+
+ wchar_t *name; // name shown for the prefs page in the treelist
+ intptr_t where; // section in the treelist the prefs page is to be added to
+ // 0 for General Preferences
+ // 1 for Plugins
+ // 2 for Skins
+ // 3 for Bookmarks (no longer in the 5.0+ prefs)
+ // 4 for Prefs (the old 'Setup' section - no longer in 5.0+)
+ // 6 for Media Library
+
+ intptr_t _id;
+ struct _prefsDlgRec *next; // no longer implemented as a linked list, now used by Winamp for other means
+} prefsDlgRecW;
+
+#define IPC_ADD_PREFS_DLG 332
+#define IPC_ADD_PREFS_DLGW 1332
+#define IPC_REMOVE_PREFS_DLG 333
+#define IPC_UPDATE_PREFS_DLG 342
+#define IPC_UPDATE_PREFS_DLGW 1342
+/* (requires Winamp 2.9+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_REMOVE_PREFS_DLG);
+**
+** IPC_ADD_PREFS_DLG:
+** To use this you need to allocate a prefsDlgRec structure (either on the heap or with
+** some global data but NOT on the stack) and then initialise the members of the structure
+** (see the definition of the prefsDlgRec structure above).
+**
+** hInst - dll instance of where the dialog resource is located.
+** dlgID - id of the dialog resource.
+** proc - dialog window procedure for the prefs dialog.
+** name - name of the prefs page as shown in the preferences list.
+** where - see above for the valid locations the page can be added.
+**
+** Then you do SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG);
+**
+** example:
+**
+** prefsDlgRec* prefsRec = 0;
+** prefsRec = GlobalAlloc(GPTR,sizeof(prefsDlgRec));
+** prefsRec->hInst = hInst;
+** prefsRec->dlgID = IDD_PREFDIALOG;
+** prefsRec->name = "Pref Page";
+** prefsRec->where = 0;
+** prefsRec->proc = PrefsPage;
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG);
+**
+**
+** IPC_REMOVE_PREFS_DLG:
+** To use you pass the address of the same prefsRec you used when adding the prefs page
+** though you shouldn't really ever have to do this but it's good to clean up after you
+** when you're plugin is being unloaded.
+**
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_REMOVE_PREFS_DLG);
+**
+** IPC_ADD_PREFS_DLGW
+** requires Winamp 5.53+
+**
+** IPC_UPDATE_PREFS_DLG
+** IPC_UPDATE_PREFS_DLGW
+** requires Winamp 5.64+
+*/
+
+
+#define IPC_OPENPREFSTOPAGE 380
+/* SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_OPENPREFSTOPAGE);
+**
+** There are two ways of opening a preferences page.
+**
+** The first is to pass an id of a builtin preferences page (see below for ids) or a
+** &prefsDlgRec of the preferences page to open and this is normally done if you are
+** opening a prefs page you added yourself.
+**
+** If the page id does not or the &prefsRec is not valid then the prefs dialog will be
+** opened to the first page available (usually the Winamp Pro page).
+**
+** (requires Winamp 5.04+)
+** Passing -1 for param will open the preferences dialog to the last page viewed.
+**
+** Note: v5.0 to 5.03 had a bug in this api
+**
+** On the first call then the correct prefs page would be opened to but on the next call
+** the prefs dialog would be brought to the front but the page would not be changed to the
+** specified.
+** In 5.04+ it will change to the prefs page specified if the prefs dialog is already open.
+*/
+
+/* Builtin Preference page ids (valid for 5.0+)
+** (stored in the lParam member of the TVITEM structure from the tree item)
+**
+** These can be useful if you want to detect a specific prefs page and add things to it
+** yourself or something like that ;)
+**
+** Winamp Pro 20
+** General Preferences 0
+** File Types 1
+** Playlist 23
+** Titles 21
+** Playback 42 (added in 5.25)
+** Station Info 41 (added in 5.11 & removed in 5.5)
+** Video 24
+** Localization 25 (added in 5.5)
+** Skins 40
+** Classic Skins 22
+** Plugins 30
+** Input 31
+** Output 32
+** Visualisation 33
+** DSP/Effect 34
+** General Purpose 35
+**
+** Note:
+** Custom page ids begin from 60
+** The value of the normal custom pages (Global Hotkeys, Jump To File, etc) is not
+** guaranteed since it depends on the order in which the plugins are loaded which can
+** change on different systems.
+**
+** Global Hotkeys, Jump To File, Media Library (under General Preferences and child pages),
+** Media Library (under Plugins), Portables, CD Ripping and Modern Skins are custom pages
+** created by the plugins shipped with Winamp.
+*/
+
+
+#define IPC_GETINIFILE 334
+/* (requires Winamp 2.9+)
+** char *ini=(char*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILE);
+** This returns a pointer to the full file path of winamp.ini.
+**
+** char ini_path[MAX_PATH] = {0};
+**
+** void GetIniFilePath(HWND hwnd){
+** if(SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION) >= 0x2900){
+** // this gets the string of the full ini file path
+** lstrcpynA(ini_path,(char*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILE),sizeof(ini_path)/sizeof(char));
+** }
+** else{
+** char* p = ini_path;
+** p += GetModuleFileNameA(0,ini_path,sizeof(ini_path)/sizeof(char)) - 1;
+** while(p && *p != '.' && p != ini_path){p = CharPrevA(ini_path,p);}
+** lstrcpynA(p+1,"ini",sizeof(ini_path)/sizeof(char));
+** }
+** }
+*/
+
+
+#define IPC_GETINIFILEW 1334
+/* (requires Winamp 5.58+)
+** wchar_t *ini=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILEW);
+** This returns a pointer to the full file path of winamp.ini.
+**
+** wchar_t ini_path[MAX_PATH] = {0};
+**
+** void GetIniFilePath(HWND hwnd){
+** if(SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION) >= 0x5058){
+** // this gets the string of the full ini file path
+** lstrcpynW(ini_path,(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILEW),sizeof(ini_path)/sizeof(wchar_t));
+** }
+** else{
+** wchar_t* p = ini_path;
+** p += GetModuleFileNameW(0,ini_path,sizeof(ini_path)/sizeof(wchar_t)) - 1;
+** while(p && *p != '.' && p != ini_path){p = CharPrevW(ini_path,p);}
+** lstrcpynW(p+1,L"ini",sizeof(ini_path)/sizeof(wchar_t));
+** }
+** }
+**
+** IPC_GETINIFILEW requires 5.58+
+*/
+
+
+#define IPC_GETINIDIRECTORY 335
+/* (requires Winamp 2.9+)
+** char *dir=(char*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIDIRECTORY);
+** This returns a pointer to the directory where winamp.ini can be found and is
+** useful if you want store config files but you don't want to use winamp.ini.
+*/
+
+
+#define IPC_GETINIDIRECTORYW 1335
+/* (requires Winamp 5.58+)
+** wchar_t *dir=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIDIRECTORYW);
+** This returns a pointer to the directory where winamp.ini can be found and is
+** useful if you want store config files but you don't want to use winamp.ini.
+*/
+
+
+#define IPC_GETPLUGINDIRECTORY 336
+/* (requires Winamp 5.11+)
+** char *plugdir=(char*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETPLUGINDIRECTORY);
+** This returns a pointer to the directory where Winamp has its plugins stored and is
+** useful if you want store config files in plugins.ini in the plugins folder or for
+** accessing any local files in the plugins folder.
+*/
+
+
+#define IPC_GETPLUGINDIRECTORYW 1336
+/* (requires Winamp 5.58+)
+** wchar_t *plugdir=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETPLUGINDIRECTORYW);
+** This returns a pointer to the directory where Winamp has its plugins stored and is
+** useful if you want store config files in plugins.ini in the plugins folder or for
+** accessing any local files in the plugins folder.
+*/
+
+
+#define IPC_GETM3UDIRECTORY 337
+/* (requires Winamp 5.11+)
+** char *m3udir=(char*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETM3UDIRECTORY);
+** This returns a pointer to the directory where winamp.m3u (and winamp.m3u8 if supported) is stored in.
+*/
+
+
+#define IPC_GETM3UDIRECTORYW 338
+/* (requires Winamp 5.3+)
+** wchar_t *m3udirW=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETM3UDIRECTORYW);
+** This returns a pointer to the directory where winamp.m3u (and winamp.m3u8 if supported) is stored in.
+*/
+
+
+#define IPC_GETVISDIRECTORYW 339
+/* (requires Winamp 5.58+)
+** wchar_t *visdir=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVISDIRECTORYW);
+** This returns a pointer to the directory set to load/store visualization plugins from.
+**
+** This can otherwise be obtained by reading the "VISDir" entry in the winamp section of
+** winamp.ini which if null then you need to assume <winampdir>\plugins
+*/
+
+
+#define IPC_GETSKINDIRECTORYW 340
+/* (requires Winamp 5.58+)
+** wchar_t *skindir=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETSKINDIRECTORYW);
+** This returns a pointer to the directory set to load/store installed skins from.
+**
+** This can otherwise be obtained by reading the "SkinDir" entry in the winamp section of
+** winamp.ini which if null then you need to assume <winampdir>\skins
+*/
+
+
+#define IPC_GETDSPDIRECTORYW 341
+/* (requires Winamp 5.58+)
+** wchar_t *dspdir=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETDSPDIRECTORYW);
+** This returns a pointer to the directory set to load/store installed DSP/effect plugins from.
+**
+** This can otherwise be obtained by reading the "DSPDir" entry in the winamp section of
+** winamp.ini which if null then you need to assume <winampdir>\plugins
+*/
+
+
+#define IPC_GETMLINIFILE 343
+#define IPC_GETMLINIFILEW 1343
+/* (requires Winamp 5.66+)
+** wchar_t *ml_ini=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETMLINIFILEW);
+** This returns a pointer to the full file path of gen_ml.ini.
+*/
+
+
+#define IPC_GETSHAREDDLLDIRECTORYW 1344
+/* (requires Winamp 5.8+)
+** wchar_t *shareddir=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETSHAREDDLLDIRECTORYW);
+** This returns a pointer to the directory set to load/store installed DSP/effect plugins from.
+*/
+
+
+#define IPC_SPAWNBUTTONPOPUP 361 // param =
+// 0 = eject
+// 1 = previous
+// 2 = next
+// 3 = pause
+// 4 = play
+// 5 = stop
+
+
+#define IPC_OPENURLBOX 360
+/* (requires Winamp 5.0+)
+** HGLOBAL hglobal = (HGLOBAL)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENURLBOX);
+** You pass a hwnd for the dialog to be parented to (which modern skin support uses).
+** This will return a HGLOBAL that needs to be freed with GlobalFree() if this worked.
+*/
+
+
+#define IPC_OPENFILEBOX 362
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENFILEBOX);
+** You pass a hwnd for the dialog to be parented to (which modern skin support uses).
+*/
+
+
+#define IPC_OPENDIRBOX 363
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENDIRBOX);
+** You pass a hwnd for the dialog to be parented to (which modern skin support uses).
+*/
+
+
+#define IPC_SETDIALOGBOXPARENT 364
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_SETDIALOGBOXPARENT);
+** Pass 'parent' as the window which will be used as the parent for a number of the built
+** in Winamp dialogs and is useful when you are taking over the whole of the UI so that
+** the dialogs will not appear at the bottom right of the screen since the main winamp
+** window is located at 3000x3000 by gen_ff when this is used. Call this again with
+** parent = null to reset the parent back to the orginal Winamp window.
+*/
+
+
+#define IPC_GETDIALOGBOXPARENT 365
+/* (requires Winamp 5.51+)
+** HWND hwndParent = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GETDIALOGBOXPARENT);
+** hwndParent can / must be passed to all modal dialogs/MessageBoxes when using Winamp as a parent.
+*/
+
+
+#define IPC_UPDATEDIALOGBOXPARENT 366
+/* (requires Winamp 5.53+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_UPDATEDIALOGBOXPARENT);
+** If you previously called IPC_SETDIALOGBOXPARENT then call this every time your window resizes.
+*/
+
+
+#define IPC_DRO_MIN 401 // reserved for DrO
+
+#define IPC_SET_JTF_COMPARATOR 409
+/* (requires Winamp 5.2+)
+/* pass me an int (__cdecl *)(const char *, const char *) in wParam
+** If this is not set or if it is cleared then Winamp reverts to it's own comparator.
+** It is not until Winamp 5.33+ that passing wParam=0 or another function will allow
+** for it to be changed from what was set on the first calling of this api.
+*/
+
+#define IPC_SET_JTF_COMPARATOR_W 410
+/* (requires Winamp 5.55+)
+** pass me an int (__cdecl *)(const wchar_t *, const wchar_t *) in wParam
+** If this is not set or if it is cleared then Winamp will revert to the
+** IPC_SET_JTF_COMPARATOR handler or the native search function if not set.
+*/
+
+#define IPC_SET_JTF_DRAWTEXT 416
+
+#define IPC_SET_JTF_LOAD_MODE 426
+/* (requires Winamp 5.66+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)mode,IPC_SET_JTF_LOAD_MODE);
+** Pass 'mode' to alter the loading mode of the JTF window (default is mode = 0).
+** If 'value' is 1 then disable loading of the full playlist results if no search.
+** If 'value' is 0 then enable loading of the full playlist results if no search.
+**
+** If you pass 'value' as -666 to this api then it will return the current mode.
+** int mode = SendMessageW(hwnd_winamp,WM_WA_IPC,-666,IPC_SET_JTF_LOAD_MODE);
+*/
+
+#define IPC_GET_JTF_LOAD_MODE(hwnd_winamp) SendMessageW(hwnd_winamp,WM_WA_IPC,-666,IPC_SET_JTF_LOAD_MODE)
+/* (requires Winamp 5.66+)
+** int curpan = IPC_GETPANNING(hwnd_winamp);
+** This will return the current loading mode of the JTF window.
+*/
+
+
+#define IPC_DRO_MAX 499
+
+
+// pass 0 for a copy of the skin HBITMAP
+// pass 1 for name of font to use for playlist editor likeness
+// pass 2 for font charset
+// pass 3 for font size
+#define IPC_GET_GENSKINBITMAP 503
+
+
+#ifdef __cplusplus
+class ifc_window;
+#endif
+
+typedef struct embedWindowState embedWindowState;
+
+#define FFC_CREATEEMBED 0 // param = (LPARAM)(ifc_window*)windowParent; return 1 to terminate creation.
+#define FFC_DESTROYEMBED 1
+
+typedef int (CALLBACK *FFCALLBACK)(embedWindowState* /*windowState*/, INT /*eventId*/, LPARAM /*param*/);
+
+typedef struct embedWindowState
+{
+ HWND me; //hwnd of the window
+
+ #define EMBED_FLAGS_NORESIZE 0x1
+ // set this bit to keep window from being resizable
+
+ #define EMBED_FLAGS_NOTRANSPARENCY 0x2
+ // set this bit to make gen_ff turn transparency off for this window
+
+ #define EMBED_FLAGS_NOWINDOWMENU 0x4
+ // set this bit to prevent gen_ff from automatically adding your window to the right-click menu
+
+ #define EMBED_FLAGS_GUID 0x8
+ // (5.31+) call SET_EMBED_GUID(yourEmbedWindowStateStruct, GUID) to define a GUID for this window
+
+ #define EMBED_FLAGS_FFCALLBACK 0x10
+ // 5.55+
+
+ #define EMBED_FLAGS_LEGACY_WND 0x20
+ // 5.66+ set this bit to prevent gen_ff from adding a modern skin frame to the window
+ // when using the legacy api methods for allowing old plug-ins to be dockable
+
+ #define SET_EMBED_GUID(windowState, windowGUID) { windowState->flags |= EMBED_FLAGS_GUID; *((GUID *)&windowState->extra_data[4])=windowGUID; }
+ #define GET_EMBED_GUID(windowState) (*((GUID *)&windowState->extra_data[4]))
+
+ int flags; // see above
+
+ RECT r;
+ void *user_ptr; // for application use
+
+ union
+ {
+ #pragma warning(push)
+ #pragma warning(disable:4201)
+ #pragma pack(push, 1)
+ struct
+ {
+ struct embedWindowState *link;
+ intptr_t attached;
+ intptr_t padding1[2]; //2-3
+ GUID guid; // 4-7
+ #ifdef _WIN64
+ intptr_t guidpadding;
+ #endif
+ FFCALLBACK callback; // MAKSIM UPDATE HERE
+ intptr_t padding2[52]; // 9-60
+ intptr_t hostcount; // 61
+ intptr_t reparenting; // 62
+ #ifdef __cplusplus
+ ifc_window *wasabi_window;
+ #else
+ void *wasabi_window; // ifc_window *
+ #endif
+ };
+ #pragma warning(pop)
+ #pragma pack(pop)
+ intptr_t extra_data[64]; // for internal winamp use
+ };
+} embedWindowState;
+
+
+#define IPC_GET_EMBEDIF 505
+/* (requires Winamp 2.9+)
+** HWND myframe = (HWND)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&wa_wnd,IPC_GET_EMBEDIF);
+**
+** or
+**
+** HWND myframe = 0;
+** HWND (*embed)(embedWindowState *params)=0;
+** *(void**)&embed = (void*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_EMBEDIF);
+** myframe = embed(&wa_wnd);
+**
+** You pass an embedWindowState* and it will return a hwnd for the frame window or if you
+** pass wParam as null then it will return a HWND embedWindow(embedWindowState *);
+**
+** Embed window can send notification to the first child.
+** Notifications will come in form of WM_NOTIFY.
+** Notifications:
+*/
+
+#define EWN_FIRST (0)
+
+typedef struct __EMBEDSHOW
+{
+ NMHDR hdr;
+ BOOL fShow;
+ UINT nStatus;
+} EMBEDSHOW;
+
+#define EWN_SHOWWINDOW (EWN_FIRST + 0) // lParam = (LPARAM)(EMBEDSHOW*)pnmh. This is preffered way to show hide your chold window
+
+#define IPC_SKINWINDOW 534
+
+#define SWF_NORESIZE EMBED_FLAGS_NORESIZE
+#define SWF_NOTRANSPARENCY EMBED_FLAGS_NOTRANSPARENCY
+#define SWF_NOWINDOWMENU EMBED_FLAGS_NOWINDOWMENU
+
+typedef struct __SKINWINDOWPARAM
+{
+ INT cbSize; // sizeof(SKINWINDOWPARAM)
+ HWND hwndToSkin;
+ GUID windowGuid;
+ UINT flagsEx;
+ FFCALLBACK callbackFF;
+} SKINWINDOWPARAM;
+
+
+typedef struct embedEnumStruct
+{
+ int (*enumProc)(embedWindowState *ws, struct embedEnumStruct *param); // return 1 to abort
+ int user_data; // or more :)
+} embedEnumStruct; // pass
+#define IPC_EMBED_ENUM 532
+/* (requires Winamp 2.9+)
+*/
+
+
+#define IPC_EMBED_ISVALID 533
+/* (requires Winamp 2.9+)
+** int valid = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)embedhwnd,IPC_EMBED_ISVALID);
+** Pass a hwnd in the wParam to this to check if the hwnd is a valid embed window or not.
+*/
+
+
+#define IPC_EMBED_ADD_LEGACY 535
+/* (requires Winamp 5.66+)
+** int done = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(embedWindowState*)ws,IPC_EMBED_ADD_LEGACY);
+** You pass an embedWindowState* filled with any appropriate details and ensure you add
+** EMBED_FLAGS_LEGACY_WND to the 'flags' member to ensure it will be handled correctly.
+** Returns 1 if the request was able to be processed.
+*/
+
+
+#define IPC_EMBED_REMOVE_LEGACY 536
+/* (requires Winamp 5.66+)
+** int done = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(embedWindowState*)ws,IPC_EMBED_REMOVE_LEGACY);
+** You pass an embedWindowState* filled with any appropriate details and ensure you add
+** EMBED_FLAGS_LEGACY_WND to the 'flags' member to ensure it will be handled correctly.
+** Returns 1 if the request was able to be processed.
+*/
+
+
+#define IPC_EMBED_UPDATE_LEGACY_POS 537
+/* (requires Winamp 5.66+)
+** int done = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(embedWindowState*)ws,IPC_EMBED_UPDATE_LEGACY_POS);
+** You pass an embedWindowState* filled with an updated position of the window by filling
+** int the 'r' member so Winamp will know the correct position of the window after moving.
+** Returns 1 if the request was able to be processed.
+**
+** Not sending this (ideally at the end of the window being moved) will likely cause issues
+** with the placement and docking of the legacy window when Winamp's naitve and any embedded
+** windows are then moved.
+*/
+
+
+#define IPC_GET_EMBED_SNAPFUNC 538
+/* (requires Winamp 5.66+)
+** SnapToScreen is used to adjust the rect passed so as to keep the window no the screen
+** RECT r;
+** BOOL (*SnapToScreen)(LPRECT outrc)=0;
+** *(void**)&SnapToScreen = (void*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_EMBED_SNAPFUNC);
+** SnapToScreen(&r);
+**
+** or
+**
+** SnapWindowToAllWindows is used to allow the window to natively dock to other Winamp windows
+** RECT r;
+** HWND myWnd = 0;
+** void (*SnapWindowToAllWindows)(LPRECT outrc, HWND hwndNoSnap)=0;
+** *(void**)&SnapWindowToAllWindows = (void*)SendMessageW(hwnd_winamp,WM_WA_IPC,1,IPC_GET_EMBED_SNAPFUNC);
+** SnapWindowToAllWindows(&r, myWnd);
+*/
+
+
+#define IPC_CONVERTFILE 506
+/* (requires Winamp 2.92+)
+** Converts a given file to a different format (PCM, MP3, etc...)
+** To use, pass a pointer to a waFileConvertStruct struct
+** This struct can be either on the heap or some global
+** data, but NOT on the stack. At least, until the conversion is done.
+**
+** eg: SendMessageW(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE);
+**
+** Return value:
+** 0: Can't start the conversion. Look at myConvertStruct->error for details.
+** 1: Conversion started. Status messages will be sent to the specified callbackhwnd.
+** Be sure to call IPC_CONVERTFILE_END when your callback window receives the
+** IPC_CB_CONVERT_DONE message.
+*/
+#ifdef __cplusplus
+class ifc_audiostream;
+class AudioCoder;
+#else
+typedef void *ifc_audiostream;
+typedef void *AudioCoder;
+#endif
+typedef struct
+{
+ char *sourcefile; // "c:\\source.mp3"
+ char *destfile; // "c:\\dest.pcm"
+ intptr_t destformat[8]; // like 'PCM ',srate,nch,bps.
+ //hack alert! you can set destformat[6]=mmioFOURCC('I','N','I',' '); and destformat[7]=(int)my_ini_file; (where my_ini_file is a char*)
+ HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages
+
+ //filled in by winamp.exe
+ char *error; //if IPC_CONVERTFILE returns 0, the reason will be here
+
+ int bytes_done; //you can look at both of these values for speed statistics
+ int bytes_total;
+ int bytes_out;
+
+ int killswitch; // don't set it manually, use IPC_CONVERTFILE_END
+ /* everything below is for internal use */
+ ifc_audiostream *decoder; // for internal winamp use
+ HANDLE convert_thread;
+ HANDLE file_handle;
+ AudioCoder *audio_coder;
+ HMODULE encoder_mod;
+ int bps;
+ int channels;
+ int sample_rate;
+ intptr_t extra_data[56]; // for future use
+} convertFileStruct;
+
+
+#define IPC_CONVERTFILEW 515
+// (requires Winamp 5.36+)
+
+typedef struct
+{
+ wchar_t *sourcefile; // "c:\\source.mp3"
+ wchar_t *destfile; // "c:\\dest.pcm"
+ intptr_t destformat[8]; // like 'PCM ',srate,nch,bps.
+ //hack alert! you can set destformat[6]=mmioFOURCC('I','N','I',' '); and destformat[7]=(int)my_ini_file; (where my_ini_file is a char*)
+ HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages
+
+ //filled in by winamp.exe
+ wchar_t *error; //if IPC_CONVERTFILE returns 0, the reason will be here
+
+ int bytes_done; //you can look at both of these values for speed statistics
+ int bytes_total;
+ int bytes_out;
+
+ int killswitch; // don't set it manually, use IPC_CONVERTFILE_END
+ /* everything below is for internal use */
+ ifc_audiostream *decoder; // for internal winamp use
+ HANDLE convert_thread;
+ HANDLE file_handle;
+ AudioCoder *audio_coder;
+ HMODULE encoder_mod;
+ int bps;
+ int channels;
+ int sample_rate;
+ intptr_t extra_data[56]; // for future use
+} convertFileStructW;
+
+
+#define IPC_CONVERTFILE_END 507
+/* (requires Winamp 2.92+)
+** Stop/ends a convert process started from IPC_CONVERTFILE
+** You need to call this when you receive the IPC_CB_CONVERTDONE message or when you
+** want to abort a conversion process
+**
+** eg: SendMessageW(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE_END);
+**
+** No return value
+*/
+
+
+#define IPC_CONVERTFILEW_END 516
+// (requires Winamp 5.36+)
+
+
+typedef struct {
+ HWND hwndParent;
+ int format;
+
+ //filled in by winamp.exe
+ HWND hwndConfig;
+ int extra_data[8];
+ //hack alert! you can set extra_data[6]=mmioFOURCC('I','N','I',' '); and extra_data[7]=(int)my_ini_file; (where my_ini_file is a char*)
+} convertConfigStruct;
+
+#define IPC_CONVERT_CONFIG 508
+#define IPC_CONVERT_CONFIG_END 509
+
+
+typedef struct
+{
+ void (*enumProc)(intptr_t user_data, const char *desc, int fourcc);
+ intptr_t user_data;
+} converterEnumFmtStruct;
+
+#define IPC_CONVERT_CONFIG_ENUMFMTS 510
+/* (requires Winamp 2.92+)
+*/
+
+
+typedef struct
+{
+ char cdletter;
+ char *playlist_file;
+ HWND callback_hwnd;
+
+ //filled in by winamp.exe
+ char *error;
+} burnCDStruct;
+#define IPC_BURN_CD 511
+/* (requires Winamp 5.0+)
+*/
+
+
+typedef struct
+{
+ convertFileStruct *cfs;
+ int priority;
+} convertSetPriority;
+
+#define IPC_CONVERT_SET_PRIORITY 512
+
+
+typedef struct
+{
+ convertFileStructW *cfs;
+ int priority;
+} convertSetPriorityW;
+
+#define IPC_CONVERT_SET_PRIORITYW 517
+// (requires Winamp 5.36+)
+
+
+#define IPC_CONVERT_TEST 518
+/* requires Winamp 5.55+
+* pass a convertFileStructW and it will verify that you are able to transcode
+* checks:
+* - valid input file
+* - valid destination format / encoder type (including winamp pro authorization for mp3)
+* - valid destination file (not that as a side-effect, this function will create a 0 byte destination file!)
+*/
+
+
+typedef struct
+{
+ unsigned int format; //fourcc value
+ char *item; // config item, eg "bitrate"
+ char *data; // buffer to recieve, or buffer that contains the data
+ int len; // length of the data buffer (only used when getting a config item)
+ char *configfile; // config file to read from
+} convertConfigItem;
+
+#define IPC_CONVERT_CONFIG_SET_ITEM 513 // returns TRUE if successful
+#define IPC_CONVERT_CONFIG_GET_ITEM 514 // returns TRUE if successful
+
+
+typedef struct
+{
+ const char *filename;
+ char *title; // 2048 bytes
+ int length;
+ int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit
+} waHookTitleStruct;
+
+#define IPC_HOOK_TITLES 850
+/* (requires Winamp 5.0+)
+** If you hook this message and modify the information then make sure to return TRUE.
+** If you don't hook the message then make sure you pass it on through the subclass chain.
+**
+** LRESULT CALLBACK WinampWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
+** {
+** LRESULT ret = CallWindowProc((WNDPROC)WinampProc,hwnd,umsg,wParam,lParam);
+**
+** if(message==WM_WA_IPC && lParam==IPC_HOOK_TITLES)
+** {
+** waHookTitleStruct *ht = (waHookTitleStruct *) wParam;
+** // Doing ATF stuff with ht->title, whatever...
+** return TRUE;
+** }
+** return ret;
+** }
+*/
+
+
+typedef struct
+{
+ const wchar_t *filename;
+ wchar_t *title; // 2048 characters
+ int length;
+ int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit
+} waHookTitleStructW;
+
+#define IPC_HOOK_TITLESW 851
+/* (requires Winamp 5.3+)
+** See information on IPC_HOOK_TITLES for how to process this.
+*/
+
+
+#define IPC_GETSADATAFUNC 800
+/* (requires Winamp 5.0+)
+** <returned_function_pointer> = SendMessageW(hwnd_winamp,WM_WA_IPC,param,IPC_GETSADATAFUNC);
+** where param can be 0 , 1 or 2. A param == 2 is meant to replace param == 0 as of 5.5+
+**
+** void (*export_sa_setreq)(int want);
+** *(void **)&export_sa_setreq=(void *)SendMessageW(hwnd_winamp,WM_WA_IPC,1,IPC_GETSADATAFUNC);
+** This can called as either want = 0 -> use user setting (ie classic skin mode)
+** or want = 1 -> just obtain data (ie modern skin mode)
+**
+** (replaces passing wParam == 0 and if not present then this call will return a null function pointer)
+** char * (*export_sa_get)(char data[75*2 + 8]);
+** *(void **)&export_sa_get=(void*)SendMessageW(hwnd_winamp,WM_WA_IPC,2,IPC_GETSADATAFUNC);
+**
+** When called this will fill the passed buffer with 150 bytes of data and return a pointer to it.
+** char data[75*2 + 8];
+** char *p = export_sa_get(data);
+**
+**
+** (deprecated as of at least 5.5+ but should still work)
+** char * (*export_sa_get_deprecated)();
+** *(void **)&export_sa_get_deprecated=(void*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETSADATAFUNC);
+**
+** When called this will return 150 bytes of data as a static buffer inside Winamp.
+** char *data = export_sa_get_deprecated();
+*/
+
+
+#define IPC_GETVUDATAFUNC 801
+/* (requires Winamp 5.0+)
+**
+** int (*export_vu_get)(int channel);
+** *(void **)&export_vu_get=(void*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVUDATAFUNC);
+**
+**
+** This returns a function pointer of int export_vu_get(int channel) and when called it
+** will return values between 0 - 255 or or it will return -1 for a bad channel / value.
+**
+** Calling export_vu_get(0) will return the left channel.
+** Calling export_vu_get(1) will return the right channel.
+*/
+
+
+#define IPC_ISMAINWNDVISIBLE 900
+/* (requires Winamp 5.0+)
+** int visible=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISMAINWNDVISIBLE);
+** You send this to Winamp to query if the main window is visible or not such as by
+** unchecking the option in the main right-click menu. If the main window is visible then
+** this will return 1 otherwise it returns 0.
+*/
+
+
+typedef struct
+{
+ int numElems;
+ int *elems;
+ HBITMAP bm; // set if you want to override
+} waSetPlColorsStruct;
+
+#define IPC_SETPLEDITCOLORS 920
+/* (requires Winamp 5.0+)
+** This is sent by gen_ff when a modern skin is being loaded to set the colour scheme for
+** the playlist editor. When sent numElems is usually 6 and matches with the 6 possible
+** colours which are provided be pledit.txt from the classic skins. The elems array is
+** defined as follows:
+**
+** elems = 0 => normal text
+** elems = 1 => current text
+** elems = 2 => normal background
+** elems = 3 => selected background
+** elems = 4 => minibroswer foreground
+** elems = 5 => minibroswer background
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_SETPLEDITCOLORS)
+** {
+** waSetPlColorsStruct* colStr = (waSetPlColorsStruct*)wp;
+** if(colStr)
+** {
+** // set or inspect the colours being used (basically for gen_ff's benefit)
+** }
+** }
+*/
+
+
+typedef struct
+{
+ HWND wnd;
+ int xpos; // in screen coordinates
+ int ypos;
+} waSpawnMenuParms;
+
+// waSpawnMenuParms2 is used by the menubar submenus
+typedef struct
+{
+ HWND wnd;
+ int xpos; // in screen coordinates
+ int ypos;
+ int width;
+ int height;
+} waSpawnMenuParms2;
+
+// the following IPC use waSpawnMenuParms as parameter
+#define IPC_SPAWNEQPRESETMENU 933
+#define IPC_SPAWNFILEMENU 934 //menubar
+#define IPC_SPAWNOPTIONSMENU 935 //menubar
+#define IPC_SPAWNWINDOWSMENU 936 //menubar
+#define IPC_SPAWNHELPMENU 937 //menubar
+#define IPC_SPAWNPLAYMENU 938 //menubar
+#define IPC_SPAWNPEFILEMENU 939 //menubar
+#define IPC_SPAWNPEPLAYLISTMENU 940 //menubar
+#define IPC_SPAWNPESORTMENU 941 //menubar
+#define IPC_SPAWNPEHELPMENU 942 //menubar
+#define IPC_SPAWNMLFILEMENU 943 //menubar
+#define IPC_SPAWNMLVIEWMENU 944 //menubar
+#define IPC_SPAWNMLHELPMENU 945 //menubar
+#define IPC_SPAWNPELISTOFPLAYLISTS 946
+
+
+#define WM_WA_SYSTRAY WM_USER+1
+/* This is sent by the system tray when an event happens (you might want to simulate it).
+**
+** if(uMsg == WM_WA_SYSTRAY)
+** {
+** switch(lParam)
+** {
+** // process the messages sent from the tray
+** }
+** }
+*/
+
+
+#define WM_WA_MPEG_EOF WM_USER+2
+/* Input plugins send this when they are done playing back the current file to inform
+** Winamp or anyother installed plugins that the current
+**
+** if(uMsg == WM_WA_MPEG_EOF)
+** {
+** // do what is needed here
+** }
+*/
+
+
+//// video stuff
+
+#define IPC_IS_PLAYING_VIDEO 501 // returns >1 if playing, 0 if not, 1 if old version (so who knows):)
+#define IPC_GET_IVIDEOOUTPUT 500 // see below for IVideoOutput interface
+#define VIDEO_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24))
+#define VIDUSER_SET_INFOSTRING 0x1000
+#define VIDUSER_GET_VIDEOHWND 0x1001
+#define VIDUSER_SET_VFLIP 0x1002
+#define VIDUSER_SET_TRACKSELINTERFACE 0x1003 // give your ITrackSelector interface as param2
+#define VIDUSER_OPENVIDEORENDERER 0x1004
+#define VIDUSER_CLOSEVIDEORENDERER 0x1005
+#define VIDUSER_GETPOPUPMENU 0x1006
+#define VIDUSER_SET_INFOSTRINGW 0x1007
+#define VIDUSER_SET_THREAD_SAFE 0x1008 // set param2 = 1 if open(), draw() and close() will be called on the same thread
+#define VIDUSER_SET_PALETTE 0x1010
+
+#define IPC_HAS_VIDEO_SUPPORT 502
+/* (requires Winamp 5.666+)
+** int has_video_support=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_HAS_VIDEO_SUPPORT);
+** indicates if video support is enabled or not
+** This returns 0 if video support is disabled (no compatible input plug-ins or via
+** the no_video=1 winamp.ini configuration option) and 1 if enabled (so will return
+** 1 on all older Winamp clients where this API method is not available).
+*/
+
+typedef struct
+{
+ int w;
+ int h;
+ int vflip;
+ double aspectratio;
+ unsigned int fmt;
+} VideoOpenStruct;
+
+#ifndef NO_IVIDEO_DECLARE
+#ifdef __cplusplus
+
+class VideoOutput;
+class SubsItem;
+
+#ifndef _NSV_DEC_IF_H_
+struct YV12_PLANE {
+ unsigned char* baseAddr;
+ long rowBytes;
+} ;
+
+struct YV12_PLANES {
+ YV12_PLANE y;
+ YV12_PLANE u;
+ YV12_PLANE v;
+};
+#endif
+
+class IVideoOutput
+{
+ public:
+ virtual ~IVideoOutput() { }
+ virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0;
+ virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { (void)token; (void)msgcallback; /* to eliminate warning C4100 */ }
+ virtual void close()=0;
+ virtual void draw(void *frame)=0;
+ virtual void drawSubtitle(SubsItem *item) {UNREFERENCED_PARAMETER(item); }
+ virtual void showStatusMsg(const char *text) {UNREFERENCED_PARAMETER(text); }
+ virtual int get_latency() { return 0; }
+ virtual void notifyBufferState(int bufferstate) { UNREFERENCED_PARAMETER(bufferstate); } /* 0-255*/
+ virtual INT_PTR extended(INT_PTR param1, INT_PTR param2, INT_PTR param3) { UNREFERENCED_PARAMETER(param1); UNREFERENCED_PARAMETER(param2); UNREFERENCED_PARAMETER(param3); return 0; } // Dispatchable, eat this!
+};
+
+class ITrackSelector
+{
+ public:
+ virtual int getNumAudioTracks()=0;
+ virtual void enumAudioTrackName(int n, char *buf, int size)=0;
+ virtual int getCurAudioTrack()=0;
+ virtual int getNumVideoTracks()=0;
+ virtual void enumVideoTrackName(int n, char *buf, int size)=0;
+ virtual int getCurVideoTrack()=0;
+
+ virtual void setAudioTrack(int n)=0;
+ virtual void setVideoTrack(int n)=0;
+};
+
+#endif //cplusplus
+#endif//NO_IVIDEO_DECLARE
+
+// these messages are callbacks that you can grab by subclassing the winamp window
+
+// wParam =
+#define IPC_CB_WND_EQ 0 // use one of these for the param
+#define IPC_CB_WND_PE 1
+#define IPC_CB_WND_MB 2
+#define IPC_CB_WND_VIDEO 3
+#define IPC_CB_WND_MAIN 4
+
+#define IPC_CB_ONSHOWWND 600
+#define IPC_CB_ONHIDEWND 601
+
+#define IPC_CB_GETTOOLTIP 602
+#define IPC_CB_GETTOOLTIPW 1602
+
+#define IPC_CB_MISC 603
+#define IPC_CB_MISC_TITLE 0 // start of playing/stop/pause
+#define IPC_CB_MISC_VOLUME 1 // volume/pan
+#define IPC_CB_MISC_STATUS 2 // start playing/stop/pause/ffwd/rwd
+#define IPC_CB_MISC_EQ 3
+#define IPC_CB_MISC_INFO 4
+#define IPC_CB_MISC_VIDEOINFO 5
+#define IPC_CB_MISC_TITLE_RATING 6 // (5.5+ for when the rating is changed via the songticker menu on current file)
+#define IPC_CB_MISC_PAUSE 7 // 5.65+
+#define IPC_CB_MISC_UNPAUSE 8 // 5.65+
+
+/* Example of using IPC_CB_MISC_STATUS to detect the start of track playback with 5.x
+**
+** if(lParam == IPC_CB_MISC && wParam == IPC_CB_MISC_STATUS)
+** {
+** if(SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING) == 1 &&
+** !SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETOUTPUTTIME))
+** {
+** char* file = (char*)SendMessageW(hwnd_winamp,WM_WA_IPC,
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS),IPC_GETPLAYLISTFILE);
+** // only output if a valid file was found
+** if(file)
+** {
+** MessageBox(hwnd_winamp,file,"starting",0);
+** // or do something else that you need to do
+** }
+** }
+** }
+*/
+
+
+#define IPC_CB_CONVERT_STATUS 604 // param value goes from 0 to 100 (percent)
+#define IPC_CB_CONVERT_DONE 605
+
+
+#define IPC_ADJUST_FFWINDOWSMENUPOS 606
+/* (requires Winamp 2.9+)
+** int newpos=SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFWINDOWSMENUPOS);
+** This will move where Winamp expects the freeform windows in the menubar windows main
+** menu. This is useful if you wish to insert a menu item above extra freeform windows.
+*/
+
+
+#define IPC_ISDOUBLESIZE 608
+/* (requires Winamp 5.0+)
+** int dsize=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISDOUBLESIZE);
+** You send this to Winamp to query if the double size mode is enabled or not.
+** If it is on then this will return 1 otherwise it will return 0.
+*/
+
+
+#define IPC_ADJUST_FFOPTIONSMENUPOS 609
+/* (requires Winamp 2.9+)
+** int newpos=SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFOPTIONSMENUPOS);
+** moves where winamp expects the freeform preferences item in the menubar windows main
+** menu. This is useful if you wish to insert a menu item above the preferences item.
+** If you pass adjust_offset as zero then it will return the current offset without adjusting it.
+**
+** Note: This setting was ignored by gen_ff until it was fixed in 5.1
+** gen_ff would assume that the menu position was 11 in all cases and so when you
+** had two plugins attempting to add entries into the main right click menu it
+** would cause the 'colour themes' submenu to either be incorrectly duplicated or
+** to just disappear instead.
+*/
+
+
+#define IPC_GETTIMEDISPLAYMODE 610
+/* (requires Winamp 5.0+)
+** int mode=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETTIMEDISPLAYMODE);
+** This will return the status of the time display i.e. shows time elapsed or remaining.
+** This returns 0 if Winamp is displaying time elapsed or 1 for the time remaining.
+*/
+
+
+#define IPC_SETVISWND 611
+/* (requires Winamp 5.0+)
+** int viswnd=(HWND)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)viswnd,IPC_SETVISWND);
+** This allows you to set a window to receive the following message commands (which are
+** used as part of the modern skin integration).
+** When you have finished or your visualisation is closed then send wParam as zero to
+** ensure that things are correctly tidied up.
+*/
+
+/* The following messages are received as the LOWORD(wParam) of the WM_COMMAND message.
+** See %SDK%\winamp\wa5vis.txt for more info about visualisation integration in Winamp.
+*/
+#define ID_VIS_NEXT 40382
+#define ID_VIS_PREV 40383
+#define ID_VIS_RANDOM 40384
+#define ID_VIS_FS 40389
+#define ID_VIS_CFG 40390
+#define ID_VIS_MENU 40391
+
+
+#define IPC_GETVISWND 612
+/* (requires Winamp 5.0+)
+** int viswnd=(HWND)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVISWND);
+** This returns a HWND to the visualisation command handler window if set by IPC_SETVISWND.
+*/
+
+
+#define IPC_ISVISRUNNING 613
+/* (requires Winamp 5.0+)
+** int visrunning=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISVISRUNNING);
+** This will return 1 if a visualisation is currently running and 0 if one is not running.
+*/
+
+
+#define IPC_CB_VISRANDOM 628 // param is status of random
+
+
+#define IPC_SETIDEALVIDEOSIZE 614
+/* (requires Winamp 5.0+)
+** This is sent by Winamp back to itself so it can be trapped and adjusted as needed with
+** the desired width in HIWORD(wParam) and the desired height in LOWORD(wParam).
+**
+** if(uMsg == WM_WA_IPC){
+** if(lParam == IPC_SETIDEALVIDEOSIZE){
+** wParam = MAKEWPARAM(height,width);
+** }
+** }
+*/
+
+
+#define IPC_GETSTOPONVIDEOCLOSE 615
+/* (requires Winamp 5.0+)
+** int sovc=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETSTOPONVIDEOCLOSE);
+** This will return 1 if 'stop on video close' is enabled and 0 if it is disabled.
+*/
+
+
+#define IPC_SETSTOPONVIDEOCLOSE 616
+/* (requires Winamp 5.0+)
+** int sovc=SendMessageW(hwnd_winamp,WM_WA_IPC,enabled,IPC_SETSTOPONVIDEOCLOSE);
+** Set enabled to 1 to enable and 0 to disable the 'stop on video close' option.
+*/
+
+
+typedef struct {
+ HWND hwnd;
+ int uMsg;
+ WPARAM wParam;
+ LPARAM lParam;
+} transAccelStruct;
+
+#define IPC_TRANSLATEACCELERATOR 617
+/* (requires Winamp 5.0+)
+** (deprecated as of 5.53x+)
+*/
+
+
+typedef struct {
+ int cmd;
+ int x;
+ int y;
+ int align;
+} windowCommand; // send this as param to an IPC_PLCMD, IPC_MBCMD, IPC_VIDCMD
+
+
+#define IPC_CB_ONTOGGLEAOT 618
+
+
+#define IPC_GETPREFSWND 619
+/* (requires Winamp 5.0+)
+** HWND prefs = (HWND)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETPREFSWND);
+** This will return a handle to the preferences dialog if it is open otherwise it will
+** return zero. A simple check with the OS api IsWindow(..) is a good test if it's valid.
+**
+** e.g. this will open (or close if already open) the preferences dialog and show if we
+** managed to get a valid
+** SendMessageW(hwnd_winamp,WM_COMMAND,MAKEWPARAM(WINAMP_OPTIONS_PREFS,0),0);
+** MessageBox(hwnd_winamp,(IsWindow((HWND)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETPREFSWND))?"Valid":"Not Open"),0,MB_OK);
+*/
+
+
+#define IPC_SET_PE_WIDTHHEIGHT 620
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&point,IPC_SET_PE_WIDTHHEIGHT);
+** You pass a pointer to a POINT structure which holds the width and height and Winamp
+** will set the playlist editor to that size (this is used by gen_ff on skin changes).
+** There does not appear to be any bounds limiting with this so it is possible to create
+** a zero size playlist editor window (which is a pretty silly thing to do).
+*/
+
+
+#define IPC_GETLANGUAGEPACKINSTANCE 621
+/* (requires Winamp 5.0+)
+** HINSTANCE hInst = (HINSTANCE)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE);
+** This will return the HINSTANCE to the currently used language pack file for winamp.exe
+**
+** (5.5+)
+** If you pass 1 in wParam then you will have zero returned if a language pack is in use.
+** if(!SendMessageW(hwnd_winamp,WM_WA_IPC,1,IPC_GETLANGUAGEPACKINSTANCE)){
+** // winamp is currently using a language pack
+** }
+**
+** If you pass 2 in wParam then you will get the path to the language pack folder.
+** wchar_t* lngpackfolder = (wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,2,IPC_GETLANGUAGEPACKINSTANCE);
+**
+** If you pass 3 in wParam then you will get the path to the currently extracted language pack.
+** wchar_t* lngpack = (wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,3,IPC_GETLANGUAGEPACKINSTANCE);
+**
+** If you pass 4 in wParam then you will get the name of the currently used language pack.
+** wchar_t* lngname = (char*)SendMessageW(hwnd_winamp,WM_WA_IPC,4,IPC_GETLANGUAGEPACKINSTANCE);
+*/
+#define LANG_IDENT_STR 0
+#define LANG_LANG_CODE 1
+#define LANG_COUNTRY_CODE 2
+/*
+** (5.51+)
+** If you pass 5 in LOWORD(wParam) then you will get the ident string/code string
+** (based on the param passed in the HIWORD(wParam) of the currently used language pack.
+** The string returned with LANG_IDENT_STR is used to represent the language that the
+** language pack is intended for following ISO naming conventions for consistancy.
+**
+** wchar_t* ident_str = (wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,MAKEWPARAM(5,LANG_XXX),IPC_GETLANGUAGEPACKINSTANCE);
+**
+** e.g.
+** For the default language it will return the following for the different LANG_XXX codes
+** LANG_IDENT_STR -> "en-US" (max buffer size of this is 9 wchar_t)
+** LANG_LANG_CODE -> "en" (language code)
+** LANG_COUNTRY_CODE -> "US" (country code)
+**
+** On pre 5.51 installs you can get LANG_IDENT_STR using the following method
+** (you'll have to custom process the string returned if you want the langugage or country but that's easy ;) )
+**
+** #define LANG_PACK_LANG_ID 65534 (if you don't have lang.h)
+** HINSTANCE hInst = (HINSTANCE)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE);
+** wchar_t buffer[9] = {0};
+** LoadStringW(hInst,LANG_PACK_LANG_ID,buffer,sizeof(buffer)/sizeof(wchar_t));
+**
+**
+**
+** The following example shows how using the basic api will allow you to load the playlist
+** context menu resource from the currently loaded language pack or it will fallback to
+** the default winamp.exe instance.
+**
+** HINSTANCE lang = (HINSTANCE)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE);
+** HMENU popup = GetSubMenu(GetSubMenu((LoadMenu(lang?lang:GetModuleHandle(0),MAKEINTRESOURCE(101))),2),5);
+** // do processing as needed on the menu before displaying it
+** TrackPopupMenuEx(orig,TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,rc.left,rc.bottom,hwnd_owner,0);
+** DestroyMenu(popup);
+**
+** If you need a specific menu handle then look at IPC_GET_HMENU for more information.
+*/
+
+
+#define IPC_CB_PEINFOTEXT 622 // data is a string, ie: "04:21/45:02"
+
+
+#define IPC_CB_OUTPUTCHANGED 623 // output plugin was changed in config
+
+
+#define IPC_GETOUTPUTPLUGIN 625
+/* (requires Winamp 5.0+)
+** char* outdll = (char*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETOUTPUTPLUGIN);
+** This returns a string of the current output plugin's dll name.
+** e.g. if the directsound plugin was selected then this would return 'out_ds.dll'.
+*/
+
+
+#define IPC_SETDRAWBORDERS 626
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,enabled,IPC_SETDRAWBORDERS);
+** Set enabled to 1 to enable and 0 to disable drawing of the playlist editor and winamp
+** gen class windows (used by gen_ff to allow it to draw its own window borders).
+*/
+
+
+#define IPC_DISABLESKINCURSORS 627
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,enabled,IPC_DISABLESKINCURSORS);
+** Set enabled to 1 to enable and 0 to disable the use of skinned cursors.
+*/
+
+
+#define IPC_GETSKINCURSORS 628
+/* (requires Winamp 5.36+)
+** data = (WACURSOR)cursorId. (check wa_dlg.h for values)
+*/
+
+
+#define IPC_CB_RESETFONT 629
+
+
+#define IPC_IS_FULLSCREEN 630
+/* (requires Winamp 5.0+)
+** int val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_IS_FULLSCREEN);
+** This will return 1 if the video or visualisation is in fullscreen mode or 0 otherwise.
+*/
+
+
+#define IPC_SET_VIS_FS_FLAG 631
+/* (requires Winamp 5.0+)
+** A vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode
+*/
+
+
+#define IPC_SHOW_NOTIFICATION 632
+/* (requires Winamp 5.0+ & Modern skin support - gen_ff.dll present)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_SHOW_NOTIFICATION);
+** If a Modern skin is loaded and this message is sent/received then it will
+** trigger the Modern skin notifier to appear (subject to user settings).
+*/
+
+
+#define IPC_GETSKININFO 633
+#define IPC_GETSKININFOW 1633
+/* (requires Winamp 5.0+)
+** This is a notification message sent to the main Winamp window by itself whenever it
+** needs to get information to be shown about the current skin in the 'Current skin
+** information' box on the main Skins page in the Winamp preferences.
+**
+** When this notification is received and the current skin is one you are providing the
+** support for then you return a valid buffer for Winamp to be able to read from with
+** information about it such as the name of the skin file.
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_GETSKININFO){
+** if(is_our_skin()){
+** return is_our_skin_name();
+** }
+** }
+*/
+
+
+#define IPC_GET_MANUALPLADVANCE 634
+/* (requires Winamp 5.03+)
+** int val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_MANUALPLADVANCE);
+** IPC_GET_MANUALPLADVANCE returns the status of the Manual Playlist Advance.
+** If enabled this will return 1 otherwise it will return 0.
+*/
+
+
+#define IPC_SET_MANUALPLADVANCE 635
+/* (requires Winamp 5.03+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SET_MANUALPLADVANCE);
+** IPC_SET_MANUALPLADVANCE sets the status of the Manual Playlist Advance option.
+** Set value = 1 to turn it on and value = 0 to turn it off.
+*/
+
+
+#define IPC_GET_NEXT_PLITEM 636
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_NEXT_PLITEM);
+**
+** Sent to Winamp's main window when an item has just finished playback or the next
+** button has been pressed and requesting the new playlist item number to go to.
+**
+** Subclass this message in your application to return the new item number.
+** Return -1 for normal Winamp operation (default) or the new item number in
+** the playlist to be played instead of the originally selected next track.
+*/
+
+
+#define IPC_GET_PREVIOUS_PLITEM 637
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PREVIOUS_PLITEM);
+**
+** Sent to Winamp's main window when the previous button has been pressed and Winamp is
+** requesting the new playlist item number to go to.
+**
+** Return -1 for normal Winamp operation (default) or the new item number in
+** the playlist to be played instead of the originally selected previous track.
+*/
+
+
+#define IPC_IS_WNDSHADE 638
+/* (requires Winamp 5.04+)
+** int is_shaded=SendMessageW(hwnd_winamp,WM_WA_IPC,wnd,IPC_IS_WNDSHADE);
+** Pass 'wnd' as an id as defined for IPC_GETWND or pass -1 to query the status of the
+** main window. This returns 1 if the window is in winshade mode and 0 if it is not.
+** Make sure you only test for this on a 5.04+ install otherwise you get a false result.
+** (See the notes about unhandled WM_WA_IPC messages).
+*/
+
+
+#define IPC_SETRATING 639
+/* (requires Winamp 5.04+ with ML)
+** int rating=SendMessageW(hwnd_winamp,WM_WA_IPC,rating,IPC_SETRATING);
+** This will allow you to set the 'rating' on the current playlist entry where 'rating'
+** is an integer value from 0 (no rating) to 5 (5 stars).
+**
+** The following example should correctly allow you to set the rating for any specified
+** playlist entry assuming of course that you're trying to get a valid playlist entry.
+**
+** void SetPlaylistItemRating(int item_to_set, int rating_to_set){
+** int cur_pos=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,item_to_set,IPC_SETPLAYLISTPOS);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,rating_to_set,IPC_SETRATING);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,cur_pos,IPC_SETPLAYLISTPOS);
+** }
+**
+** Note: Winamp 5.6+ allows you to save the rating directly into the file as long as the
+** file being rated supports the rating metadata field via a supporting input plug-in
+** to process the tag save as appropriate. If not then the rating will not be saved.
+*/
+
+
+#define IPC_GETRATING 640
+/* (requires Winamp 5.04+ with ML)
+** int rating=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING);
+** This returns the current playlist entry's rating between 0 (no rating) to 5 (5 stars).
+**
+** The following example should correctly allow you to get the rating for any specified
+** playlist entry assuming of course that you're trying to get a valid playlist entry.
+**
+** int GetPlaylistItemRating(int item_to_get, int rating_to_set){
+** int cur_pos=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS), rating = 0;
+** SendMessageW(hwnd_winamp,WM_WA_IPC,item_to_get,IPC_SETPLAYLISTPOS);
+** rating = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING);
+** SendMessageW(hwnd_winamp,WM_WA_IPC,cur_pos,IPC_SETPLAYLISTPOS);
+** return rating;
+** }
+*/
+
+
+#define IPC_GETNUMAUDIOTRACKS 641
+/* (requires Winamp 5.04+)
+** int n = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMAUDIOTRACKS);
+** This will return the number of audio tracks available from the currently playing item.
+*/
+
+
+#define IPC_GETNUMVIDEOTRACKS 642
+/* (requires Winamp 5.04+)
+** int n = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMVIDEOTRACKS);
+** This will return the number of video tracks available from the currently playing item.
+*/
+
+
+#define IPC_GETAUDIOTRACK 643
+/* (requires Winamp 5.04+)
+** int cur = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETAUDIOTRACK);
+** This will return the id of the current audio track for the currently playing item.
+*/
+
+
+#define IPC_GETVIDEOTRACK 644
+/* (requires Winamp 5.04+)
+** int cur = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVIDEOTRACK);
+** This will return the id of the current video track for the currently playing item.
+*/
+
+
+#define IPC_SETAUDIOTRACK 645
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,track,IPC_SETAUDIOTRACK);
+** This allows you to switch to a new audio track (if supported) in the current playing file.
+*/
+
+
+#define IPC_SETVIDEOTRACK 646
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,track,IPC_SETVIDEOTRACK);
+** This allows you to switch to a new video track (if supported) in the current playing file.
+*/
+
+
+#define IPC_PUSH_DISABLE_EXIT 647
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_PUSH_DISABLE_EXIT);
+** This will let you disable or re-enable the UI exit functions (close button, context
+** menu, alt-f4). Remember to call IPC_POP_DISABLE_EXIT when you are done doing whatever
+** was required that needed to prevent exit otherwise you have to kill the Winamp process.
+*/
+
+
+#define IPC_POP_DISABLE_EXIT 648
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_POP_DISABLE_EXIT);
+** See IPC_PUSH_DISABLE_EXIT
+*/
+
+
+#define IPC_IS_EXIT_ENABLED 649
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_IS_EXIT_ENABLED);
+** This will return 0 if the 'exit' option of Winamp's menu is disabled and 1 otherwise.
+*/
+
+
+#define IPC_IS_AOT 650
+/* (requires Winamp 5.04+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_IS_AOT);
+** This will return the status of the always on top flag.
+** Note: This may not match the actual TOPMOST window flag while another fullscreen
+** application is focused if the user has the 'Disable always on top while fullscreen
+** applications are focused' option under the General Preferences page is checked.
+*/
+
+
+#define IPC_USES_RECYCLEBIN 651
+/* (requires Winamp 5.09+)
+** int use_bin=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_USES_RECYCLEBIN);
+** This will return 1 if the deleted file should be sent to the recycle bin or
+** 0 if deleted files should be deleted permanently (default action for < 5.09).
+**
+** Note: if you use this on pre 5.09 installs of Winamp then it will return 1 which is
+** not correct but is due to the way that SendMessageW(..) handles un-processed messages.
+** Below is a quick case for checking if the returned value is correct.
+**
+** if(SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_USES_RECYCLEBIN) &&
+** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION)>=0x5009)
+** {
+** // can safely follow the option to recycle the file
+** }
+** else
+* {
+** // need to do a permanent delete of the file
+** }
+*/
+
+
+//#define IPC_FLUSHAUDITS 652
+
+
+#define IPC_GETPLAYITEM_START 653
+#define IPC_GETPLAYITEM_END 654
+
+
+#define IPC_GETVIDEORESIZE 655
+#define IPC_SETVIDEORESIZE 656
+
+
+#define IPC_INITIAL_SHOW_STATE 657
+/* (requires Winamp 5.36+)
+** int show_state = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_INITIAL_SHOW_STATE);
+** returns the processed value of nCmdShow when Winamp was started
+** (see MSDN documentation the values passed to WinMain(..) for what this should be)
+**
+** e.g.
+** if(SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_INITIAL_SHOW_STATE) == SW_SHOWMINIMIZED){
+** // we are starting minimised so process as needed (keep our window hidden)
+** }
+**
+** Useful for seeing if winamp was run minimised on startup so you can act accordingly.
+** On pre-5.36 versions this will effectively return SW_NORMAL/SW_SHOWNORMAL due to the
+** handling of unknown apis returning 1 from Winamp.
+*/
+
+
+#define IPC_GET_STOP_AFTER_CURRENT 658
+/* (requires Winamp 5.58+)
+** int stopping=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_STOP_AFTER_CURRENT);
+** IPC_GET_STOP_AFTER_CURRENT returns the status of the Stop After Current state.
+** If enabled this will return 0 otherwise it will return 1 (see the notes about
+** SendMessageW(WM_WA_IPC) handling with unsupported apis for why this is inverted).
+*/
+
+// >>>>>>>>>>> Next is 659
+
+#define IPC_PLCMD 1000
+
+#define PLCMD_ADD 0
+#define PLCMD_REM 1
+#define PLCMD_SEL 2
+#define PLCMD_MISC 3
+#define PLCMD_LIST 4
+
+//#define IPC_MBCMD 1001
+
+#define MBCMD_BACK 0
+#define MBCMD_FORWARD 1
+#define MBCMD_STOP 2
+#define MBCMD_RELOAD 3
+#define MBCMD_MISC 4
+
+#define IPC_VIDCMD 1002
+
+#define VIDCMD_FULLSCREEN 0
+#define VIDCMD_1X 1
+#define VIDCMD_2X 2
+#define VIDCMD_LIB 3
+#define VIDPOPUP_MISC 4
+#define VIDCMD_EXIT_FS 5
+
+//#define IPC_MBURL 1003 //sets the URL
+//#define IPC_MBGETCURURL 1004 //copies the current URL into wParam (have a 4096 buffer ready)
+//#define IPC_MBGETDESC 1005 //copies the current URL description into wParam (have a 4096 buffer ready)
+//#define IPC_MBCHECKLOCFILE 1006 //checks that the link file is up to date (otherwise updates it). wParam=parent HWND
+//#define IPC_MBREFRESH 1007 //refreshes the "now playing" view in the library
+//#define IPC_MBGETDEFURL 1008 //copies the default URL into wParam (have a 4096 buffer ready)
+
+#define IPC_STATS_LIBRARY_ITEMCNT 1300 // updates library count status
+
+/*
+** IPC's in the message range 2000 - 3000 are reserved internally for freeform messages.
+** These messages are taken from ff_ipc.h which is part of the Modern skin integration.
+*/
+
+#define IPC_FF_FIRST 2000
+
+#define IPC_FF_COLOURTHEME_CHANGE IPC_FF_ONCOLORTHEMECHANGED
+#define IPC_FF_ONCOLORTHEMECHANGED IPC_FF_FIRST + 3
+/*
+** This is a notification message sent when the user changes the colour theme in a Modern
+** skin and can also be detected when the Modern skin is first loaded as the gen_ff plugin
+** applies relevant settings and styles (like the colour theme).
+**
+** The value of wParam is the name of the new color theme being switched to.
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(const char*)colour_theme_name,IPC_FF_ONCOLORTHEMECHANGED);
+**
+** (IPC_FF_COLOURTHEME_CHANGE is the name i (DrO) was using before getting a copy of
+** ff_ipc.h with the proper name in it).
+*/
+
+
+#define IPC_FF_ISMAINWND IPC_FF_FIRST + 4
+/*
+** int ismainwnd = (HWND)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)test_wnd,IPC_FF_ISMAINWND);
+**
+** This allows you to determine if the window handle passed to it is a modern skin main
+** window or not. If it is a main window or any of its windowshade variants then it will
+** return 1.
+**
+** Because of the way modern skins are implemented, it is possible for this message to
+** return a positive test result for a number of window handles within the current Winamp
+** process. This appears to be because you can have a visible main window, a compact main
+** window and also a winshaded version.
+**
+** The following code example below is one way of seeing how this api works since it will
+** enumerate all windows related to Winamp at the time and allows you to process as
+** required when a detection happens.
+**
+**
+** EnumThreadWindows(GetCurrentThreadId(),enumWndProc,0);
+**
+** BOOL CALLBACK enumWndProc(HWND hwnd, LPARAM lParam){
+**
+** if(SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)hwnd,IPC_FF_ISMAINWND)){
+** // do processing in here
+** // or continue the enum for other main windows (if they exist)
+** // and just comment out the line below
+** return 0;
+** }
+** return 1;
+** }
+*/
+
+
+#define IPC_FF_GETCONTENTWND IPC_FF_FIRST + 5
+/*
+** HWND wa2embed = (HWND)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)test_wnd,IPC_FF_GETCONTENTWND);
+**
+** This will return the Winamp 2 window that is embedded in the window's container
+** i.e. if hwnd is the playlist editor windowshade hwnd then it will return the Winamp 2
+** playlist editor hwnd.
+**
+** If no content is found such as the window has nothing embedded then this will return
+** the hwnd passed to it.
+*/
+
+
+#define IPC_FF_NOTIFYHOTKEY IPC_FF_FIRST + 6
+/*
+** This is a notification message sent when the user uses a global hotkey combination
+** which had been registered with the gen_hotkeys plugin.
+**
+** The value of wParam is the description of the hotkey as passed to gen_hotkeys.
+** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(const char*)hotkey_desc,IPC_FF_NOTIFYHOTKEY);
+*/
+
+#define IPC_FF_LAST 3000
+
+
+/*
+** General IPC messages in Winamp
+**
+** All notification messages appear in the lParam of the main window message proceedure.
+*/
+
+
+#define IPC_GETDROPTARGET 3001
+/* (requires Winamp 5.0+)
+** IDropTarget* IDrop = (IDropTarget*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETDROPTARGET);
+**
+** You call this to retrieve a copy of the IDropTarget interface which Winamp created for
+** handling external drag and drop operations on to it's Windows. This is only really
+** useful if you're providing an alternate interface and want your Windows to provide the
+** same drag and drop support as Winamp normally provides the user. Check out MSDN or
+** your prefered search facility for more information about the IDropTarget interface and
+** what's needed to handle it in your own instance.
+*/
+
+
+#define IPC_PLAYLIST_MODIFIED 3002
+/* (requires Winamp 5.0+)
+** This is a notification message sent to the main Winamp window whenever the playlist is
+** modified in any way e.g. the addition/removal of a playlist entry.
+**
+** It is not a good idea to do large amounts of processing in this notification since it
+** will slow down Winamp as playlist entries are modified (especially when you're adding
+** in a large playlist).
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYLIST_MODIFIED)
+** {
+** // do what you need to do here
+** }
+*/
+
+
+#define IPC_PLAYING_FILE 3003
+/* (requires Winamp 5.0+)
+** This is a notification message sent to the main Winamp window when playback begins for
+** a file. This passes the full filepath in the wParam of the message received.
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILE)
+** {
+** // do what you need to do here, e.g.
+** process_file((char*)wParam);
+** }
+*/
+
+
+#define IPC_PLAYING_FILEW 13003
+/* (requires Winamp 5.3+)
+** This is a notification message sent to the main Winamp window when playback begins for
+** a file. This passes the full filepath in the wParam of the message received.
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILEW)
+** {
+** // do what you need to do here, e.g.
+** process_file((wchar_t*)wParam);
+** }
+*/
+
+#define IPC_FILE_TAG_MAY_UPDATEW 3046
+/* (requires Winamp 5.66+)
+** This is a notification message sent to the main Winamp window when a file is about to
+** be opened in the file info editor and so may have it's tag (e.g. id3) updated.
+**
+** The wParam value holds a copy of the filepath of the file which may update and this
+** can be sent without a matching IPC_FILE_TAG_MAY_HAVE_UPDATED(W) message if the user
+** does not make any changes or the file being edited does not support tagging updates.
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_FILE_TAG_MAY_UPDATEW)
+** {
+** // do what you need to do here, e.g.
+** }
+*/
+
+#define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004
+#define IPC_FILE_TAG_MAY_HAVE_UPDATEDW 3005
+/* (requires Winamp 5.0+)
+** This is a notification message sent to the main Winamp window when a file's tag
+** (e.g. id3) may have been updated. This appears to be sent when the InfoBox(..) function
+** of the associated input plugin returns a 1 (which is the file information dialog/editor
+** call normally).
+**
+** The wParam value holds a copy of the filepath of the file which was updated.
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_FILE_TAG_MAY_HAVE_UPDATED)
+** {
+** // do what you need to do here, e.g.
+** update_info_on_file_update((char*)wParam);
+** }
+*/
+
+
+#define IPC_ALLOW_PLAYTRACKING 3007
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,allow,IPC_ALLOW_PLAYTRACKING);
+** Send allow as nonzero to allow play tracking and zero to disable the mode.
+** This is useful if you're an input plugin and need to edit a tag in a file
+** whilst playing that track so this can be sent to Winamp so it appears like
+** there wasn't a stop in the playback of the file (as far as the UI display).
+*/
+
+
+#define IPC_HOOK_OKTOQUIT 3010
+/* (requires Winamp 5.0+)
+** This is a notification message sent to the main Winamp window asking if it's okay to
+** close or not. Return zero to prevent Winamp from closing or return anything non-zero
+** to allow Winamp to close.
+**
+** The best implementation of this option is to let the message pass through to the
+** original window proceedure since another plugin may want to have a say in the matter
+** with regards to Winamp closing.
+**
+** if(uMsg == WM_WA_IPC && lParam == IPC_HOOK_OKTOQUIT)
+** {
+** // do what you need to do here, e.g.
+** if(no_shut_down())
+** {
+** return 0;
+** }
+** }
+*/
+
+
+#define IPC_WRITECONFIG 3011
+/* (requires Winamp 5.0+)
+** SendMessageW(hwnd_winamp,WM_WA_IPC,write_type,IPC_WRITECONFIG);
+**
+** Send write_type as 2 to write all config settings and the current playlist.
+**
+** Send write_type as 1 to write the playlist and common settings.
+** This won't save the following ini settings::
+**
+** defext, titlefmt, proxy, visplugin_name, dspplugin_name, check_ft_startup,
+** visplugin_num, pe_fontsize, visplugin_priority, visplugin_autoexec, dspplugin_num,
+** sticon, splash, taskbar, dropaotfs, ascb_new, ttips, riol, minst, whichicon,
+** whichicon2, addtolist, snap, snaplen, parent, hilite, disvis, rofiob, shownumsinpl,
+** keeponscreen, eqdsize, usecursors, fixtitles, priority, shuffle_morph_rate,
+** useexttitles, bifont, inet_mode, ospb, embedwnd_freesize, no_visseh
+** (the above was valid for 5.1)
+**
+** Send write_type as 0 to write the common and less common settings and no playlist.
+*/
+
+
+#define IPC_UPDATE_URL 3012
+// pass the URL (char *) in lparam, will be free()'d on done.
+
+
+#define IPC_GET_RANDFUNC 3015 // returns a function to get a random number
+/* (requires Winamp 5.1+)
+** int (*randfunc)(void) = (int(*)(void))SendMessageW(plugin.hwndParent,WM_WA_IPC,0,IPC_GET_RANDFUNC);
+** if(randfunc && randfunc != 1){
+** randfunc();
+** }
+**
+** This will return a positive 32-bit number (essentially 31-bit).
+** The check for a returned value of 1 is because that's the default return value from
+** SendMessageW(..) when it is not handled so is good to check for it in this situation.
+*/
+
+
+#define IPC_METADATA_CHANGED 3017
+/* (requires Winamp 5.1+)
+** int changed=SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)(char*)field,IPC_METADATA_CHANGED);
+** a plugin can SendMessageW this to winamp if internal metadata has changes.
+** wParam should be a char * of what field changed
+**
+** Currently used for internal actions (and very few at that) the intent of this api is
+** to allow a plugin to call it when metadata has changed in the current playlist entry
+** e.g.a new id3v2 tag was found in a stream
+**
+** The wparam value can either be NULL or a pointer to an ansi string for the metadata
+** which has changed. This can be thought of as an advanced version of IPC_UPDTITLE and
+** could be used to allow for update of the current title when a specific tag changed.
+**
+** Not recommended to be used since there is not the complete handling implemented in
+** Winamp for it at the moment.
+*/
+
+
+#define IPC_SKIN_CHANGED 3018
+/* (requires Winamp 5.1+)
+** This is a notification message sent to the main Winamp window by itself whenever
+** the skin in use is changed. There is no information sent by the wParam for this.
+**
+** if(message == WM_WA_IPC && lparam == IPC_SKIN_CHANGED)
+** {
+** // do what you need to do to handle skin changes, e.g. call WADlg_init(hwnd_winamp);
+** }
+*/
+
+
+#define IPC_REGISTER_LOWORD_COMMAND 3019
+/* (requires Winamp 5.1+)
+** WORD id = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_REGISTER_LOWORD_COMMAND);
+** This will assign you a unique id for making your own commands such as for extra menu
+** entries. The starting value returned by this message will potentially change as and
+** when the main resource file of Winamp is updated with extra data so assumptions cannot
+** be made on what will be returned and plugin loading order will affect things as well.
+
+** 5.33+
+** If you want to reserve more than one id, you can pass the number of ids required in wParam
+*/
+
+
+typedef struct
+{
+ wchar_t *name; // filled in by plugin, make sure it's a unicode string!! (i.e. L"myObject" instead of "myObject).
+ struct IDispatch *dispatch; // filled in by plugin
+ DWORD id; // filled in by winamp on return
+} DispatchInfo;
+
+#define IPC_GET_DISPATCH_OBJECT 3020 // gets winamp main IDispatch * (for embedded webpages)
+#define IPC_GET_UNIQUE_DISPATCH_ID 3021 // gives you a unique dispatch ID that won't conflict with anything in winamp's IDispatch *
+#define IPC_ADD_DISPATCH_OBJECT 3022 // add your own dispatch object into winamp's. This lets embedded webpages access your functions
+// pass a pointer to DispatchInfo (see below). Winamp makes a copy of all this data so you can safely delete it later
+
+#define IPC_REMOVE_DISPATCH_OBJECT 3038
+/* (requires Winamp 5.56+)
+** remove registered IDispatch. pass (DWORD)dispatchId ad parameter
+*/
+
+// see IPC_JSAPI2_GET_DISPATCH_OBJECT for version 2 of the Dispatchable scripting interface
+
+
+#define IPC_GET_PROXY_STRING 3023
+/* (requires Winamp 5.11+)
+** char* proxy_string=(char*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PROXY_STRING);
+** This will return the same string as is shown on the General Preferences page.
+*/
+
+
+#define IPC_USE_REGISTRY 3024
+/* (requires Winamp 5.11+)
+** int reg_enabled=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_USE_REGISTRY);
+** This will return 0 if you should leave your grubby hands off the registry (i.e. for
+** lockdown mode). This is useful if Winamp is run from a USB drive and you can't alter
+** system settings, etc.
+*/
+
+
+#define IPC_GET_API_SERVICE 3025
+/* (requires Winamp 5.12+)
+** api_service* api_service = (api_service*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_API_SERVICE);
+** This api will return Winamp's api_service pointer (which is what Winamp3 used, heh).
+** If this api is not supported in the Winamp version that is being used at the time then
+** the returned value from this api will be 1 which is a good version check.
+**
+** As of 5.12 there is support for .w5s plugins which reside in %WinampDir%\System and
+** are intended for common code that can be shared amongst other plugins e.g. jnetlib.w5s
+** which contains jnetlib in one instance instead of being duplicated multiple times in
+** all of the plugins which need internet access.
+**
+** Details on the .w5s specifications will come at some stage (possibly).
+*/
+
+
+typedef struct {
+ const wchar_t *filename;
+ const wchar_t *metadata;
+ wchar_t *ret;
+ size_t retlen;
+} extendedFileInfoStructW;
+
+#define IPC_GET_EXTENDED_FILE_INFOW 3026
+/* (requires Winamp 5.13+)
+** Pass a pointer to the above struct in wParam
+*/
+
+
+#define IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE 3027
+#define IPC_SET_EXTENDED_FILE_INFOW 3028
+/* (requires Winamp 5.13+)
+** Pass a pointer to the above struct in wParam
+*/
+
+
+#define IPC_PLAYLIST_GET_NEXT_SELECTED 3029
+/* (requires 5.2+)
+** int pl_item = SendMessageW(hwnd_winamp,WM_WA_IPC,start,IPC_PLAYLIST_GET_NEXT_SELECTED);
+**
+** This works just like the ListView_GetNextItem(..) macro for ListView controls.
+** 'start' is the index of the playlist item that you want to begin the search after or
+** set this as -1 for the search to begin with the first item of the current playlist.
+**
+** This will return the index of the selected playlist according to the 'start' value or
+** it returns -1 if there is no selection or no more selected items according to 'start'.
+**
+** Quick example:
+**
+** int sel = -1;
+** // keep incrementing the start of the search so we get all of the selected entries
+** while((sel = SendMessageW(hwnd_winamp,WM_WA_IPC,sel,IPC_PLAYLIST_GET_NEXT_SELECTED))!=-1){
+** // show the playlist file entry of the selected item(s) if there were any
+** MessageBox(hwnd_winamp,(char*)SendMessageW(hwnd_winamp,WM_WA_IPC,sel,IPC_GETPLAYLISTFILE),0,0);
+** }
+*/
+
+
+#define IPC_PLAYLIST_GET_SELECTED_COUNT 3030
+/* (requires 5.2+)
+** int selcnt = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_PLAYLIST_GET_SELECTED_COUNT);
+** This will return the number of selected playlist entries.
+*/
+
+
+#define IPC_GET_PLAYING_FILENAME 3031
+/* (requires Winamp 5.?+)
+** wchar_t* fn=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PLAYING_FILENAME);
+** This will return the currently playing filename string as held by Winamp.
+*/
+
+
+#define IPC_OPEN_URL 3032
+// send either ANSI or Unicode string (it'll figure it out, but it MUST start with "h"!, so don't send ftp:// or anything funny)
+// you can also send this one from another process via WM_COPYDATA (unicode only)
+
+
+#define IPC_USE_UXTHEME_FUNC 3033
+/* (requires Winamp 5.35+)
+** int ret = SendMessageW(hwnd_winamp,WM_WA_IPC,param,IPC_USE_UXTHEME_FUNC);
+** param can be IPC_ISWINTHEMEPRESENT or IPC_ISAEROCOMPOSITIONACTIVE or a valid hwnd.
+**
+** If you pass a hwnd then it will apply EnableThemeDialogTexture(ETDT_ENABLETAB)
+** so your tabbed dialogs can use the correct theme (on supporting OSes ie XP+).
+**
+** Otherwise this will return a value based on the param passed (as defined below).
+** For compatability, the return value will be zero on success (as 1 is returned
+** for unsupported ipc calls on older Winamp versions)
+*/
+ #define IPC_ISWINTHEMEPRESENT 0
+/* This will return 0 if uxtheme.dll is present
+** int isthemethere = !SendMessageW(hwnd_winamp,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC);
+*/
+ #define IPC_ISAEROCOMPOSITIONACTIVE 1
+/* This will return 0 if aero composition is active
+** int isaero = !SendMessageW(hwnd_winamp,WM_WA_IPC,IPC_ISAEROCOMPOSITIONACTIVE,IPC_USE_UXTHEME_FUNC);
+*/
+
+
+#define IPC_GET_PLAYING_TITLE 3034
+/* (requires Winamp 5.5+)
+** wchar_t* title=(wchar_t*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PLAYING_TITLE);
+** This will return the currently playing file title string as displayed in Winamp's window.
+*/
+
+
+#define IPC_CANPLAY 3035
+/* (requires Winamp 5.5+)
+** In_Module *in_mod=(In_Module*)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)fn,IPC_CANPLAY);
+** This api will return either a In_Module* for plugin associated with the file passed or
+** it will return 0 to indicate there is not a supporting input plugin.
+** Pass a unicode (wchar_t) filepath.
+**
+** In_Module *in_mod=(In_Module*)SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)fn,IPC_CANPLAY);
+** if(in_mod && (in_mod != (In_Module*)1){
+** // we got a valid In_Module *
+** }
+*/
+
+
+typedef struct {
+ // fill these in...
+ size_t size; // init to sizeof(artFetchData)
+ HWND parent; // parent window of the dialogue
+
+ // fill as much of these in as you can, otherwise leave them 0
+ const wchar_t *artist;
+ const wchar_t *album;
+ int year, amgArtistId, amgAlbumId;
+
+ int showCancelAll; // if set to 1, this shows a "Cancel All" button on the dialogue
+
+ // winamp will fill these in if the call returns successfully:
+ void* imgData; // a buffer filled with compressed image data. free with WASABI_API_MEMMGR->sysFree()
+ int imgDataLen; // the size of the buffer
+ wchar_t type[10]; // eg: "jpg"
+ const wchar_t *gracenoteFileId; // if you know it
+} artFetchData;
+
+#define IPC_FETCH_ALBUMART 3036
+/* pass an artFetchData*. This will show a dialog guiding the use through choosing art, and return when it's finished
+** return values:
+** 1: error showing dialog
+** 0: success
+** -1: cancel was pressed
+** -2: cancel all was pressed
+*/
+
+
+#define IPC_JSAPI2_GET_DISPATCH_OBJECT 3037
+/* pass your service's unique ID, as a wchar_t * string, in wParam
+** Winamp will copy the string, so don't worry about keeping it around
+** An IDispatch * object will be returned (cast the return value from SendMessageW)
+** This IDispatch can be used for scripting/automation/VB interaction
+** Pass to IE via IDocHostUIHandler::GetExternal and it will become window.external in javscript
+*/
+
+// #define IPC_REMOVE_DISPATCH_OBJECT 3038 /* this id already in use */
+
+
+#define IPC_HANDLE_URI 3039 /* only for use in WM_COPYDATA, passes Winamp a filename that will get handled by svc_urihandler */
+
+
+#define IPC_PLAYFILEW_NDE 3040 /* just like IPC_PLAYFILEW, but the filename is an NDE reference-counted string (but not the title!!) */
+#define IPC_PLAYFILEW_NDE_TITLE 3041 /* use this if the title is reference counted also */
+
+
+#define IPC_OUTPUT_STARTED 3042
+/* (requires Winamp 5.57+)
+** This is a notification message sent to the main Winamp window by an output plugin
+** when the pre-buffer has been filled and output has started which is useful if you
+** want to wait until playback has buffered before doing something on song transition.
+**
+** It is not guaranteed that this message is implemented in all output plugins (with
+** only out_ds supporting it as of 5.57) so is recommended to wait for 5 seconds or
+** until you receive this notification message before handling the song transition.
+**
+** if(message == WM_WA_IPC && lparam == IPC_OUTPUT_STARTED)
+** {
+** // do what you need to do
+** }
+*/
+
+
+typedef struct {
+ int last_time;
+ int g_fullstop;
+} stopPlayingInfoStruct;
+
+#define IPC_STOPPLAYING 3043
+/* (requires Winamp 5.57+)
+** This is a notification message sent to the main Winamp window by itself whenever
+** playback is stopped either when file playback ends or the user stops playing.
+**
+** if(message == WM_WA_IPC && lparam == IPC_STOPPLAYING)
+** {
+** // do what you need to do such as logging where playback was
+** }
+*/
+
+
+#define IPC_GET_D3DX9 3044
+/* (requires Winamp 5.57+)
+** HMODULE d3dx9 = (HMODULE)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_D3DX9);
+**
+** This will return the module handle of a d3dx9_*.dll based against the version
+** internally required by Winamp and it's supporting plug-ins (version can change).
+**
+** HMODULE d3dx9 = (HMODULE)SendMessageW(hwnd_winamp,WM_WA_IPC, 0, IPC_GET_D3DX9);
+** if (!d3dx9 || d3dx9 == (HMODULE)1) {
+** // if here then loading failed and you'll need to manually load the library
+** }
+*/
+
+
+#define IPC_GET_FILEREGISTRAR_OBJECT 3045
+/* (requires Winamp 5.58+)
+** IFileTypeRegistrar* registrar = (IFileTypeRegistrar*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_FILEREGISTRAR_OBJECT);
+**
+** You call this to retrieve a copy of a IFileTypeRegistrar object which Winamp will
+** create which provides some commonly used functions for registry and file access
+** which will be automatically elevated on Vista / Window 7 depending on the user's
+** permissions as required.
+**
+** // it is best to call this everytime that the object is required as there is no
+** // guarantee it will already have been created or if it's already been released
+** IFileTypeRegistrar *registrar = (IFileTypeRegistrar*)SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_FILEREGISTRAR_OBJECT);
+** // make sure that we've got a valid object (as 1 is an unsupported api return)
+** if(registrar && (registrar != (IFileTypeRegistrar*)1)){
+** // we got a valid copy of the object (automatically elevated as required)
+** // so now we can start using the IFileTypeRegistrar object as required
+**
+** // once we're done using the IFileTypeRegistrar object for the immediate moment
+** // then we should release the object so everything is kept as clean as possible
+** registrar->Release();
+** }
+**
+** 5.66+:
+** If you pass 1 in wParam then it will skip trying to provide a fallback instance
+** which is helpful for batch processing and you need to know if elevation failed.
+*/
+
+
+#define IPC_SHELL_ACTION_START 3047
+#define IPC_SHELL_ACTION_END 3048
+/* (requires Winamp 5.66+)
+** This is a notification message sent to the main Winamp window by itself whenever
+** there is an action generated by the Windows shell which may change the playlist.
+**
+** if(message == WM_WA_IPC && lparam == IPC_SHELL_ACTION_START)
+** {
+** }
+*/
+
+
+#define IPC_REGISTER_WINAMP_IPCMESSAGE 65536
+/* (requires Winamp 5.0+)
+** DWORD id = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)name,IPC_REGISTER_WINAMP_IPCMESSAGE);
+** e.g. DWORD id = SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)&"enter_a_different_string",IPC_REGISTER_WINAMP_IPCMESSAGE);
+**
+** The value 'id' returned is > 65536 and is incremented on subsequent calls for unique
+** 'name' values passed to it. By using the same 'name' in different plugins will allow a
+** common runtime api to be provided for the currently running instance of Winamp
+** e.g.
+** PostMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)my_param,registered_ipc);
+** Have a look at wa_hotkeys.h for an example on how this api is used in practice for a
+** custom WM_WA_IPC message.
+**
+**
+** if(uMsg == WM_WA_IPC && lParam == id_from_register_winamp_ipcmessage){
+** // do things
+** }
+*/
+
+/**************************************************************************/
+
+/*
+** Finally there are some WM_COMMAND messages that you can use to send
+** Winamp misc commands.
+**
+** To send these, use:
+**
+** SendMessageW(hwnd_winamp, WM_COMMAND,command_name,0);
+*/
+
+#ifndef _WA_IPC_LEAN_H_
+#define WINAMP_OPTIONS_EQ 40036 // toggles the EQ window
+#define WINAMP_OPTIONS_PLEDIT 40040 // toggles the playlist window
+#define WINAMP_VOLUMEUP 40058 // turns the volume up a little
+#define WINAMP_VOLUMEDOWN 40059 // turns the volume down a little
+#define WINAMP_FFWD5S 40060 // fast forwards 5 seconds
+#define WINAMP_REW5S 40061 // rewinds 5 seconds
+
+// the following are the five main control buttons, with optionally shift
+// or control pressed
+// (for the exact functions of each, just try it out)
+#define WINAMP_BUTTON1 40044
+#define WINAMP_BUTTON2 40045
+#define WINAMP_BUTTON3 40046
+#define WINAMP_BUTTON4 40047
+#define WINAMP_BUTTON5 40048
+#define WINAMP_BUTTON1_SHIFT 40144
+#define WINAMP_BUTTON2_SHIFT 40145
+#define WINAMP_BUTTON3_SHIFT 40146
+#define WINAMP_BUTTON4_SHIFT 40147
+#define WINAMP_BUTTON5_SHIFT 40148
+#define WINAMP_BUTTON1_CTRL 40154
+#define WINAMP_BUTTON2_CTRL 40155
+#define WINAMP_BUTTON3_CTRL 40156
+#define WINAMP_BUTTON4_CTRL 40157
+#define WINAMP_BUTTON5_CTRL 40158
+
+#define WINAMP_FILE_PLAY 40029 // pops up the load file(s) box
+#define WINAMP_FILE_DIR 40187 // pops up the load directory box
+#define WINAMP_OPTIONS_PREFS 40012 // pops up the preferences
+#define WINAMP_OPTIONS_AOT 40019 // toggles always on top
+#define WINAMP_HELP_ABOUT 40041 // pops up the about box :)
+
+#define ID_MAIN_PLAY_AUDIOCD1 40323 // starts playing the audio CD in the first CD reader
+#define ID_MAIN_PLAY_AUDIOCD2 40324 // plays the 2nd
+#define ID_MAIN_PLAY_AUDIOCD3 40325 // plays the 3rd
+#define ID_MAIN_PLAY_AUDIOCD4 40326 // plays the 4th
+#define ID_MAIN_PLAY_AUDIOCD_SEP 40327
+
+// IDs 42000 to 45000 are reserved for gen_ff
+// IDs from 45000 to 57000 are reserved for library
+#endif
+
+#endif//_WA_IPC_H_ \ No newline at end of file
diff --git a/Src/Winamp/wasabicfg.h b/Src/Winamp/wasabicfg.h
new file mode 100644
index 00000000..a1170a33
--- /dev/null
+++ b/Src/Winamp/wasabicfg.h
@@ -0,0 +1,3 @@
+#pragma once
+#include "buildType.h"
+#define WA5
diff --git a/Src/Winamp/whatsnew-5.0.txt b/Src/Winamp/whatsnew-5.0.txt
new file mode 100644
index 00000000..3eeb0ff9
--- /dev/null
+++ b/Src/Winamp/whatsnew-5.0.txt
@@ -0,0 +1,38 @@
+Winamp 5.0:
+* Support for classic Winamp 1.x/2.x/2.9x skins and Winamp 3 ("Modern") skins
+* Fancy new modern skin:
+ - Integrated video, AVS, and Milkdrop support
+ - Many built-in colorthemes
+* Same ol' classic skin for people who want the Winamp 2 feel
+* Vastly more powerful media library:
+ - Automatic background directory scanning options
+ - Customizable views and columns, graphical view editor
+ - Internet Radio (SHOUTcast) and TV listings
+ - Context-sensitive item info viewer
+* CD ripping support (AAC@2x in free version, MP3 at unlimited speeds in pro)
+* CD burning support (limited to 2x in free version)
+* Advanced title formatting logic for file types that support it
+* Huge AVS updates:
+ - New effects, bundled some popular 3rd party APEs
+ - A much better selection of default presets
+ - Experimental SMP support
+ - Full AVS preset subdirectory support
+ - Extensions and optimizations to the AVS evaluation library
+* Support for playback of AAC and VP6 in NSV files/streams
+* Global hotkey support
+* new Signal Processing Studio DSP plug-in
+* Options to disable plugin exception handling for developers
+* A ton of new plug-in API calls (SDK forthcoming)
+* fixed changing-systray options while minimized bug
+* new Winamp icon
+* added XP Manifest.xml to winamp.exe
+* made agent icon use configured winamp system tray icon
+* optimized winamp's load titles on demand logic, made faster
+* made winamp's internal submenu management more reliable
+* added skin font override preferences
+* added spacebar shows current playlist item in playlist editor
+* fixed manual playlist advance w/ repeat
+* made winamp's open directory recurse checkbox nicer looking
+* big prefs overhaul to make steve happy
+* huge thanks to Amir Szekely and the rest of the NSIS developers
+ for their help \ No newline at end of file
diff --git a/Src/Winamp/whatsnew.txt b/Src/Winamp/whatsnew.txt
new file mode 100644
index 00000000..4b97de3c
--- /dev/null
+++ b/Src/Winamp/whatsnew.txt
@@ -0,0 +1,2002 @@
+Winamp 5.24
+* Fixed: [in_midi] crash bug & potential security vulnerability
+
+Winamp 5.23
+* Improved: [gen_jumpex] jump-to-file speed improvements
+* Fixed: playlist saving with network share files
+* Fixed: Media Library preferences not loading in correct order
+* Fixed: main window not hilited when restoring from minimized state in classic skin.
+* Fixed: slow loading of playlists with URLs
+* Fixed: CD burning using third party input plugins
+* Fixed: classic skin winshade playlist time display
+* Fixed: [gen_ff] Wasabi XML font-related fixes from Martin Poehlmann
+* Fixed: [gen_ff] Map.getHeight() maki script function returning width instead
+* Fixed: [gen_ff] winshade global hotkeys broken w/ modern skins
+* Fixed: [gen_jumpex] 'Add to Queue' issues
+* Fixed: [gen_jumpex] NT4 incompatability
+* Fixed: [gen_jumpex] misc bug fixes
+* Fixed: [gen_ml] icon changes on drag+drop items
+* Fixed: [in_mp3] playback of AAC streams
+* Fixed: [in_mp4] seek bug when using right arrow key
+* Fixed: [in_wm] Playback restarts from beginning when editing tags of a currently playing .wma file
+* Fixed: [in_wm] protocol/extension reversed in config > filetype > edit
+* Fixed: [in_wm] 'Audio only' always checked for ASF/WMV in config
+* Fixed: [in_wm] seek bug when using right arrow key
+* Fixed: [ml_bookmarks] 'Edit Bookmarks' menu item not working when Media Library is hidden
+* Fixed: [ml_local] crash while rearranging media library views
+* Fixed: [ml_local] crash on close
+* Fixed: [ml_local] sort arrow reversed in some columns
+* Fixed: [ml_playlists] Import Playlists uses containing dir for title instead of filename
+* Fixed: [ml_playlists] No "Recurse" checkbox in Import Playlists From Folder
+* Fixed: [ml_playlists] Add Dir adds all filetypes (not just all-supported)
+* Fixed: [ml_playlists] rt-click enqueue not working & other issues
+* Fixed: [ml_playlists] Not saving playlists in some situations
+* Fixed: [ml_playlists] crash when loading badly formed WPL playlists
+* Fixed: [ml_playlists] drag&drop into playlist not adding to correct position
+* Fixed: [ml_playlists] root playlist screen not updating when adding new playlist
+* Fixed: [ml_playlists] reverting changes on send-to: playlist
+* Fixed: [ml_playlists] drag+drop m3u files broken
+* Fixed: [ml_pmp] Syncing duplicates finally fixed (thanks gordol)
+* Fixed: [ml_pmp] Removing items from a playlist not saving issue (thanks Nick)
+* Fixed: [ml_wire] some podcasts only display one item
+* Fixed: [pmp_ipod] Playlist sort now works again
+* Fixed: [out_ds] stop with fade (shift+v) issue
+* Updated: [in_cdda] CDDB 2.0.1.25
+
+Winamp 5.22
+* New: loading of additional playlist formats: ASX/WAX/WMX/WVX, WPL, B4S
+* New: [gen_ff] modern skin unicode support
+* New: [in_wm] burning of DRM protected files (if allowed by content provider)
+* New: [ml_pmp] transfer of playlists to portable devices
+* Improved: More informative CD burning status window
+* Improved: [gen_ff] modern skinning engine speed optimizations
+* Improved: [gen_jumpex] jump-to-file search response
+* Improved: [gen_tray] enhanced icon pack support plus more... (thanks DrO)
+* Improved: [in_wm] seeking improvements
+* Improved: [in_wm] gapless WMA support
+* Improved: [ml_nowplaying] Redesigned 'Now Playing' media library view
+ (it actually works now)
+* Improved: [pmp_ipod] Loading times for iPods reduced
+* Fixed: Winamp won't restore after being minimized with a dialog box open
+* Fixed: $abbr() title formatting lockup
+* Fixed: Add Folder adds tracks BEFORE the last track
+* Fixed: Clicking 'Next' in Fullscreen video OSD acts like clicking it twice
+* Fixed: Rating in pledit right-click context menu always shows "No Rating"
+* Fixed: Stop with fadeout (Shift+V) just stops playback, no fadeout
+* Fixed: CD burning bugs and crashes
+* Fixed: Delete key not working in Online Services or SC Wire search
+* Fixed: [gen_jumpex] handling of playlist with more than 65,536 files
+* Fixed: [gen_jumpex] 'on end of queue' fixed
+* Fixed: [gen_jumpex] modern skin pledit docked toolbar mode not remembered
+* Fixed: [gen_jumpex] ML size/position not remembered when switching from Classic to Modern and back to Classic skin
+* Fixed: [gen_jumpex] misc bug fixes
+* Fixed: [gen_ml] playlists root view slowness bug
+* Fixed: [gen_ml] Modern skin: Media Library > View (menu) > Devices
+* Fixed: [in_midi] corrupt header crash
+* Fixed: [in_mp4] metadata writing crash
+* Fixed: [in_mp4] seek bug when using right arrow key
+* Fixed: [in_mp3] MPEG-2 and MPEG-2.5 Layer 3 playback crash
+* Fixed: [in_mp3] Winamp crashes when trying to play any wrongly named .aac file
+* Fixed: [in_wave] WAV burning fix
+* Fixed: [in_wave] Locking files (wav's can't be renamed/deleted)
+* Fixed: [in_wm] lockup on wma with expired/unrenewable drm license
+* Fixed: [in_wm] out of sync audio/video on some WMV streams
+* Fixed: [in_vorbis] fullpath shown in playlist for tagless files with atf disabled
+* Fixed: [ml_pmp] Duplicates being synchronized
+* Fixed: [ml_pmp] Several crashes during transfers
+* Fixed: [out_ds] Can't select different Output Device with two active instances of out_ds
+* Fixed: [out_ds] incorrect enumeration of stereo outputs for two of same pro soundcard
+
+Winamp 5.21
+* New: [jnetlib] HTTP compression support
+* Improved: [installer] multi-user profile migration
+* Fixed: [ml_wire] memory leak
+* Fixed: [pmp_p4s] DRMclien.dll error
+* Fixed: [gen_ff] skin info display in preferences
+* Fixed: [in_mp3] Wordwrap disabled in Info Editor Comments field
+* Fixed: [in_wm] Minor bug fixes
+* Fixed: Keyboard shortcuts don't work from video window
+* Fixed: [in_vorbis] No Artist metadata in stream titles
+* Fixed: [in_dshow] floating point audio
+* Updated: Coding Technology AAC+ Decoder 7.2.5
+
+Winamp 5.2
+* New: [ml_pmp] Synchronize your Media Library with your portable media player
+ Compatible with iPod, Creative, and Microsoft Plays For Sure devices
+* New: [enc_aacplus] Coding Technologies aacPlus High Bitrate encoder available in Winamp Pro
+* New: [enc_aacplus] Coding Technologies aacPlus (HE-AAC) in MP4 container
+* New: [enc_aacplus] Coding Technologies LC-AAC encoder
+* New: [gen_ml] icons in treeview
+* New: [ml_online] Dynamic AJAX Internet Media Hub
+* New: [in_nsv] Using Coding Technologies AAC playback within NSV container
+* New: [in_mp3] gapless MP3 playback
+* New: [installer] multi-user profile options
+* New: [installer] remembers your previous installer settings
+* New: [in_wave] in_wave 3.0
+* New: right-to-left playlist display
+* Improved: new ATF functions and tags, including:
+ $repeat(x, count) - creates a string with x repeated count times
+ $lpad() - same as $pad, but adds padding to the left
+ $decode(...) - switch/case function. example: $decode($fileext(%filename%),MP3,MPEG-1 Layer 3,MP4,MPEG-4 Container,Other)
+ $IfStrEqual(string1,string2,result) - if string1 and string2 are equal, displays result. case insensitive
+ $IfStrEqual2(string1,string2,result,else) - if string1 and string2 are equal, displays result, otherwise displays else. case insensitive
+ %folder% - top level folder name of the file
+* Improved: Stereo beat visualization for modern skins
+* Improved: [gen_ff] new vis modes available to skinners
+* Improved: [gen_ml] CD drive info view (Rip & Burn)
+* Improved: [gen_tray] gen_tray v1.0 (thanks DrO)
+* Improved: [in_midi] provides metadata to media library
+* Improved: [in_mod] provides metadata to media library
+* Improved: [in_mp3] unicode id3 tags
+* Improved: [in_mp3] preliminary id3v2.4 support
+* Fixed: broken playlist sorting
+* Fixed: playlist problems with multi-line tags (e.g. %comment%)
+* Fixed: shuffle with only one song in playlist
+* Fixed: ghost seek slider appears if Winamp loses focus during seeking
+* Fixed: video options from video window right-click context menu
+* Fixed: playlist winshade international character support
+* Fixed: fullscreen video display international character support
+* Fixed: m3u playlist handling security vulnerability (thanks to NSFOCUS and Information Risk Management Plc)
+* Fixed: [enc_lame] bit reservoir
+* Fixed: [enc_lame] cutoff of last frame
+* Fixed: [gen_ff] regions on components don't work
+* Fixed: [gen_ff] playlist & video focus bug
+* Fixed: [gen_ff] playlist winshade memory leak
+* Fixed: [gen_ff] GDI Object leak with Current Skin prefs page
+* Fixed: [in_midi] not following winamp's title formatting options
+* Fixed: [in_midi] reset button blocks further access to config
+* Fixed: [in_mod] not following winamp's title formatting options
+* Fixed: [in_mp3] incorrect version identification (showed 5.18 in 5.12)
+* Fixed: [in_mp3] incorrect information shown for AAC+ files
+* Fixed: [in_mp3] reading incorrect id3 comment tag
+* Fixed: [in_mp3] sometimes failing to read last id3 frame
+* Fixed: [in_mp3] id3v2 album art loss when editing tags
+* Fixed: [in_mp4] loss of album art when modifying metadata
+* Fixed: [in_vorbis] not following winamp's title formatting options
+* Fixed: [in_vorbis] registry usage (now multi-user profile safe)
+* Fixed: [in_wave] 32bit floating point WAV playback distortion
+* Fixed: [in_wm] changes made with Attribute Editor not updating in ML/Playlist
+* Fixed: [vis_milk] missing files from distro (you can stop bugging us now, Rovastar :)
+* Fixed: [vis_milk] 100% cpu usage when paused
+* Updated: [gen_jumpex] DrO's Jump To File Extension 0.97
+* Updated: [enc_lame] LAME 3.97b2
+* Updated: [gen_ff] libpng 1.2.8
+* Updated: [gen_ff] FreeType 2.1.10
+* Updated: [enc_aacplus] Coding Technologies aacPlus encoder v7.2.0a
+
+Winamp 5.13
+* Fixed: [in_mp3] extremely critical security vulnerability
+
+Winamp 5.12
+* New: [in_wm] Windows Media Video support (with DRM)
+* New: [in_mp4] Support for HE-AAC MP4/M4A files
+* Improved: lots of minor plugin improvements
+* Improved: Visualization data calculations
+* Improved: Significantly less playlist memory usage
+* Improved: more multi-user improvements (almost there!)
+* Improved: [installer] setup options, saved settings, codec downloading
+* Improved: [gen_ff] optimized skinning engine
+* Improved: [out_disk] new features
+* Improved: [in_cdda] playback/ripping with sonic engine
+* Fixed: freezing when cancelling cd burn
+* Fixed: video scaling bug (with modern skin scaling < 100%)
+* Fixed: minor installer bugs
+* Fixed: freeze when loading classic skin with main window hidden
+* Fixed: Visualizations for 24bit and 32bit songs
+* Fixed: Advanced Title Formatting with Japanese, Chinese and Korean metadata (thanks mrym)
+* Fixed: [in_mp3] raw AAC VBR file seeking and bitrate reporting
+* Fixed: [in_mp4] unicode metadata writing
+* Fixed: [in_wm/in_dshow] mms:// streaming video playback
+* Fixed: [in_cdda] audio cd bitrate display
+* Fixed: [in_cdda] Sonic engine on 64bit windows (thanks STanger)
+* Fixed: lots of small bugs ...
+* Updated: Sonic CD Engine 2.2.50
+* Updated: libmp4v2 1.4.1
+* Updated: Coding Technology AAC+ Decoder 7.2.0
+
+Winamp 5.111
+* Fixed: works with internet explorer 3.0 again (old win95/nt3.51)
+* Fixed: Auto-Preset EQ crash (non-mp3 files)
+* Fixed: $upper, $caps, $caps2 crash with foreign characters
+* Fixed: Station Info crash (with http filtering program)
+* Fixed: empty playlist bugs
+* Fixed: [in_mp3] proxy ignored when ‘only port 80’ was checked
+* Fixed: [in_midi] lyrics not working
+
+Winamp 5.11
+* Updated: LAME 3.96.1
+* Fixed: playlist focus issue after adding files to playlist
+* Fixed: crash on multichannel songs with EQ enabled
+* Fixed: internet connection detection not working when set to "dial-up"
+* Fixed: manual playlist advance with winamp videos
+* Fixed: EQ text display glitch
+* Fixed: video not filling up video window
+* Fixed: black bars in fullscreen video
+* Fixed: [gen_ml] crash with no write access
+* Fixed: [gen_ml] CDDB Dialog Media Library drawing glitch
+* Fixed: [in_dshow] seeking on files with no video or no audio
+* Fixed: [in_cdda] aspi ripping crash
+* Fixed: [ml_wire] "my music" folder creation
+* Fixed: [ml_wire] Podcasts with dates before 1970 handled properly
+* Fixed: [ml_wire] Downloading of podcasts with parameters in URL
+* Fixed: [out_ds] fade-on-seek settings
+* Fixed: [in_wm] pause glitch
+* Fixed: [in_mp4] view-file-info filename not scrolling
+* Coming Soon: Multi-user profile support (preliminary support enabled)
+
+Winamp 5.1 Surround Edition
+* New: CodingTechnologies AACPlus encoder!
+ The MP3 Killer!
+ Awesome at low bitrates too!
+* New: Grand Prize Winner of the Internet Surround Music Project!
+ KAJE - Hey Buddy (featuring Afrika Bambaataa)
+* New: SHOUTcast Wire - A Media RSS Browser and Subscription Service
+* New: Predixis Smart Playlist Generator
+ (Mix your tracks based on what they sound like!)
+* New: AOL Radio featuring (((XM))) Free Sampler!
+* New: CD Ripping now available at 8x in free version!
+* New: Microsoft WMA encoder
+* New: Over 200 new Milkdrop presets!
+* Update: in_vorbis now returns bitrate in getextendedfileinfo
+* Fixed: WMA stuttery playback
+* Fixed: out_ds copy button on status tab now works all the time
+* Fixed: Much improved ripping and playback with Sonic engine
+* Fixed: Video window now resizable regardless of Sidecar
+* Fixed: Length of long mp3's now reported properly
+* Fixed: Silent install switch now works properly
+* Fixed: Simultaneous CD Playback and Ripping
+
+Winamp 5.094
+* New: in_wm now handles bitrate and length extended info
+* New: New random number generation for playlist shuffle
+* Fixed: Security vulnernability in id3v2 tags (thanks to LSS Security)
+* Fixed: Winamp now shuffles playlists larger than 32,768 songs
+* Fixed: Fade on start now behaves properly
+* Fixed: separate directsound settings with multiple instances
+* Fixed: Winamp now supports adding URLs longer than 260 characters.
+* Fixed: Editing files created in iTunes no longer causes corruption.
+* Fixed: Length of long mp3's now reported properly
+* Fixed: gen_jumpex no longer crashes when DEP is enabled
+* Fixed: Sort selections in media library are now remembered.
+* Fixed: Album names with non-alphanumeric characters behave better
+* Fixed: Fixed intermittent crash on seeking for some users
+* Updated: libmp4v2.dll
+
+
+Winamp 5.093
+* Fixed: OSD stays onscreen in DirectDraw Mode
+* Fixed: Fullscreen video OSD doesn't reappear after using Pause
+* Fixed: ML Playlist > Select all (no delete key)
+* Fixed: Vis data for in_mod (and possibly other input plugins)
+* Fixed: msvcp60.dll now linked static
+* Fixed: Small intermittent bugs in gen_ml and gen_ff
+* Fixed: Greater than 2 channel vis data now works
+* Fixed: Media Library problems with parentheses/brackets in artist or album names
+* Fixed: Ripping CDs with trailing ellipses (...) in artist or album name
+* Fixed: Better video flipping for YUV colorspace videos
+* Fixed: Saved mute settings with modern skin.
+* Fixed: Drag and Drop from external applications
+* Fixed: Open File Dialog always-on-top
+* Fixed: Crossfade on start
+* Fixed: Freeze when switching audio tracks in a multi-audio stream.
+* Fixed: Fullscreen switching with scaled video window.
+* Update: Dynamic Online Media can now alert users to live events(can disable).
+
+Winamp 5.092
+* New: DRM WMA Playback supports out_wave
+* New: Non-DRM WMA Playback allows any output plugin
+* New: Community Picks AVS Preset Pack
+* New: Deletes in the Media Library now move files to the Recycle Bin
+* New: NSV Subtitles can be disabled on the fly
+* Fixed: Long delay and high cpu on exit with many items in playlist
+* Fixed: gen_ml shutdown bug
+* Fixed: Easy Move of video window back to normal
+* Fixed: Pause in WMA playback memory leak
+* Fixed: Multi-monitor full screen video
+* Fixed: Drag and Drop in playlist editor
+* Fixed: Drag and Drop on Winamp
+* Fixed: Now Playing update on song change
+* Fixed: Media Library/Windows Media scanning errors
+* Fixed: Stay in fullscreen/Config mismatch
+* Fixed: Ctrl-B Crash
+* Fixed: Authentication for OGG/Vorbis streams
+* Fixed: Drag and Drop strange behavior in open file dialogs
+* Fixed: Stuttering WMA On Start and Seek
+* Fixed: NSV Video stall during buffering
+* Fixed: Autosize of video to be accurate to the Video size not snap size
+* Fixed: Short NSV Clips audio cutout
+* Update: Online Media tree is now dynamic (Checking can now be disabled)
+* Update: Sonic Install/Config flag mismatch
+* Update: CD Ripping/Burning Library (possible cause of msvcrt.dll errors)
+
+Winamp 5.08:
+* Updated Windows Media DRM License
+* Fixed playFile function in gen_ff.dll (Allows Modern skins to launch playback)
+* Created new eMusic bundles
+* Critical Security bug fixed in in_mp4.dll and enc_mp4.dll and libmp4v2.dll
+* HTTP Seeking corrected for webservers that refuse to return Accept-Range
+* Critical Security buffer overflow fixed in in_cdda.dll
+
+Winamp 5.07:
+* Critical Security bug fixed in in_cdda.dll and .m3u handler
+* in_mp3 & in_nsv should work on Win95 again
+* Proxy settings work again
+* Installer fixed so that read_file.dll is installed always with mod support
+* Version number should be properly reported by IPC_GETVERSION for this build
+
+Winamp 5.06:
+* Fixed crashbug when clearing the playlist and then right clicking on the songticker
+* Security bug fixes
+* Lots of small bugfixes
+* JTFE v0.96ff
+
+Winamp 5.05:
+* Security bug fix
+* Fix for upside down videos through DirectShow
+* JTFE v0.96c
+* Added prompt when loading a skin for the first time
+
+Winamp 5.04a:
+* fixed drag & drop on docked toolbar at startup
+* modern skin updates :
+ fixed lockup when exiting while in runModal
+
+Winamp 5.04:
+* update JTFE
+* Added Coding Technologies' AACPlus decoder
+* fixed deletion of temporary generated WAV files after a burning process on some
+ computers
+* fixed typo in some context menu shortcuts
+* fixed slowness IPC bug caused by gen_hotkeys
+* added "clear" button in internet radio/tv views
+* added screenshots of classic/modern mode in installer
+* fixed MP3 bitrate calculation (in_mp3 was reporting incorrect lengths on some MP3s)
+* fixed incorrect length reporting on long WMA files
+* better fix for pledit/video windows showing up at startup when minimized
+* fixed db text bug when moving EQ sliders
+* upgraded MP3 encoding to LAME v3.96
+* fixed crash in WMA playback when using WMA v8 codecs
+* updated default streaming values in in_nsv
+* added Winamp.com Audio&Video views in the Media Library
+* fixed tiny memory leak in in_cdda
+* added right click context menu on "Now Playing" item in Media Library
+* added script/ActiveX disabling for Media Library's minibrowser (on by default)
+* fixed memory leak on MP3 files with messed up ID3v2 tags
+* fixed visualization when playing CD tracks
+* fixed proxy user:pass@server:port string getting cut when playing Shoutcast streams
+* made in_dshow not to handle mms:// streams ending with .wma
+* fixed %tracknumber% tag for CD tracks
+* fixed some crash bugs in in_mp4
+* fixed playlist generation when ripping full CDs
+* added "import playlist from folder" in Media Library
+* updated Media Library preferences screens
+* added new SPS presets from Cockos, Inc. (pitch shifters, etc...)
+* added basic streaming (download) support for M4A/MP4 HTTP streams
+* added monitoring of fullscreen apps, disables always on top temporarilly
+* added IPC_IS_WNDSHADE
+* added gen_ml rating ipcs
+* added ratings from playlist context menu (acts on selected entries)
+* added ratings from song ticker context menu (acts on current track)
+* added rating hotkeys in gen_hotkey
+* fixed saving read-only playlists
+* fixed double separator lines in gen_ml id3less item context menu
+* fixed refresh of view losing query after removing dead files & background scan
+* added escaping of ", ', [ and ] in ml queries : uses %HH where HH is the hex char code (uses %% for '%')
+* added sdk support for multiple audio/video tracks in video input plugins (see wa_ipc.h for ITrackSelector class)
+* added multiple audio avi support (right click video window, select "Audio Tracks")
+* fixed multimonitor problem when toggling a windowshade on one monitor while playing a fullscreen video on the other
+* added ML_IPC_EDITQUERY and ML_IPC_EDITVIEW
+* fixed pledit drawing bug under winxp/cleartype
+* fixed crash in id3 reading of zero byte files
+* fixed crash in sps when exiting winamp before closing the open/save dialog
+* added IPC_PUSH_DISABLE_EXIT, IPC_POP_DISABLE_EXIT and IPC_IS_EXIT_ENABLED
+* fixed gen_ml crash when inserting item with length -1
+* made gen_ml much more resistant to databases that have been corrupted
+* fixed ml nuke
+* added disabling of "keep on screen" option when going into a different resolution because of a
+ fullscreen application (ie: a game)
+* made ui:preferences global hotkey open the prefs to the previously opened page
+* fixed a few preferences cosmetic 'bugs'
+* modern skin updates :
+ - fixed windowshade repeat-track button state
+ - fixed scaling docked toolbars
+ - fixed 5.03 assert on deletion of newGroupAsLayout()
+ - fixed floating video windows coordinates dropping to 0,0
+ - fixed auto opaque when layouts are loaded already docked as toolbars
+ - fixed fadein/fadeout not used on notification window when linking all normal windows'
+ alpha
+ - fixed docked toolbars moving when some other window docked to them switches to an
+ alternative layout
+ - fixed silent crash on shutdown when pledit is docked as toolbar and gen_ml unloads
+ before gen_ff (would not remember settings from session to session)
+ - fixed snap points
+ - fixed click on +12db / 0db / -12db
+ - optimized text scrolling (a lot)
+ - fixed content of pledit not painting in some instances
+ - gen_hotkeys are now routed thru System.onKeyDown(name), where name is the name of
+ the hotkey prefixed by "HOTKEY: " (ie: "HOTKEY: Playback: Play"). You may issue a
+ complete; statement to prevent gen_hotkey from handling the hotkey
+ - fixed horizontal resize of main window with video/vis drawer closed and config drawer open
+ - added auto-height for next drawer opening when resizing main window with video/vis drawer closed,
+ this avoids having an unreasonably tall drawer open if you just watched a video in a big window and
+ then only resized the player back to its horizontal minimum after the video had closed. auto-height
+ resets to 4:3 proportions
+ - fixed docking bug when using snapadjustleft
+ - fixed buggy calculation of time display default width conflicting with right text alignment
+ - fixed windows moving after changing screen resolution
+ - fixed rare always on top desync with classic skins
+
+Winamp 5.03:
+* made MP4 AAC the new default ripping encoder
+* fixed a crash bug when playing some AVI files in in_dshow
+* added multimedia keyboard keys in global hotkeys default configuration
+* added "Manual playlist advance" in Repeat button popup menu in Classic mode
+* improvements in MP3 encoder configuration (added --alt-preset standard, etc...)
+* made the tabs in the preferences XP correctly themed under Windows XP
+* revamped the Media Library preferences a bit
+* new experimental WMA9 input plugin
+* gen_jumpex updates from DrO
+* added "Nuke library" action in Media Library
+* more upside down videos fixes
+* fixed crash if a plugin generated a pledit wm_windowposchanged on shutdown
+* fixed crash exploit in in_mod (thanks Peter Winter-Smith)
+* fixed various crashes in in_midi when playing invalid files
+* made in_midi store its settings in winamp.ini instead of the registry
+* fixed error during installation on computers with chinese/oriental regional settings
+* removed AOD from installer
+* added Shift-R to toggle manual playlist advance
+* updated VP6 video decoder to latest VP6.2 code
+* fixed crash when launching winamp with very long filenames from explorer
+* made registration dialog to appear in Explorer's taskbar when installing pro version
+* fixed pledit/video windows showing up at startup when minimized
+* modern skins updates :
+ - winamp modern skin now uses a 3 state repeat button: no repeat/repeat all/repeat track
+ - added appplication desktop toolbars capabilities for layouts, add
+ appbar="left|top|right|bottom" to use them
+ - upped maki binary version, improved stack protection
+ - current skin version number is 1.2 (this should not change for a long while now, and
+ of course we continue to support 0.8 to 1.1)
+ - (very) limited maki debugger (for now you can bring it up with invokeDebugger(); in a
+ script then use 'x' to continue and 'i' to trace into)
+ - fixed obscure capture problem with dragging windows
+ - fixed rectrgn being forced to 1 in xml xuiobject buttons that are originally imageless
+ - fixed hilited state not on after clicking on buttons while the mouse stays in area
+ - fixed scripted onEnterArea/onLeaveArea not being always correctly called while mouse
+ button stays down
+ - fixed getToken being passed NULL throwing guru
+ - fixed clipping of painting within the background's region of a group rather than
+ within the composed region (the one you can change with sysregion)
+ - fixed image cache problem when using the same bitmap as a map and a button image
+ parameter
+
+Winamp 5.02:
+* added a couple of gen_ml APIs
+* fixed gen_ml radio/tv cache clearing after viewing prefs bug
+* made gen_ml radio/tv keep old data when updating fails, made it not update when no
+ internet is available
+* made gen_ml support some new quicksearch syntaxes: "* beck radiohead"
+ will list all things matching beck OR radiohead, and:
+ radiohead "<lastplay > [3 days ago]>" will show all things matching radiohead
+ played in the last 3 days...
+* gen_ml option for any/all guess modes
+* made SPS support 24 bit samples
+* added priority setting for CD ripping
+* made CD ripping only support one rip at at time
+* added send to -> add to library for playlist (and other) send to menus.
+* better media library audio view support for no artist/no album
+* fixed enter after info box and popup menus in library
+* moved litestep options to be in classic skin prefs
+* fixed playlist editor classic redraw bug, made playlist handle mousewheel scrolling while
+ moving items better.
+* made "EXE" filetype extension non registerable :)
+* cleaned up "disable screensaver when video is playing" option
+* latest SDKs available (AVS, Media library, new Winamp IPC calls, etc...)
+* upgraded to Gracenote CDDB v2 DLLs
+* improvements in gen_hotkeys
+* upgraded MP3 encoding to LAME v3.95.1
+* out_ds now uses winamp.ini instead of registry for settings
+* new fix for upside down videos in in_dshow
+* added OGM as supported extension in in_dshow
+* modern skins updates :
+ - optimized region a bit
+ - fixed handling of global alpha for unparented layouts
+ - fixed tiny bug in keypress flow
+ - fixed potential layer capture cancellation issue
+ - fixed crash when quickly alternating alt+g and alt+w
+ - fixed player not coming up to front when playing a video via external URL click
+ - fixed assertion when arial.ttf (or whatever fallback font has been set) is not present in the font directory
+ - fixed faulty skin font unmapping sometimes conflicting with fallback to os default gui font
+ - added date and version functions to maki
+ - added added timerhours="1" to text object to show 1:00:00 instead of 60:00
+ - added timeroffstyle 3 and 4 to text object to display "0:00:00" and " : : "
+ - upped skin version to 1.1 - you MUST use 1.1 if you recompile your scripts
+ - updated maki compiler (http://bluemars.org/maki) :
+ - added stack protection to maki binaries - upped the binaries version header
+ - added self version check in maki binaries
+ - non-existing (future) maki functions will not crash the maki runtime anymore, YAY
+ - fixed unknown maki functions return values
+ - fixed winamp appearing on secondary taskbar with ultramon regardless of true position
+ - fixed extraneous invalidations
+* new extended jump file dialog (thanks to Darren Owen)
+* added basic MP4 AAC encoding/decoding (thanks to Menno Bakker for the help)
+* fixed unicode metadata in in_vorbis
+* fixed crash in installer code
+* removed generation of "badframes.stt" files in VP6 decoder
+* <3 farewell Justin <3
+
+Winamp 5.01:
+* fixed gen_ml selection bug
+* added gen_ml option for no guessing at all
+* made AVS and SPS support loop() in user code
+* made AVS support megabuf() in user code
+* made pro installer not prompt for regkey if already valid
+* improved font directory retrieval in gen_ff
+* added content rating system in Internet TV's listing
+* added bandwidth usage statistic in Internet Radio/TV listings
+* made media library guess from filename only when NO metadata found
+* added seperate recent items tracking options for files/streams
+* made installer better handle installing wa5 directly over wa3.
+* added milkdrop docs to installer
+* made uninstaller not remove winamp directory if not empty (user is
+ now required to do so manually to avoid people going "oops")
+* made installer check sonic px.dll versions and prompt for reboot
+ accordingly
+* fixed nsv metadata querying bugs
+* fixed gen_ml guessing bugs for files with metadata that are not in DB
+
+Winamp 5.0:
+* fixed http playlist retrieval issues
+* fixed classic skin refresh bug in gen_ff
+* fixed editing query while radio refreshing in gen_ml
+* modern skin - fixed version detection for skins that use wasabixml tag, fixed unclickable "old skin" msgbox
+* fixed guessing bug in gen_ml
+* made agent add icon after explorer.exe crash
+* fixed AVS crash on win98 bug
+* fixed in_nsv dsp plugin support
+* fixed gen_ml -recurse bug
+* new Signal Processing Studio DSP plug-in
+* fixed out_ds buffer size using crossfade time when crossfade is off
+
+Winamp 5.0rc666:
+* fixed potential crashbug in ml
+* avs sscope updates, fixes
+* modern skins : fixed SHGetSpecialFolderPath on old OSes
+
+Winamp 5.0rc11:
+* added colorthemes submenu to options menu
+* fixed AVS bugs, added new texer2 APE
+* fixed ML genre combobox low screenres bug
+
+Winamp 5.0rc10:
+* modern skin updates
+ - fixed coming back from windowshade closes video drawer
+ - fixed user settings path assert
+ - added 6 color themes (coagulated, peachy, bricks set, rosemary, blueberry and cream, qwayke)
+* added media library plugins configuration, support for type column
+* latest VP5 decoder, including NSV/VP6 decoder
+* disabled hotkeys when hotkeys configuration is focused
+* AVS: support getkbmouse() from script. woot.
+* AVS: support new text features, including $(title), $(reg00), $(playpos), $(playlen)
+* AVS: added (optional) eval code for effect lists
+* AVS: experimental SMP support
+* AVS: fixed a alpha clamping bug in dmove
+* AVS: eval code stats in debug window
+* AVS: memory footprint reduction (framebuffer freeing)
+* AVS: eval code optimizations, much smaller and faster code (woot)
+
+Winamp 5.0rc9:
+* fixed how some very broken databases would set the db recovery into an infinite loop
+* fixed info for wa3 skins
+* fixed winamp3 upgrading for later builds
+* fixed sendto ml playlist when it is open
+
+Winamp 5.0rc8:
+* modern skin updates
+ - fixed config menu radiobuttons turning off when clicked again
+ - fixed unreadable selected list item text color in 2 gamma groups
+ - fixed theme list using slightly different colors than ml lists
+ - fixed taskbar move syscommand bringing up wa2 main window
+* updated avs, faster evallib. makes eval heavy presets superfaster.
+* made cd ripping unlock drive and cleanup on exit in middle of rip
+
+Winamp 5.0rc7:
+* fixed metrics dialog parenting
+* fixed avs Nbuffer stuff, exposed Nbuffers via API (woo hope no more crashy)
+* fixed avs memory leak
+
+Winamp 5.0rc6:
+* fixed gen_ml view restoring when "do not load library at startup" checked
+* fixed another avs dmove bug
+
+Winamp 5.0rc5:
+* made reginfo stored in the registry instead of winamp.ini
+* added Ctrl+H to keyboard shortcut list in about
+
+Winamp 5.0rc4:
+* fixed drag&drop to main window when AVS is docked
+* more advanced title logic tweaks
+* fixed error in keyboard shortcuts list in about box
+
+Winamp 5.0rc3:
+* updated hotkeys to be tabable
+* updated advanced title logic to fix a few issues
+* fixed issue when modern skin or gen_ff not found
+* fixed modern skin about box when in classic skins]
+* new AOD with good uninstall supprot
+
+Winamp 5.0rc2:
+* fixed playlist editor status bug
+* fixed seh options not being saved
+* made installer check for gen_peercast and prompt user
+
+Winamp 5.0rc1
+* updated credits
+* updated to newer NSIS
+* made gen_hotkeys, gen_ml, and gen_ff all use msg registration api to avoid msg collisions
+* updated installer to prompt for reboot in certain instances on < win2k
+* fixed typo in installer
+* modern skin updates
+ - fixed options/skins menu issue
+ - changed some colorthemes names
+ - fixed lack of shift/ctrl + eject
+ - fixed shutdown problem with text objects
+
+Winamp 5.0rc0 11/16/03
+* fixed crash when subtitles but no video
+* added SEH options to avs and winamp for plug-ins
+* fixed bug in gracenote TUID and "Now Playing" tab
+* added CD locking when ripping
+* christophe optimized some in_dshow stuff (not sure if he wanted this shit in here, heh)
+* gen_ml recent items limiting fix
+* gen_ml info viewer fixes
+* SHUT YOUR MOUTH: http://www.firehose.net/~deadbeef/media/music/031115-shutyourmouth.mp3
+* modern skin updates
+ - final skin drop
+ - fixed player taking focus when notifier goes away (again, yeah, i just forgot to check it in :-))
+ - fixed resizing / snapadjust issues opening the drawer without showing its content (hole in player) in some cases
+ - disabled notifier fade sliders when running on w95/98
+ - fixed component editwnd colors (colortheme editor)
+ - fixed shade songticker alternate font color not matching bitmap font color group
+ - fixed lack of shift/ctrl + next/play/stop/prev
+ - fixed system.floattostring ignoring its ndigits param
+ - fixed potential crash in text widgets that change display param dynamically
+ - fixed locked windows going offscreen (like nonstep avs) made then ignore offscreen since they are locked to a layout that checks its own position
+ - added nooffscreencheck="1" for layouts in case offscreen check needs to be disabled for a window
+ - fixed assert in region
+ - fixed crash color extraction from undefined container
+ - fixed crash when not specifying a band parameter to an eqband object
+ - fixed buttons onleavearea detection with nonstandard scales
+ - fixed notifier not showing minimized when "show in windowshade and when minimized" is on
+ - fixed freeform dropdownlists not closing
+ - fixed crash when a window is destroyed while moving all windows docked
+ - fixed system.playfile (base dir changed, has to be relative to skin in wa5, so filename is tweaked if it starts with "skin\nameofskin")
+
+
+Winamp 5.0 beta 5 11/14/03
+* modern skin updates
+ - fixed mousewheel in pledit not responding after context menu popped on frame
+ - fixed mousewheel controlling volume when scrolling in now playing ml pane
+ - fixed mousewheel controlling volume after clicking on ml titlebar
+ - fixed doublesize menu item not disabled when not using scale locks
+ - fixed potential crash in colortheme management
+ - fixed player getting focus when notifier closes, added nofocusonclose param for containers
+ - fixed loading skins that are packaged wrong, with the skin in a subdirectory in the wal
+* fixed mouse cursor on popup menus
+* updated AVS presets/APEs to good final ones
+* updated gen_hotkeys labeling
+
+Winamp 5.0beta4:
+* modern skin updates:
+ - new skin drop
+ - fixed going from opaque on hover to opaque on focus disables autoopacity
+ - fixed how the arrow icon on the drawer would not change to reflect the direction the drawer will open
+ - fixed notifier not setting winamp to the foreground after restoring it when clicked (added System.activateApplication())
+ - fixed closing player with maximize on, now restarts with maximize on too
+ - fixed drawer remembering opened drawer size when maximized upon startup
+ - fixed closing drawer when maximize on, now drawer keeps maximize state when closed til manual resize and no longer loses old wnd size, will open to maximize height
+ - fixed opening config drawer while being maximized losing maximized state and/or saving maximized height, now auto adjusts size to match available space (added System.onSnapAdjustChanged())
+ - fixed auto restore on video start if maximized was entered when video wasn't playing (which kinda ruined the point, heh)
+ - fixed layout not saving its position when resized from script (ie: clicking maximize button) and reloading to the old pos
+ - fixed video overlay repositionning lagging when moving main window from another window (ie, ctrl+shift+move another window)
+ - fixed cancellation of drawer animation when using fixed alpha
+ - fixed saving unlinked auto opacity setting
+ - fixed flickers, paintings slowdowns and leftovers when hosting a skinned window inside the preferences
+ - fixed freetype using OS dpi instead of fixed 96 dpi like it was supposed to
+ - fixed skins using gradient, polygon, osedge and solid color generated images
+ - fixed crash in system.eject() and system.playfile()
+ - fixed "component is missing" in a bunch of skins
+ - fixed skin crashes due to scriptcore object not found, added fake scriptcore, does nothing (sorry, single core...)
+ - fixed crash when switching to skins that do not define the window background color and doesn't lets us extrapolate from a constructed window
+ - fixed custom opacity using window's opacity as a starting point (and reseting to it on cancel) when opacity is linked
+ - fixed invisible window when loading desktopalpha skin with global transparency on
+ - made jpgloading external
+ - fixed ctrl+f4 on main window or on pure wasabi windows (with no pl/ml/video, etc, ie: colorthemes) bringing up wa2 window
+ - fixed notifier "disable in fullscreen"
+ - fixed 0db/-12db not always working
+ - fixed eq showing last modern skin eq settings after going back to classic and changing them
+ - fixed mmd3 getting chopped off
+ - fixed skins getting trapped into a infinite loop because the eq value they set would come back slightly off due to 4 bits of precision lost between wa3 & wa5 eq range,
+ and that would try again and again to set the value based on comparision. made it so that this gap is checked for and if value matches, we send the last hiprecision value in the callback
+ - fixed equalizer menu entry being checked after closing config drawer without animation
+ - fixed blank notifier when linked autoopacity on
+ - fixed switching desktopalpha on a window that previously had forced transparency flag
+ - fixed clicking eq button on windowshade not repainting drawer when transparency on and eq wasn't the previously selected tab in config drawer and drawer animation is off (phew!)
+* updated a lot of little menu shit
+* made better handling of no media in library
+* renamed a lot of directories to folders, library to media library.
+* disabled drag&drop moving of tree items in media library for other than playlists/views
+* made sonic logo in burning link to sonic (well, almost)
+* made video view have better column defaults
+* fixed changing-systray options while minimized bug
+* added simple view editor to library (woot), added support for X:XX times, and a few new operators to querylang
+* switched Gracenote submit mode from test to normal
+* new Winamp icon
+* cleaned up query builder, made time editor external to it so that the simple view editor can use it too
+* changed user-agent versions
+* improved library length retrieval for legacy plugins
+* fixed library adding files to directory list
+* updated OLE drag&drop logic to fix library (might have broken other things, but I sure hope not)
+* added XP Manifest.xml to winamp.exe
+* fixed a channelshift bug in AVS, and made AVS support nifty script help dialogs for APEs
+* made ctrl+b, shift+b, shift+z work, added some menu items for some of them.
+* made F1 open help, added help menu item to main menu, made help launch browser
+* skinned combo boxes in Media Library, made radio/tv resizing behavior better (hides comboboxes when small)
+* made agent icon use configured winamp system tray icon
+* fixed sendto burner status updates
+* made agent use the new icon
+* fixed firsttime CD lookup bug
+* optimized winamp's load titles on demand logic, made faster
+* made winamp prompt before exit if ripping a CD
+* made config saving after prefs window closing deferred for better ui response
+* improved view editor advanced builder
+* fixed manifest
+* made ctrl+f1 do about box
+* made winamp's internal submenu management more reliable
+* made installer support winamp3 upgrading/skin migration
+* out_ds no longer changes buffer size when changing crossfading in modern skin, uses max(crossfadetime, buffersize) instead
+
+Winamp 5.0beta4 11/10/03:
+* modern skin updates:
+ - fixed paint problems when resizing media library up with opacity < 100%
+ - fixed flicker in media library list headers when scrolling horiztonally with opacity < 100%
+ - fixed potential crash if skin switched many many times
+ - gave a better look to gen_ff's about box, made it use wasabi for ttf & script
+ - delayed cancellation of forced transparency off (ie, video) by one second to avoid flickering if we're merely switching to a safe transparency mode for a fraction of a second
+ - gave log scale to opaque on hover sliders
+ - added System.onShowNotification hooked up to IPC_SHOW_NOTIFICATION so that skins can implement their notifier however they like
+ - fixed bitrate/samplerate/channels display sometimes going to 0
+ - added System.getSongInfoText()
+ - made skin config menu do a real crossfade between pages
+ - made skin config menu scroll entire pages of menu items rather than use thinger-like click-n-wait-n-release
+ - fixed crash when drawing very big truetype fonts in very small spaces
+ - fixed freetype font padding
+ - fixed rare region problem when offset(x,y) would do nothing
+ - separated default/fallback font from ttf override font
+ - added allowmaping="0" to prevent a font from being overriden (ie, the font uses special symbols that are necessary for your design)
+ - added auto 100% opacity on focus
+ - added font mapper to map any specific font (even a bitmap skin font) to any other specific TTF font
+ - fixed tooltips left/right padding
+ - added skin info tab in preferences, for skinners to put an about box or preference widgets. when no group is defined,
+ we print the data from the skininfo block.
+ note: to put a group there, just have a <groupdef id="skin.about.group"/>, the group should be nicely resizable
+ to accomodate various dialog size corrections for OS' dpi setting.
+ - added display="VID_Info" for text objects to show the same video info string as in classic mode
+ - fixed tooltips stealing focus in some rare remaining cases
+ - grayed out opacity settings for win95/98
+* added bitrate & file size columns to library (you may need to rescan your directories for this info)
+* added IPC_SHOW_NOTIFICATION for plugins to ask to show the notification, returns 1 if the skin implements it, 0 if not
+* added "show notification" global hotkey
+
+
+Winamp 5.0beta3 11/07/03:
+* modern skin updates :
+ - new skin drop
+ - fixed winamp3 skins windowshade not being used :
+ - prevented use of autoclose="1" in < 1.0 skins (wasn't doing anything in 0.8 but breaks windowshades if used in 1.0)
+ - added autoavailable="0" to drawer's wndholder params (should _not_ be used in floating component windows unless you know what you are doing)
+ - fixed maddoubleclicks on switch to vis/video spawning undocked wnd
+ - fixed vertical componentbucket sizes stuff, added functions to use as custom bucket
+ - fixed freetype wrapped text draw
+ - removed wa2 skinned cursors in freeform mode
+ - removed some wa2 drawing in freeform mode for speed and clarity
+ - fixed window position being forgotten when fonts dpi is not 96 (thx dougieha!)
+ - added leftpadding & rightpadding params for text objects
+ - added auto-100% opacity option, monitors mouse hovering a layout and brings it temporarilly back to fully opaque
+ - fixed multimonitor tooltips
+ - added multimonitor compliant offscreen detection, brings back to main screen if window is lost, ignored if docked to main window
+ - added metadata access for scripts (only to currently playing item)
+ - made color themes auto update to new groups in default theme
+ - fixed unwanted window activations
+ - fixed region optimizations
+ - made grid object build its region (finally)
+ - added container.getCurLayout(), container.close()
+ - added noparent param for layouts (excludes from the minimize/restore window group)
+ - added forcealpha param for layouts to prevent screen burps when changing often transparency (keeps layered flag if alpha=255)
+ - added layout.getDesktopalpha(), layout.istransparencysafe()
+ - added system.isminimized(), system.minimize(), system.restore();
+ - added system.getplaylistlength(), system.getplaylistindex();
+ - fixed layout.setalpha()
+ - fixed changing display param on text objects after init
+ - made random button toggle random instead of switching to a random preset, changed avs & milkdrop accordingly
+ - added submenu to views in all 3 playlists popup menus
+ - fixed keyboard shortcuts not being redirected to winamp in some circumstances (ie, titlebar click in library)
+ - fixed keyboard cancelling capture when dragging (ie, ctrl+alt+dragawindow)
+ - newer skin drop! with new config menu and crossfader
+ - fixed isDesktopAlphaSafe() crashing in w98 (grrr) and isTransparencySafe not taking everything into account, fixes notifier in win98
+ - fixed onplay being called instead of onresume in script
+ - added notification of pause / resume
+ - fixed double click on songtitle popping a non-responding dialog box
+ - fixed double click in songtitle not cancelling text grab
+ - added fullscreen flag for vis to send to winamp so that script can query if something (video or vis) is fullscreen, modified avs & milkdrop accordingly
+ - linked auto100% opacity when layouts opacity is linked
+ - added link all windows opacity (and auto100%) & scale, added custom opacity dialog
+ - made auto100% hold time configurable
+ - made another mode where scale lock is just ignored, and everything is locked
+ - fixed notifier being in the menu (added nomenu param to containers)
+ - fixed forced-auto100%-opacity on window request (ie, video/milkdrop)
+ - fixed docking and moving the notifier leading to crash
+ - fixed opening scale menu in notifier and clicking ok when notifier is gone crashb
+ - added distance to window for auto100%
+ - added configurability of fadein, hold, fadeout time for auto100%
+ - disabled video/vis drawer when not in 100% opacity for microsoftish reasons
+ - added Layout.isLayoutAnimationSafe() for scripts to do the same
+ - made font renderer svc load early, fixes a crash when using <truetypefont /> in gen_ff's system xml
+ - added detection of hover on winamp's dialogs & menus for auto100
+ - fixed (00:00) in title when playing streams
+* added user-definable global hotkeys (gen_hotkeys)
+* added font override combo for pledit
+* added "recent items" view to media library (independent of main library data -- tracks files, streams, etc)
+* added column customization in library (right click on columns header)
+* added comment, play count, last played, last updated, and ratings columns
+* added ratings setting context menu in media view
+* made the library detect alt+3 tag changes from within winamp and keep DB up to date
+* added query editor, whoohoo
+* added option to use pledit font in trees and views, then justin fixed it ;)
+* updated to new sonic SDK
+* fixed mini info viewer bugs
+* made winamp use filename guesswork even when library isn't open for script access and title
+ formatting (of course, only if no metadata is in the file)
+* made library info viewer have meaningful info on artist/album clicks
+* made library never add .cda files
+* created general API so people can use the sendto menu in ml plugins and in other plugins
+* added ML DB API, and ML plugin adding API for other kinds of plugins
+* added sendto menu to playlist editor context menu
+* made nsv/mp3 tag editting not increment play count
+* added data track checks in CD ripping
+* added spacebar shows current playlist item in playlist editor
+* made ml's recent items optional, and moved config for it to prefs (added option for how
+ many days to keep items in list, too)
+* made ml's internet tv/radio items optional.
+* made library DB file updating more robust, and added a ton of code to recover corrupted DB.
+
+Winamp 5.0beta2 10/23/03:
+* modern skin updates :
+ - new skin drop
+ - woo francis owns, and fixed keyboard bugs
+ - fixed alt+f4 from video wnd & pledit
+ - fixed resizing cursor in popups
+ - fixed add to library parenting window to main window rather than to library
+ - fixed switching to vis while video is playing
+ - added checkmarks to scale/opacity menu
+ - fixed avs fullscreen complaint when video is there hanging
+ - fixed resizerect docking to viewport for snapAdjusted wnds
+ - fixed slowdowns loading big playlists in mmd3
+ - added redock after drawer open/close
+ - gave modern skin default positions for main wnd/pledit/library
+ - added popup menu on song title text
+ - fixed how menus would overlap menubar buttons when skin was at the bottom of the screen
+ - added "animate config drawer" in skin option menus
+ - fixed saving/restoring of classic main window and eq status, and classic pledit windowshade and size
+ - fixed showing classic skins at startup when loading modern skin
+ - even newer skin drop
+ - added "temporary" to scale menu so that this locked scale thing is a bit more obvious
+ - added "pe_info" xml text display string for pledit selected/total length (not yet in skin)
+ - added dsound ipc for crossfader buttons/sliders support
+ - added vis menu action ("vis_menu"), made modern skin's button configurable (menu/config)
+ - added localization support in gen_ff
+ - added bitmap font override to ttf, added pref page with font list & scale overide
+ - added altfont, altsize, altcolor, altprettymucheverything for text objects, so that
+ skinners can make their skins ttf friendly, added "use alternate fonts" in fonts pref tab
+ - added checkbox for using operating system font rendering
+ - gave a few fontsizes to bitmapfont text objects so overrides aren't all the same size
+ - fixed crashbugs when not finding ttf fonts
+ - fixed empty playlist when starting with previously windowshaded playlist in classic mode but no xnf data
+ - fixed crash when trying to update stuff while switching skin
+ - fixed crossfader time going back to 0
+ - added right to left ttf rendering
+ - fixed layouts jumping on the screen when changing truetype font override
+ - updated to freetype 2.1.5, fixes crash, #ifdefed out some unused stuff from it
+ - fixed ctrl+w + alt+g guru
+ - fixed alt+tab while resizing player
+ - fixed player leaving a resize trail when aborting resize above autorefresh-on-alt+tab windows
+ - removed small kerning hack due to freetype 2.1.5 having much better native kerning
+ - fixed equalizer xnf entry getting duplicated over and over
+ - fixed small leak in font loader
+ - fixed font engine not reloading a ttf font after switching to win32 font renderer and back (and thus, using the override font, which also serves as fallback)
+ - adjusted some ttf rendering paddings
+ - added ability to not override bitmap font with ttf or use altfont on 7-bits character strings
+ - fixed disabled widgets states
+ - fixed typo in about box :)
+ - added ctrl+tab / ctrl+shift+tab to cycle thru windows
+* made playlist showing deferred so startups looked cleaner with modern skins
+* fixed crash on skindir change in prefs
+* added "adding to burner" status window when using sendto/drag&drop to burner, for reassuring
+ status
+* added rescan in background menu item to library menu
+* added "add folder in background" checkbox to "add folder" in library
+* added scan on startup library option
+* christophe's now playing updates
+* fixed manual playlist advance w/ repeat
+* fixed CD burning view and skin switching bug
+* fixed burning when WAV writer is configured to not write WAV headers
+* switched to new Gracenote ID
+* fixed "return" key in ml's info editor
+* added left mouse click on disabled edit boxes in ml's info editor
+* better burning error handling (shows the burning status window to easily view the error)
+* better mini-info-viewer when no internet handling
+* made winamp's open directory recurse checkbox nicer looking
+* avs doubleclick (fullscreen vs config) option in fullscreen options
+* avs alt+f4 closes winamp instead of loading preset
+* milkdrop config while running now shows help
+* added new avs default presets
+* fixed installer dual-winamp-launch bug
+* fixed gen_ml bg scanning error problem
+* optional screensaver disabling for video, fullscreen or not. now with optional mode that works
+ even if winamp is not active.
+* slight avs window reorganization
+* made modern skin extracted by default, for speed
+* improved config dialogs for aac/mp3
+* made info viewer activated by button instead of slider
+* made internet radio/tv page handle resize better (search doesnt get screwed on small windows)
+* cleaned up some labeling places
+* cleaned up ripping and burning UIs more
+* fixed library prefs radio buttons
+* added Gracenote TUID retrieval in "Now Playing" tab in ML
+* cleaned up ML playlist editor buttons, added burn button
+* added wait for blank media dialogs for burning
+* made bookmarks support drag&drop more and sendto.
+* made it so you can't remove/rename modern skin
+* added option to add burned CDs to local CD DB
+
+Winamp 5.0beta 10/13/03
+* modern skin updates :
+ - fixed win98 crash with desktopalpha skins
+ - fixed pledit jumping on top of main window when docked and interacting with config drawer
+ - fixed avs hiding main window when docking to editor
+ - fixed vis gammagroup filtering
+ - fixed bgr color for pledit scrollbar background in v1.0 skins
+ - fixed rare crash on skinswitch
+ - added timers resolution autodetection
+ - added configuration of text scrolling speed
+ - added vis_cfg action to toggle vis cfg window via button
+ - fixed config drawer tabs moving the app when not selected
+ - added enable docking checkbox and docking distance editobox in prefs
+ - added tooltip checkbox in prefs
+ - fixed tooltip stealing focus from popup menus
+ - added support for noresize flag in embedwnd so that it spawns the right container
+ - added notransparency flag for embedwnd, made milkdrop use it
+ - fixed potential aot reset by embedwnd (ie, milkdrop)
+ - fixed slow text ticker, made it use timerclient_getSkipped to have consistent speed regardless of timer resolution
+ - added timer resolution in prefs page
+ - added link ratio & alpha in prefs page
+ - fixed empty popups in pledit menubar, commandbuttons and ml menubar when no playlist or devices are available
+ - fixed "mono" display when nothing playing, made songinfo update faster after clicking play
+ - separated link position & link width for main winshade window, changed default to link all
+ - removed move="1" for song title display on main window normal and shade modes
+ - fixed click on beatvis that would sometime fail to toggle active status
+ - added gammagroup xml param to vis objects
+ - made switching to windowshade open undocked video & vis when video is playing or vis is visible, docks back when coming back to normal mode
+* made library able to update info on files that dont support tag writing when tag writing is checked
+* fixed burning bug when using certain .WAV output settings
+* enabled burning on multiple devices simultaneously
+* made Winamp check to see if AVS or milkdrop is running fullscreen before starting video playback, and remove
+ fullscreen if necessary
+* made AVS and Milkdrop check for video playback before going fullscreen (milkdrop uses fake mode, AVS complains)
+ (to avoid DirectDraw crash)
+
+Winamp 5.a10 10/10/03:
+* fixed library's playlist buttons
+* cleaned up prefs for steve some
+* fixed crash bugs in AVS, added new AVS effects from Unconed and Tom Holden
+* made doubleclick in AVS go fullscreen
+* made AVS autodetect video modes for fullscreen if necessary
+* updated to latest veritas SDK (should prompt for reboot if necessary now)
+* new milkdrop that integrates better, and fixes bugs, and is smaller
+* fixed tagz '?' lameness
+* modern skin updates :
+ - fixed aot changes not being detected
+ - fixed elapsed/remaining toggle not being forwarded
+ - fixed right key in menubar when menu item selected is a submenu, fixed left when in a submenu, fixed right after hovering on an submenu item, phew!
+ - fixed left/right keys seeking while in a menubar
+ - fixed guru due to custom checkbox accessing nonexisting layouts because they are now dynamic, made them use configattributes
+ - made vis & video open undocked when in windowshade mode
+
+Winamp 5.0a9 10/08/03:
+* modern skin updates :
+ - fixed starting modern skin when winamp is minimized (or reloading winamp with modern skin when it was minimized on exit)
+ - added Vis_FS action
+ - added menubar keyboard shortcuts
+ - made winamp ask the skin about *any* key it receives so that script can trap (and prevent) them
+ - added left/right keys for menubar navigation
+ - fixed avs flicker when spawning & closing via menu or keyboard shortcuts
+ - added guid for colorthemes pref page ({53DE6284-7E88-4c62-9F93-22ED68E6A024})
+ - fixed keyboard script hooks
+ - added "equalizer" to popups, automatically opens the drawer and switches to the tab
+ - added modern skin submenu to main popup menu/options
+ - added attrib page for adding items to View menu via script (also show up in main popup)
+ - fixed auto move of docked layouts when switching to windowshade when original layout has snapadjust values
+ - added action PE_ListOfLists for winshade playlist editors
+ - added about box guid for lightning bolt click ({8DDA9D48-B915-4320-A888-831A1D837516})
+ - added unlink="1" for layouts to remember their own position/size regardless of linkwidth/linkheight
+ - added windowshade for main & pledit, whoohoo Sven!
+ - fixed checkmark for container entries in menu
+ - added automatic discarding of unused bitmaps in memory, drops usage by 2 to 7mb (depending on skin) when not interacting with the ui
+ - fixed huge leak in ttf rendering, that one was leaking 300k/s when the song title was scrolling ! uh oh...
+ - fixed small leak in xmlparser
+ - fixed parsing of groupdefs in the middle of dynamic containers
+ - fixed small leak on skinswitch
+ - fixed small leak in gammamgr
+ - reduced memory usage by ~3mb when using winamp modern skin.
+ - fixed shutdown sequence
+ - fixed drawer locking up in closed position after detaching both windows via the menus
+ - fixed vis or video poping up when clicking detach menu option while wnd is hidden
+ - added option to bypass user defined drawer direction when window is going to get partially hidden after opening the drawer
+ - added ability to set cfgattribute value "-" to make a separator in the custom skin option menus
+ - added user option for drawer direction
+ - added reversed drawer, heehee
+ - added guiobject.reverseTarget() to move x/y values according to w/h values so that a drawer moves the opposite direction (ie, increase w/h in a targettimer, call reverseTarget and instead of growing to the right/bottom, the object will grow to the left/top - works on layouts!)
+ - fixed weakness in assessing visible states
+ - fixed drawer not remembering size after user resize
+ - added open from library in pledit lists submenu
+ - added "manage playlists" in pledit lists submenu
+ - fixed seek on doubleclick in openfile box
+ - fixed pledit disapearing on winamp startup
+ - fixed minivis stopping on desktopalpha toggle
+ - fixed some drawer issues
+* cd burning view:
+ - added item moving stuff
+ - burners default to burning view when no cd present
+ - added burning view auto refresh
+ - added 44khz resampling
+* made good generic title formatting system, that'll use library data, id3 tags, vorbis tags, cd info, etc.
+* in_dshow: added buffering status when playing streams
+* added skin rename/remove support
+* made ripping to WAV file when using a ACM conversion to generate proper files
+* in_nsv: added PCM support
+* fixed random skin support
+* fixed user info dialog multiinstance issue
+* added gracenote tuid retrieval in library's mini infobrowser
+
+Winamp 5.0a8 10/02/03:
+* big modern skin updates (as usual)
+ - docking/undocking support and drawer fixes
+* library has leet audio view searching now
+* mucho bugfixes, yo
+
+Winamp 5.0a7 9/29/03:
+* big modern skin updates (woo!)
+ - fixed opacity related repaint flicker when hiding video
+ - added modernskin custom options preliminary submenu
+ - added smooth scroll of the video/avs drawer
+ - fixed modernskin videoavs.m bugs
+ - fixed focus problems with avs in the main window
+ - changed "Media Library" to "Library"
+ - changed "Freeform" to "Modern"
+ - fixed wndregion problems when heigth/width of a group is zero
+ - fixed wndregion problems when showing/hiding objects
+ - fixed repaint problems
+ - fixed bug with playlist editor background color
+ - added font size correction
+ - added lite bold (bold="2") which looks similar to old antialias="1" on non bold, so for skins backward compatibility, bold + old antialias = lite bold
+ - more color interpolation fixes
+ - made skin menus use win32 menus
+ - fixed autowidth/height from text with bold/italic attributes
+ - added system.getidealvideowidth/height();
+ - added colorthemes_next and previous actions
+ - added actions for pl/video/avs command buttons
+ - made video follow its rect without 250ms delays
+ - fixed checkmark for elapsed/remaining in options menu
+ - added lock in scaling menu
+ - added nohscroll="1" to themeslist object to hide the scrollbar
+ - fixed gammagroups for text widgets
+* more prefs overhaul to make steve happy
+* cd burning fixes
+* cd ripping crash fix
+* other fixes/etc
+* gen_ff :
+
+
+Winamp 5.0a6 9/25/03:
+* followup to 5.0a5:
+* modern skin fixes (yay francis rules):
+ - fixed HUGE doublesize by always resizing back the huge width or height to the screen max
+ - fixed safe transparency autoswitching
+ - fixed render ratio problems when opening embedded window in already scaled window
+ - added control menu to app context menu
+ - implemented ff control menu
+ - added layout snap adjustment
+ - added System.switchSkin script call
+ - fixed initial focus to main window
+ - added eq commands from menubar
+ - added radio/tv in menubar
+ - fixed pe menu / open from library only showing the playlist rather than playing it in the pe
+ - made PE_File context menu load playlists even if ml was never shown
+ - added context menus for the player controls
+ - added elapsed/remaining hook for time displays
+ - fixed ml/pl button not lightning up when ml/pl is showing
+ - added checkmark for "Main Window" when the main container is visible
+ - improved color interpolation for wa3 skins
+* fix to ripping speed selection crash bug
+* updated mp3 codec selection on unreg stuff (to revert back to old codec)
+* burning ui fixes
+* installer fixes [workarounds for now too]
+
+Winamp 5.0a5 9/23/03:
+* very alpha version of new modern skin, lots of gen_ff updates
+* new install process (Thanks kichik for the help)
+* cd burning
+* better AAC time updating support
+* mp3 ripping (with winamp pro regkey)
+* sendto menu in library
+* big AVS updates (2.7pre3 or so? forgot to update the ver#, but this one is newer than
+ anything other as of 9/23)
+* directory autoscanning for library (woo)
+* more! I forget it all...
+
+Winamp 5.0a4:
+a4: mostly cosmetic update:
+a4: fixed library/pe in wa3 mode in 16bpp mode
+a4: new splash screen
+a4: updated credits/about box stuff
+a4: added good in_nsv about box
+* .wal support in winamp.exe
+* changed ripping filename specifier to <artist> etc
+* minibrowser moved to gen_ml
+* made empty media view have some crappy text + add directory button
+* down arrow in library search now go to results
+* veritas SDK integration for CD ripping/playback
+* huge preferences makeover
+* mini-context-info stuff in gen_ml (complete with internet checking)
+* made bitmapped font in winamp off by default for better int shit
+* uninstall plug-in support
+* changed allow multiple instances behavior to be better (always off
+ when playing/enqueuing files)
+* made bookmarks viewer editor in library
+* made library support drag&drop for adding directories
+* made library have more options for adding files metadata
+* made library metadata updating faster
+* tons of wa3 skin love
+* about box for AAC stuff
+* made wa3 pledit use colors and better scrollbars
+* bugfixes in gen_ff
+* fixed little gfx bug in fullscreen video playback on multimon
+* more!
+
+
+Winamp 2.95 (never released):
+* startup with hung winamp process in background fixed (opens new instance)
+* CD ripping support in media library
+* Preliminary AAC playback support added to in_mp3.dll
+* ryan fixed shuffle again
+* minibrowser ctrl+l fix
+* media library: lots of bugfixes
+* media library: listener count in internet tv/radio
+* media library: query playback mode preferences
+* media library: skinnable list/treeview selection colors
+* nsv: subtitle bugfixes
+* nsv: more buffering options
+* nsv: shoutcast metadata support
+* nsv: better invalid bitstream handling
+* nsv: better display options
+* nsv: new ASYN aux chunk handling.
+* nsv: support for new extended TOC with frame-accurate seeking
+* video: overlay fixes on 556 and other unusual modes
+* video: drag&drop URL to video window now works.
+* video: subtitle fixes.
+* video: support for alt+enter and alt+f4 to leave fullscreen
+* cdda: bugfixes
+* avs: evallib | and & operator fixes
+* in_vorbis fixes/updated libvorbis to post-1.0 cvs
+* in_midi fixes
+
+Winamp 2.91:
+* fixed an incorrect vis color
+* fixed shuffle; now, when you start winamp w/shuffle on, it returns
+ you to the song you were at when you exited last time
+* made winamp not crash if you close it while a file info dialog is open
+* fixed jump dialogs when using language packs
+* fixed tooltip in lightning bolt
+* made video window on autoclose not stop if configured to do so
+* made in_mp3 have options for adding tags from ml
+* fixed a bug in in_wm
+* library: made library refresh properly on add/compact/etc
+* library: fixed a library win9x view issue
+* library: fixed shift+enter in media library tree
+* library: added "Explore item folder" in library's media view
+* library: made internet radio/tv display msg when reload is blocked
+* library: added "Physically delete file" in library's media view
+* dshow: added config dialog (filetypes)
+* dshow: added option to vertically flip WMV videos (for machines with old WMV
+ codec installed)
+* dshow: added file info box
+* dshow: fixed issues with widechars
+* dshow: fixed bitrates displayed
+* dshow: added 32 & 64-bit audio support
+* nsv: fixed title updating (playlist flicker) bug
+* nsv: made nsv info box show filename and basic info
+* nsv: made nsv use less cpu on [p]rebuffering
+* nsv: fixed mp3 decoder's eating of the end of nsv file
+* nsv: added AAC decoding support
+* nsv: fixed vis on audioless nsvs
+* put AOD in all installers (opt-out always)
+
+
+Winamp 2.90:
+* hot new default skin, done by none other than the evil robot turned good, Steve Gedikian
+* added integrated full featured video support (NSV and DirectShow (AVI,ASf,MPEG,etc))
+* added library (complete with media database, shoutcast listing, playlist editing,
+ CD listing, mass tag editting, plugin API for portable devices, and more!)
+* updated Winamp's window docking code to be more robust/extensible
+ - made AVS dock use this new API
+* updated PCM equalizer with code from 4Front Technologies/George Yohng. Quality is a lot better.
+* updated equalizer default skin to show the true +12db/-12db range (the 20db was a veeery old typo)
+* a ton of new WM_WA_IPC API calls.
+ - general purpose plugin window support
+ - extended metadata system for getting more than just title/length of items.
+ - lots of exposed features via IPC
+* updated to PP's latest input and output plugins
+* focus/Z order change on window close related bugfixes
+* added track numbers and song lengths in HTML generated playlists
+* removed all ATL code, shoved EXE size by 20kb :)
+* added digital audio extraction in in_cdda.dll
+ (needs WNASPI32.DLL under Windows 9x/ME)
+* added Alt+M shortcut for minimizing Winamp
+* added Ctrl+(Keypad +)/Ctrl+(Keypad -) shortcuts in playlist editor for changing font size
+* fixed stop after current menu item trash related bug
+* added ultravox support for in_mp3
+* made in_mp3 not display 'unknown X' for empty id3 tags
+* installer uses leet new NSIS 2.0b3
+* improvements to the setup process
+* made the keep on screen code multimonitor smart and better
+* fixed & error in tooltips in winamp and winampa's systray icons
+* and TONS more! (new SDKs will be posted soon.)
+
+Winamp "Classic" 2.81:
+* updated to PP's latest input and output plugins
+* in_mp3 now doesnt continue to play on output plugin error.
+* smaller installers because we use msvcrt.dll now
+* fixed bugs relating to files with ~ in their names.
+* doublerightclick in credits makes for fullscreen credits
+* more bugfixes (including a fix in the version update notification checking)
+* updated installer to have nicer error messages.
+* made systray icon update if explorer restarts
+* and more (muahaha)!
+
+Winamp 2.80:
+* fixed drag&drop from open file dialog related bugs
+* made CDDB support better handle not-found CDs/lack of CDDB installed.
+* update to CDDB ui (bugfix)
+* new splash screen
+* minibrowser security fix
+* updated winamp agent to support both winamp 2.x and 3.x
+* included PP's hacks for slightly better unicode filename support
+* in_wave support for floating point .WAV files fixed
+* better win9x compatibility for DirectSound
+* waveOut made skip less
+* some in_mod per-file fixes
+* OGG Vorbis support for Standard and Full installs.
+* CD support back in lite installer.
+
+Winamp 2.79:
+* upgraded unzip/decompress support to zlib 1.1.4, for big security fix
+* improved multiple instance detection code/opening many files from explorer issues
+* winamp agent tooltip improvement
+* fix to id3v2+unicode support
+
+Winamp 2.78:
+* minibrowser fixes
+* cddb2 support
+* updates to mod, midi, and wav support (from the wonderful PP)
+
+Winamp 2.77:
+* mb.ini skin support (Winamp/MBOpen)
+* added page and slider for 'shuffle morph rate' to Preferences so you can
+ control how much the playlist morphs (mutates) each time it cycles
+ through.
+* PP's ACM disk writer output plug-in instead of the classic one
+* PP's WAV/VOC reader (Which is apparently so much better, but we will see)
+* included new in_midi and in_mod (yay)
+* made playlist editor automatically size down when necessary (on startup)
+* made drag&drop playlist URLs work
+* made alt+delete work again in playlist editor
+* made winamp.exe and winampa.exe both much less likely to fudge HKCR/.
+* fixed drag&drop in vis areas
+* made Winamp handle language packs that lack strings and/or dialogs better
+* made physical file remover ask you for every file, to prevent disasters
+* fixed issues with using a large number of input plug-ins and extensions in
+ open box (I think)
+* fixed a small "bug" in the id3 editor of in_mp3
+* fixed the frame count bug in id3 editor of in_mp3
+* made general purpose plug-in uninstall capability.
+* new hyper-leet desktop icon on new installs of full version.
+* removed Mjuice support from full version.
+* tinyvis 2001 v2.04
+* AVS includes experimental fullscreen overlay mode.
+
+
+Winamp 2.76:
+* ryan fixed shuffle!
+* christophe added IE URL drag&drop capability
+* faster FFTs for vis on WAV/CDDA playback
+* fixes RealPlayer's .xpl association bug
+* AVS 2.5 (new effects, speedups, smaller presets, etc)
+* TinyVis 2001. Includes fast, highly trippy "Random Intelligent Visualization".
+* Peter's latest and greatest MIDI plug-in
+
+Winamp 2.75:
+* avs 2.4.9 (interface improvements, speedups, new dynamic movement effect (yay!))
+* made skin installing do better renaming (removes [1], etc)
+* some new sample avs presets (thanks to Zen-X and Marco Muraca, Frank Nagel)
+* MASSIVELY optimized directory scanning and removed multi-add bugs
+* fixes to in_mod and in_midi.
+* fixed some NT/2K uninstall issues.
+* updated winamp agent with full color icon
+* temporarily removed in_asfs from full distribution (security issue)
+
+Winamp 2.74:
+* fixed vis shutdown related bugs (message pump is run while waiting for safety)
+* cleaned up some startup code
+* fixed layer 2 i/s bug in in_mp3
+* fixed HTTP/1.1 + Apache CGI issues in in_mp3.
+* improved HTTP auth support in in_mp3
+* updated to new in_midi version (go PP)
+* new AVS with Overlay support
+* made uninstall use NSIS's uninstaller
+
+Winamp 2.73:
+* smaller main winamp.EXE
+* new AVS version with larger interface
+* seeking for HTTP/1.1 streamed MP3 files
+* improved minibrowser functionality
+* updated versions of MOD and MIDI plug-ins (thanks Jake and PP)
+* made out_wm smaller (32k->7k)
+* updated to newer, more efficient installer (1.1o)
+* fixed one cdda related bug
+
+Winamp 2.72:
+* stupid in_mp3 fix (for lame encoded files)
+* updated directmusic/midiOut plug-in (Thanks to Peter Pawlowski)
+* updated mikamp plug-in (Thanks to Jake Stine)
+* made Winamp Agent smaller, use less memory, not interfere with ScanDisk, etc.
+* fixed some skin related bugs (main.bmp is no longer ever reloaded)
+* fixed cursor bugs - cursors are now loaded all at once (makes for slightly
+ slower skin switching, but should make things more responsive)
+* made zip skin loading more reliable (and slightly slower)
+* small avs updates
+
+Winamp 2.71:
+* new directmusic/midiOut plug-in (PP's)
+* mikmod update (we love you Jake)
+* avs: optimized fullscreen 32bpp->Xbpp (not full support yet)
+ better resizing code, multimonitor support
+ many stability improvements, opts to evaluation compiler
+ new effects, of bugfixes
+ avs minimize modes work right (mostly)
+* in_cdda: reduced plug-in size by 30k.
+* out_wave: made writeall logic better and less problematic
+ altvol mode in no longer fudges with global volume.
+* in_mp3: improved mp3 decoder sync (byte level sync, better checking)
+ fixed id3v2 rare writing bug
+ fixed in_mp3 visualization bug
+ made highest the default text for in_mp3
+* made shuffle not reinit shuffletable on add/remove, it adapts randomly
+* got rid of http:// checking for file retreiving.. http is assumed
+* made tooltips and hotkeys for demand/load/play in preferences
+* made 12k fullscreen visualization plug-in for all installs (woo)
+* fixed F5 redrawing stuff it shouldn't bug
+* fixed moving a file in the playlist and then using shift to select
+* fixed / in IPC issues (i.e. winamp.exe http://url now works all the time)
+* fixed the generic eq slowdown on silence, made more accurate
+* fixed vis plug-in installation issues
+* made workaround for bug in in_mjf.dll
+* a few other fixes I forgot to log
+
+Winamp 2.7:
+ * mp3 decoder: better tag editor, bugfixes
+ * mod decoder: too much to list. much revised. www.divent.org for more info.
+ * much improved CDDA (Faster, less crashy)
+ * waveout output plug-in bug fixes
+ * new directsound output plug-in (very charming)
+ * many optimizations and bugfixes to AVS - this version is quite fast.
+ * faster playlist loading, faster playlist editting on large lists
+ * windowshade visualization now has spectrum analyzer instead of (crappy)
+ VU meter.
+ * improved that old issue of what happens when you delete the playing file
+ in the playlist.
+ * made credits less problematic (and more time based, less frame based, no more crashing)
+ * made multiple-instance handling handle running with different command lines better
+ * return of classic demo.mp3
+ * sped up exit process some
+ * many other small fixes and refinements
+ * nsis 1.0 installer (http://www.nullsoft.com/free/nsis/ for more info)
+
+Winamp 2.666:
+ * spiffier credits in about box
+ * new mp3 input plug-in
+ * streaming improvements (now much less intrusive)
+ * fully ISO compliant decoding
+ * ID3v2 support
+ * even more
+ * AVS 2.1 . New blitter/movement filtering, MMX optimized, new presets.
+
+Winamp 2.65:
+ * fix to ex-m3u bug/security hole
+ * improved mp3 http streaming dialog (no longer upsets AVS, etc)
+ * optional aol icon in full version
+
+Winamp 2.64:
+ * fix to proxy support for mp3 streaming
+ * dsp plugin fixes
+ * justin can't code
+
+Winamp 2.63:
+ * language pack improvements/cleanups
+ * giant (2000+) skin archive bug fixed
+ * promotional offers on install
+ * streaming improvements (authentification, proxy authentification, dialogless
+ streaming when winamp is not active, content-disposition usage, etc).
+ * minibrowser start page now live if inet connected.
+ * return of out_wm (WMA writer) -- lets you transcode your WAV/MP3/MOD/etc
+ files into WMA!
+
+Winamp 2.62:
+ * Generic dialog processing message loop so now TAB/etc... works in plugins dialog windows
+ * Fix to Mjuice (memory leak that caused the full install to puke after many hours)
+ * Winamp Visualization Studio updates.
+ * Installer bitmap updates
+ * Installer terminology changes
+
+Winamp 2.61:
+ * In accordance with Microsoft's license agreement, we no longer allow you to
+ use DSP plug-ins or alternate output plug-ins when playing WMA files.
+ * Installation now gives you more options, cleaner.
+ * Some mixed block DCT and Antialiasing fixes to Nitrane.
+ * Support for .wsz files in your skin directory as well as .zip files.
+ * Fixed: gdi leak when switching skins
+ * Fixed: gdi object leak when using Winamp systray icon
+ * AVS 1.5a6 (coming soon, 1.50)
+ * fixed: make the mouseover on install listbox not, err, mess up at weird screen locations
+ * fixed: the install screen that comes up always when no net connect available.
+ * fixed: bookmarking from explorer should be less nasty
+ * updated: uninstall should be more reliable
+ * attempted fix: bookmark add/prefs display corruption bug
+
+Winamp 2.6:
+ * Massively improved CD audio support complete with menu option to play CD
+ * New splash screen (smaller) and about box effect.
+ * Removed unused links stuff in about box
+ * Improved Jump (to file) dialog (hit the J key)
+ * Bookmarking system
+ * Fix to mp3 plug-in. Now won't stop after failed shoutcast stream.
+ * Updates to URLs used in player for web site integration
+ * Winamp Agent (can monitor file types, and restore them)
+ * Better Netscape/IE integration
+ * Updated MJuice code
+ * Updated AudioSoft code
+ * Uninstall icon in start menu now has own icon
+ * New SuperPiMP installation system
+
+Winamp 2.5d:
+ * New MJuice code
+ * Cleaned up CDDA plug-in and fixed a few bugs
+
+Winamp 2.5c:
+ * Full version has MJF support
+ * Fixed icon assignment bug
+ * Added option for old-school playlist editor buttons
+ * Fixes EQ volume setting bug
+ * Removed playlist editor child options
+ * Vastly improved window stack positioning code
+ * Fixed some rare and strange docking bugs
+
+Winamp 2.50:
+ * Winamp is now freeware! Thanks to all who have previously
+ registered, your support is really appreciated!
+ * Skin selection menu in main menu, browser in preferences
+ * Builtin visualization settings are now in preferences
+ * Two streaming-related bugfixes to in_mp3.dll
+ * Added streamed-file saving to in_mp3.dll (no shoutcast saving, sorry)
+ * Added extended-M3U/PLS support (files include title and length info)
+ * Improved in_mp3.dll's frame sync code
+ * Better multi-byte character set support
+ * Numerous playlist editor bugfixes, and refinements
+ * Fixed some default skin images
+ * Fixed some leak and GDI issues (thanks, BoundsChecker)
+ * Fixed some leaks in in_cdda.dll
+ * Restructured some internals of Winamp for bitrate reporting for speed
+ * Added recent stream list to open location box
+ * Automatic IE integration for SHOUTcast
+ * Fixed a bug in out_wave.dll
+ * Updated AudioSoft plug-in
+ * Final WMA support for full version
+
+--------------------------------------------------------------------------
+
+Winamp 2.24:
+ * WSZ (Winamp Skin Zip) handling (simply open a .WSZ file in explorer
+ to have it installed)
+ * Two distributions (one with WMA and ASFS, one without)
+ * Better equalizer presets
+ * Better shuffle logic
+ * Better docking code
+ * Better support for invalid ID3v2 tags (for people putting invalid tags on)
+ * Minibrowser optimizations
+ * Fixed occasional random crashes from 2.23
+
+Winamp 2.23:
+ * Nitrane 1.60 MPEG audio decoder with MMX and 3DNow! acceleration
+ * MikMod module decoder plug-in version 1.3
+ * Self-destructing streaming dialog boxes
+ * Equalizer presets included
+ * Cosmetic fixes
+
+Winamp 2.22:
+ * AudioSoft ASFS Support
+ * SHOUTcast 1.1 (final, released) support
+ * WMA fixes
+ * Lots of bugfixes
+
+Winamp 2.21:
+ * WMA support fixed
+ * MP3 decoder bugfixes
+ * Vastly better DirectSound output
+ * Other bugfixes
+
+Winamp 2.20:
+ * Windows Media Technology 4.0 (WMT4) input/output support
+ * All new better sounding, industry standard Fraunhoffer MP3 decoder
+ * Generic PCM EQ that works on most formats (WAV/XM/MOD/IT/VQF/AAC/etc)
+ * Recursion in open directory dialog is now optional
+ * Windowshade mode for Equalizer
+ * Improved CDDA support
+ * Minibrowser improvements (new start page, etc)
+ * New version checking
+ * Fixed evil beeping bug
+ * Fixed vis/dsp plug-in directory bugs
+ * Fixed de-registration problem.
+ * Fixed a few small bugs
+
+What's new in Winamp 2.10:
+ * New preference system (yay!)
+ * New install screen stuff (with easier configuration)
+ * Improved CDDA plug-in, with auto-play
+ * Improved MPEG audio decoding
+ * Blip reduction
+ * ID3v1 URL Comment support
+ * Shoutcast URL Browser support
+ * Shoutcast 1.1 title streaming
+ * Improved MOD/XM/IT rendering (64 bit mixing, sample declicking, etc)
+ * Totally new output driver (faster and more compatible)
+ * Language package support
+ * Windows font support w/ International characterset capability (optional)
+ * Better filetype registration (with options to register on start, etc)
+ * Desktop Icon and Quicklaunch adding
+ * Customizable DSP/Vis plug-in directories.
+ * Playlist editor has more intuitive moving
+ * Winamp Browser
+ * A TON of bugfixes (if you've been having GDI errors this should fix)
+
+What's new in Winamp 2.09?
+ * Fixed stupid hanging bug in CDDA support
+ * Fixed retarded Windows-making-the-window-too-high-after-awhile bug.
+ * Fixed clear-playlist-then-seek bug.
+ * Fixed Nitrane's invalid-genre %6 bug.
+ * Added full Xing VBR support to Nitrane. Seeking and time estimation
+ work perfectly.
+ * Preliminary ID3v2 support (tag is skipped reliably)
+ * Improved Directsound output (Thanks to Leif Claesson)
+
+What's new in Winamp 2.08?
+ * Stupid VC++ 6 screwed up my PropertySheets. Crashed on some systems.
+ Fixed (as far as I can tell, let me know =).
+ * Fixed a stupid CPU consuming bug in Nitrane
+
+What's new in Winamp 2.06 (the final release of 1998!)?
+ * Built with VC++ 6 and VC++ 4.2. Faster and smaller (well, we hope)
+ * Installer now prompts to use old config/fresh config
+ * Uninstaller only will remove Plugins\ and Skins\ if they are in the
+ Winamp directory (i.e. if you have a giant skin directory in another
+ location it won't remove it)
+ * Added bar analyzer mode to built-in vis (woo!)
+ * Made .pls playlists streamable
+ * Info-reading on demand mode, supplements info-on-load
+ * Made http:// default in open location box
+ * Better directory and drive adding support (you can now do 'G:\' in
+ the open location box to play an audio CD, for instance)
+ * Fixed a slight alignment bug in playlist editor
+ * Nullsoft Visualization Library! (wVis 4.1+NS Fullscreen Vis)
+ * Included experimental gapless output driver (rocks the casbah)
+ * Improved DirectSound output driver
+ * Made some mods to the waveOut plug-in, should be more stable and more
+ compatible (might have sacrificed a teeny bit of vis accuracy tho)
+ * CDDB support now remembers if it hasn't worked recently to avoid
+ from keeping popping up.
+ * Fixed a dsp plug-in bug in Nitrane
+ * Added SHOUTcast title reading to Nitrane, improved Nitrane's HTTP
+ streaming (non-blocking connect, baby)
+ * Added better MPEG 2.5 support to Nitrane (still don't have the right
+ reordering tables, though, but an improvement nonetheless)
+
+What's new in Winamp 2.05?
+ * Fixed some vis->plug-in interface bugs
+ * Fixed apply button in setup tab of prefs
+ * Rewrote some memory chunk allocation code.
+ * Added a buttload of IPC stuff (lots, baby!)
+ * wVis 4.0: New effects, higher quality rendering, and DirectDraw fullscreen
+ modes.
+ * Fixed a skin bug
+ * Fixed a few error-detection related bugs in Nitrane.
+ * Preliminary CDDB Support (CDDBP only, no HTTP)
+ * Much improved HTTP streaming. You can now psuedo-stream MOD,WAV,and MIDI
+ files.
+ * Improved MOD decoder (Thanks Jake!)
+ * Updated icons. Fixed a lot of little cosmetic bugs.
+
+What's new in Winamp 2.04?
+ * Bugfixes. I had these logged but I lost the log file :(
+ * Better installer integration (/install and /uninstall switch)
+ * New, nicer, self checking installer. Uninstall too!
+ * Fixed vis starting before first track bug
+ * Added /CLASS="Winamp v1.y" switch
+ * Added .ZIP support for skins. Simply drop a zipped skin in your Winamp\Skins
+ directory!
+ * Nitrane 1.24 with better sound quality and corrupt MP3 handling,
+ two different EQ modes, and an experimental Aural Stimulation Mode.
+ * Better "browse for directory" boxes.
+ * More IPC stuff (EQ, Skins, etc -- see frontend.txt)
+
+
+What's new in Winamp 2.03?
+ * Improved shift selection in playlist editor
+ * Better litestep support (litestep options in preferences/options, too)
+ * Fixed a number of midi/cdda related bugs
+ * Added WM_GETMINMAXINFO handler, to improve maximize handling and windowshade
+ * Fixed some stupid (but very annoying) window region related bugs.
+ * Nitrane 1.22, for better sounding MP3 playback
+ * New 'No Playlist Advance' option for DJs and people who like to jump
+ around in playlists.
+ * Snapping is now adjustable.
+
+What's new in Winamp 2.02?
+ * massive improvements to audio output system. No more skips!
+ (be sure you set your audio output prefs to the recommended
+ settings :)
+ * Some dsp plug-in related enhancements.
+ * fixed eq preset reloading bug
+ * Optimized Nitrane's 3DNow! mode some more. About 10% faster.
+ (went from 11.5% to 10.2% or so)
+ * Ported some code to C in in_mod, for the upcoming 2.02 AXP build :)
+
+What's new in Winamp 2.01?
+ * made playlist editor use windows font.. resizable and skinnable
+ * fixed a silly little hide-mainwindow-while-minimized-bug
+ * added up/down arrow (and mousewheel scroll) to plwindowshade
+ * fixed silly position bar moving bug
+ * made EQ's 0-lock more accurate
+ * made title-scroll option
+ * added width&height chex for pl
+ * fixed error with sorting in skin selection box
+ * fixed evil playlist editor 256 color bugs and alignment stuff
+ * Nitrane 1.20. Faster, fully functional layer 2 support. Optimizations.
+ Better sounding half and quarter rate modes. fixed decoder mode setting
+ * more... ! :)
+
+What's new in Winamp 2.0?
+ * I wouldn't know where to start =) sorry, just play with it..
+
+----------- Old 1.x What's New ---------------------------------------------
+What's new in Winamp 1.92 SP?
+ * New Nitrane 1.0 MPEG audio decoder (mostly bugfixes)
+ * New MOD/XM/IT player (see readme.txt)
+ * New CDDA plug-in.
+ * Fixed WAV plug-in
+ * A few new plug-ins.
+
+What's new in Winamp 1.92?
+ * Mousewheel support (controls volume, or seeks when pressed)
+ * Saves prefs even if you shut down while winamp is running
+ * Skins can now change the color of most of Winamp's dialogs
+ (see dialogs.txt in Skins\DColor)
+ * Shift-minimize minimizes to tray
+ * Plug-in name caching
+ * Modeless prefs box, skin selector, about box
+ * Better filetype registration. With unregistration, and individual
+ extension selection
+ * Win98/IE4 taskbar support
+ * added /config=file.ini (path optional) switch.
+ * fixed some region related bugs
+ * Apply works as expected in prefs now! :)
+ * Nitrane MP3: totally new decoding engine with support for MMX, 3DNow!
+ and more.
+ * Removed MIDI/CDDA plug-ins temporarily (coming back soon when we get
+ them working better)
+
+What's new in Winamp 1.91 sp1?
+ * midi plugin: Fixed MIDI playback for files with spaces in their names
+ * midi plugin: Trying to reinitialize synth on playback
+ * wave plugin: fixed ACM problems on some systems with normal PCM files
+ (bypass ACM)
+
+What's new in Winamp 1.91?
+ * better short-fn to lfn conversion
+ * added new remove options to playlist editor
+ * added /new switch, opens up a new winamp, always
+ * none option for taskbar/tray display setting
+ * Optimized prefs/plugins -- dsp plugins now must be named dsp_*.dll.
+ * Made playlist editor keep track of playlist file (again)
+ * Added SkinDir= and PluginDir= options for winamp.ini (add them manually
+ in [Winamp] in Winamp.ini to change)
+ * Fixed up some delete playlist-then-hit-stop bugs
+ * Fixed input-change bug in vis plugins
+ * added skin enhancement: region.txt region specifier
+ * added skin enhancement: balance.bmp is like volume.bmp but for
+ balance/panning bar
+ * added skin enhancement: nums_ex.bmp allows for - sign definition :)
+ * added 'playlist types' to open dialog
+ * made snap to viewport snap on move in stead of on drop
+ * added plug-in config hotkey/menu item
+ * made vis_fs.dll default visualization
+ * changed file type to 'winamp media file' from 'mpeg file'..
+ * added demo.mp3, and auto-play on first run
+ * fixed 2 digit bitrate/mixrate bug
+ * fixed IPC_JUMPTOTIME bug (works now)
+ * improved http m3u reading (error detection, yay)
+ * made doublesize mode not so screwupy in win95
+ * optimized title/length reading code
+ * auto-idle when not playing
+ * revised plug-in spec
+ * added 'default extension' option
+ * mp3 decoder: new time calculation code (all integer)
+ * mp3 decoder: added options for different extensions
+ (and additional extensions)
+ * mp3 decoder: added MMS streaming option
+ * mp3 decoder: optimized size-changing checking code (for indirect streaming)
+ * mp3 decoder: mixed-bitrate mp3s now display average bitrate
+ * mp3 decoder: more genres
+ * mp3 decoder: high genre bug fixed
+ * mp3 decoder: improved http and mms streaming (with error detection n stuff)
+ * mp3 decoder: fixed priority setting bug
+ * mp3 decoder: added error messages for id3 editor box
+ * mp3 decoder: new output system (optimized)
+ * mod decoder: fixed priority setting bug
+ * mod decoder: added better 8 bit support
+ * mod decoder: new 'if title is empty' logic..
+ * mod decoder: added support for windowshade vu
+ * mod decoder: added .669 support
+ * mod decoder: new output system (optimized)
+ * mod decoder: added waveform dsp plugin support
+ * wav decoder: .VOC support. Only mono, 8 bit files are supported.
+ * wav decoder: .VOC support supports silence blocks and changing samplerates
+ (all upsampled to 44.1kHz)
+ * wav decoder: .WAV support. Uses ACM so you can play any .WAV file.
+ * linein/cdda decoder: support for linein:// and .CDA cd tracks.
+
+
+What's new in Winamp 1.90?
+ * Major release - Winamp is now a general purpose audio player
+ (.MODs are back baby!)
+ * Plug-in input sources. Included MP2/MP3 plug-in, MOD/XM/S3M/IT plug-in.
+ Coming soon: WAV/VOC/AU/AIFF, AAC, CD Audio, etc
+ * Lots of bugfixes
+ * New bugs (since we changed a *lot*)
+ * Included new beta nifty fullscreen visualization library (with a dot
+ fountain! :)
+
+What's new in Winamp 1.82?
+ * Even more ID3 genres
+ * Decoder bug fixed (for corrupted mp3s)
+ * Better shell integration (both play and queue options)
+
+What's new in Winamp 1.81?
+ * More ID3 genres
+ * Fixed dsp plug-in non-working thingy
+ * New 'alternate volume setting code' that works on all systems
+ * You can now set the buffering time to 0 seconds for low-latency
+ * No more integer mode (sucky)
+ * New quarter-sample-rate mode
+ * New 'agressive buffering' option
+ * Cosmetic improvements
+ * Winamp now remembers position in last playlist when starting
+ * Random skin option box (see skin selector)
+
+What's new in Winamp 1.80?
+ * Skin support
+ * Plug-Ins now go in Plugins\ (move your old ones there)
+ * Experimental integer mode for 486s
+ * 64 bit mode for extra good sound
+ * Removed Extra-HQ switch (always HQ now)
+ * Removed bufferless playback mode (slower according to vtune, just set
+ buffer-size to around 0.3 seconds for faster EQ, etc)
+ * Playlist editor bugfixes and enhancements
+ * Many small bugfixes
+ * Optimized audio output code
+ * Hold down shift while seeking for some fun
+
+What's new in Winamp 1.73?
+ * .WAV writing bug fixed (sorry! :)
+
+What's new in Winamp 1.72?
+ * Winamp style dialogs are now an option
+ * Improved streaming, supports nearly all web servers (we hope), and HTTP
+ proxies.
+ * Fixed many little bugs, little improvements
+
+What's new in Winamp 1.70?
+ * Redesigned playlist editor. Much more intuitive.
+ * Fixed a TON of 256 color issues (vis looks better, dialogs look better)
+
+What's new in Winamp 1.69?
+ * Restyled playlist editor, graphical equalizer jump box, etc
+ - they look MUCH nicer
+ * 10 band graphical equalizer
+ (Makes your 1.666 and earlier presets incompatible.. sorry)
+ * Clutterbar now shows you the function of each button in the title
+ field (when the mouse is over them)
+ * Playlist editor's time calculation is better (uses ?'s if uncertain, and
+ shows hours/minutes/seconds if applicable)
+ * Playlist editor displays time for each track (if available)
+ * More optimization, mostly in lower quality mode.
+ * Plug-in related stability improvements (tries to tame badly behaved
+ plug-ins)
+ * Minor bugs fixed, including DSP selection, reverse stereo analyzer plug-in
+ * Fixed focus-main-winamp-window-on-open-of-eq-or-pe bug. (phew)
+ * Reverted the previous button back to the old way, of previous song, always
+ (I like it better this way too)
+ * New prebuffer after seek option
+ * HQ button is now single-click
+ * Sorry, this version changes the configuration format. You will need
+ to reconfigure Winamp to your liking if you are upgrading.
+ * A few new IPC calls
+
+What's new in Winamp 1.666?
+ * The Clutterbar.
+ * Windowshade button
+ * Seek-in-windowshade mode
+ * Added desktop icon adding to preferences
+ * Added a nifty hq control on main interface.
+ * New ID3 tags
+ * General purpose plug-in architecture (woohoo)
+ * Fixed mixed-mode layer 2 bug (yay)
+ * Fixed "blip" bug in low quality imdct
+ * Optimized huffman decoding and requantinization
+ * New high quality mode. Slower (but still quick), and sounds GREAT
+ * Vastly improved shell integration. Try selecting lots of files in explorer,
+ and hit "open" (doesn't work perfectly unless Winamp is already running)
+ * Improved graphical equalizer (new ranges, more accurate, etc)
+ * Added live web links.
+ * Changed format of seeking display status
+ * Added nifty "add to playlist from explorer" (more or less) option to
+ prefs/initial setup
+ * Better VU meter with peak detection in windowshade
+ * More stable threading
+ * Improved command line handling (supports relative pathnames better)
+ * Alternate volume setting mode (for some soundcards)
+ * More ID3 format strings
+ * New buffer-all logic
+ * More IPC functions for programmers
+ * %6 ID3 bug fixed (invalid genres)
+
+What's new in Winamp 1.64?
+ * MAJOR "bug" fix: fixed buffer size logistics (enables 48/24/12khz output
+ on many soundcards that wouldn't work before).
+
+What's new in Winamp 1.62?
+ * Numerous bugs fixed
+ * Tooltip on titlebar
+ * More menu items
+
+What's new in Winamp 1.61?
+ * Improved ID3 tag reading logic
+ * Resizable playlist editor
+ * Bugs fixed in .WAV writer (now replaces /\|,. etc with _)
+ * Plug-in configuration hwndParent bug fixed
+ * Configurable icon in system tray
+ * Yes, we like refinements
+
+
+What's new in Winamp 1.60?
+ * Improved sound quality (added HQ option)
+ * Improved batch .WAV writer
+ * Cleaned up playlist editor
+ * New ID3->Title translation
+ * New multiple instances logic
+ * Lots of cosmetic improvements and refinements
+ * Countless other improvements and bugfixes
+
+
+What's new in Winamp 1.6 BETA?
+ * Plugin Architecture
+ * Visualization Plugins
+ * Simple test plugins (Analyser, Oscilliscope, VU meter)
+ * Fullscreen plugins (Analyser, Oscilliscope, Voiceprint, etc)
+ - requires DirectX3+ or NT4SP3
+ * Zygron's plugin library (some nifty effects)
+ * Trippy Visualization plugin (rotozooms/motionblurrs an image with the
+ music) - requires DirectX3+ or NT4SP3
+ * 3D Spectrum Analyser plugin (Jeff's) - requires DirectX5.
+ * DSP Plugins
+ * Simple Reverb/Echo
+ * Simple Voice Removal (not extremely advanced)
+ * Note: these plugins might not be that great, but it's open for other
+ people to write plugins (and us when we get more time), so it will
+ be pretty useful.
+ * Right-click context menus in main interface
+ * Improved ID3 tag editor w/ MPEG info display
+ * VU meter and eject button in windowshade mode
+ * Increased visualization accuracy
+ * Faster seeking
+ * More reliable HTTP streaming
+ * Limited support for Microsoft NetShow audio streams (mms://)
+ * Bugfixes, new options (of course)
+
+
+What's new in Winamp since 1.45?
+ * MPEG 2.5 support (preliminary - occasional blips)
+ * HTTP streaming support
+ * New "Eject" button
+ * Fixed clipping problem
+ * New mini features
+ * TONS of bugfixes
+
+What's new in Winamp since 1.40?
+ * Keyboard shortcuts for playlist editor (as requested)
+ * Ctrl+A: selects all
+ * Ctrl+N: selects none
+ * Ctrl+I: inverts selection
+ * Ctrl+L: loads playlist
+ * Ctrl+S: saves playlist
+ * Ctrl+O: sorts by title
+ * Shift+O: sorts by filename
+ * Ctrl+Shift+O: sorts by full filename (with path)
+ * Ctrl+R: randomize
+ * Ctrl+Shift+R: reverse
+ * Delete: deletes selected mp3s.
+ * Enter: plays (first) selecteed mp3
+ * Insert: inserts mp3s
+ * Shift+Insert: inserts directory
+ * Control+Insert: inserts playlists
+ * Super low latency low overhead buffering for some computers
+ * This lets my P5-133 use around 2% with ALL options on in Windows NT
+ (but only with my GUS pnp, it doesn't help my AWE32. huh)
+ * It isn't as skip-proof as normal buffering, so you will probably have
+ to give it some big priority boost in the preferences. But the performance
+ on some systems is amazing, the fastest I have EVER seen.
+ * Winamp is now 100% uncrippled nag-free Shareware that never expires.
+ * Registration for personal use is only $10.
+
+What's new in Winamp since 1.20?
+Here's a few:
+ * Restyled playlist editor (with improved functionality)
+ * Total time display in playlist editor
+ * Rewritten playlisting engine (less buggy, more efficient)
+ * Improved ID3 tag editor (alphabetical genres)
+ * Revised main user interface
+ * Display of positioning/volume/balance in songname field
+ * Panning control
+ * EQ & Playlist buttons
+ * Enlarged songname field.
+ * Manual songname scrolling returned
+ * Doublesize mode
+ * Optimized Visualization (less slowdown in win95)
+ * Fire Analyzer Mode
+ * Snap-to-viewport in always on top mode
+ * Returned mixed-bitrate MPEG 2 stream support
+ * Logarithmic EQ
+ * Now has full -12db to +12db adjustment
+ * Presets and auto-loading of settings (per mp3)
+ * Higher priority by default
+ * Changes to taskbar/system tray preferences take place immediately
+ * .WAV ouput support (look in Preferences/Output/Device)
+ * Added support for mixed bitrate streams
+ * More file icons
+ * Lots of bugfixes and refinements
diff --git a/Src/Winamp/winamp.exe.manifest b/Src/Winamp/winamp.exe.manifest
new file mode 100644
index 00000000..d36f084b
--- /dev/null
+++ b/Src/Winamp/winamp.exe.manifest
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+
+ <!--The compatibility section will be merged from build/win/compatibility.manifest -->
+
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+
+</assembly>
diff --git a/Src/Winamp/winampApi.cpp b/Src/Winamp/winampApi.cpp
new file mode 100644
index 00000000..a6b7be28
--- /dev/null
+++ b/Src/Winamp/winampApi.cpp
@@ -0,0 +1,83 @@
+#include "main.h"
+#include "./winampApi.h"
+
+
+WinampApi::WinampApi()
+{}
+WinampApi::~WinampApi()
+{}
+
+HRESULT WinampApi::CreateInstance(WinampApi **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = new WinampApi();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+const char *WinampApi::getServiceName()
+{
+ return "Winamp API";
+}
+
+const GUID WinampApi::getServiceGuid()
+{
+ return winampApiGuid;
+}
+
+size_t WinampApi::AddRef()
+{
+ return _ref.fetch_add( 1 );
+}
+
+size_t WinampApi::Release()
+{
+ if ( _ref.load() == 0 )
+ return _ref.load();
+
+ LONG r = _ref.fetch_sub( 1 );
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int WinampApi::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+ *object = NULL;
+ return E_NOINTERFACE;
+}
+
+HWND WinampApi::GetMainWindow(void)
+{
+ return hMainWindow;
+}
+
+HWND WinampApi::GetDlgParent(void)
+{
+ return (g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow;
+}
+
+HRESULT WinampApi::OpenUrl(HWND hwnd, const wchar_t *url)
+{
+ myOpenURL(hwnd, (wchar_t*)url);
+ return S_OK;
+}
+
+int WinampApi::GetRegVer()
+{
+ return 2;
+}
+
+#define CBCLASS WinampApi
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETMAINWINDOW, GetMainWindow)
+CB(API_GETDLGPARENT, GetDlgParent)
+CB(API_OPENURL, OpenUrl)
+CB(API_GETREGVER, GetRegVer)
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Winamp/winampApi.h b/Src/Winamp/winampApi.h
new file mode 100644
index 00000000..b2d1913f
--- /dev/null
+++ b/Src/Winamp/winampApi.h
@@ -0,0 +1,42 @@
+#ifndef NULLSOFT_WINAMP_API_WINAMP_IMPLEMENTATION_HEADER
+#define NULLSOFT_WINAMP_API_WINAMP_IMPLEMENTATION_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <atomic>
+
+#include "./api_winamp.h"
+
+class WinampApi : public api_winamp
+{
+public:
+ WinampApi();
+ ~WinampApi();
+
+public:
+ static HRESULT CreateInstance(WinampApi **instance);
+ static const char *getServiceName();
+ static const GUID getServiceGuid();
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* api_winamp */
+ HWND GetMainWindow(void);
+ HWND GetDlgParent(void);
+ HRESULT OpenUrl(HWND hwnd, const wchar_t *url);
+ int GetRegVer();
+
+protected:
+ std::atomic<std::size_t> _ref = 1;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_API_WINAMP_IMPLEMENTATION_HEADER \ No newline at end of file
diff --git a/Src/Winamp/winampv6.vcxproj b/Src/Winamp/winampv6.vcxproj
new file mode 100644
index 00000000..0a97e049
--- /dev/null
+++ b/Src/Winamp/winampv6.vcxproj
@@ -0,0 +1,1052 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{7DE5C6C7-DAF2-42F9-9324-C8CF4E7E8AC5}</ProjectGuid>
+ <RootNamespace>winampv6</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ <TargetName>winamp</TargetName>
+ <EmbedManifest>true</EmbedManifest>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetName>winamp</TargetName>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ <TargetName>winamp</TargetName>
+ <EmbedManifest>true</EmbedManifest>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetName>winamp</TargetName>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;..\Wasabi;..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_WIN32_DCOM;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;WIN32;_WINDOWS;FFSKIN;USE_VIS_HDR_HWND;_CRT_SECURE_NO_WARNINGS;_WA_IPC_LEAN_H_;IGNORE_API_GRACENOTE;D3D_DEBUG_INFO;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4013;4100;4995;4996;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <StringPooling>true</StringPooling>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;winmm.lib;msacm32.lib;shlwapi.lib;Rpcrt4.lib;d3dx9d.lib;wininet.lib;fmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-dbg;..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);..\nsutil\$(PlatformShortName)_$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>msacm32.dll;nsutil.dll;comctl32.dll;comdlg32.dll;tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <TargetMachine>MachineX86</TargetMachine>
+ <StackReserveSize>4194304</StackReserveSize>
+ <StackCommitSize>38892</StackCommitSize>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>
+xcopy /Y /D /S $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+xcopy /Y /D /S $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S ..\resources\languages\*.wlz ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Lang\
+
+xcopy /Y /D /S ..\resources\data\whatsnew.txt ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S ..\resources\skins\Bento\ ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\
+
+del /Q /F /S ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\*.m
+
+xcopy /Y /D /S "..\resources\skins\Big Bento\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.bat"
+
+xcopy /Y /D /S "..\resources\skins\Winamp Modern\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.bat"
+
+xcopy /Y /D /S "..\resources\license" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\license\"
+
+xcopy /Y /D /S "..\resources\media" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\media\"
+
+xcopy /Y /D /S "..\resources\data\avs" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\avs\"
+
+xcopy /Y /D /S "..\resources\data\freeform\xml\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\freeform\xml\"
+
+xcopy /Y /D /S ..\resources\data\vis_avs.dat ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+
+xcopy /Y /D /S "..\resources\data\dsp_sps\*.sps" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\DSP_SPS\"
+
+xcopy /Y /D /S "..\..\Qt\DLL_5.12_$(PlatformShortName)\$(Configuration)\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\"
+</Command>
+ <Message>Copy resources: whatsnew.txt file, languages, skins (Bento, Big Bento, Winamp Modern) other files to ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\</Message>
+ </PostBuildEvent>
+ <Manifest>
+ <AdditionalManifestFiles>$(ProjectDir)manifest.xml</AdditionalManifestFiles>
+ <OutputManifestFile>$(OutDir)$(TargetName)$(TargetExt).embed.manifest</OutputManifestFile>
+ </Manifest>
+ <ManifestResourceCompile>
+ <ResourceOutputFileName>$(OutDir)$(TargetName)$(TargetExt).embed.manifest.res</ResourceOutputFileName>
+ </ManifestResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;..\Wasabi;..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_WIN32_DCOM;WIN64;_DEBUG;_WINDOWS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;USE_VIS_HDR_HWND;D3D_DEBUG_INFO;_CRT_SECURE_NO_WARNINGS;_WA_IPC_LEAN_H_;IGNORE_API_GRACENOTE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4013;4100;4995;4996;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <StringPooling>true</StringPooling>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;winmm.lib;msacm32.lib;shlwapi.lib;Rpcrt4.lib;d3dx9d.lib;wininet.lib;fmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-dbg;..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);..\nsutil\$(PlatformShortName)_$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>msacm32.dll;nsutil.dll;comctl32.dll;comdlg32.dll;tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <StackReserveSize>4194304</StackReserveSize>
+ <StackCommitSize>38892</StackCommitSize>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D /S $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+xcopy /Y /D /S $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S "..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-dbg\bin\fmtd.dll" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\"
+
+xcopy /Y /D /S ..\resources\languages\*.wlz ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Lang\
+
+xcopy /Y /D /S ..\resources\data\whatsnew.txt ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S ..\resources\skins\Bento\ ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\
+
+del /Q /F /S ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\*.m
+
+xcopy /Y /D /S "..\resources\skins\Big Bento\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.bat"
+
+xcopy /Y /D /S "..\resources\skins\Winamp Modern\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.bat"
+
+xcopy /Y /D /S "..\resources\license" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\license\"
+
+xcopy /Y /D /S "..\resources\media" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\media\"
+
+xcopy /Y /D /S "..\resources\data\avs" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\avs\"
+
+xcopy /Y /D /S "..\resources\data\freeform\xml\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\freeform\xml\"
+
+xcopy /Y /D /S ..\resources\data\vis_avs.dat ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+
+xcopy /Y /D /S ..\resources\plugins\dsp_sps.dll ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+
+xcopy /Y /D /S "..\resources\data\dsp_sps\*.sps" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\DSP_SPS\"</Command>
+ <Message>Copy resources: whatsnew.txt file, languages, skins (Bento, Big Bento, Winamp Modern) other files to ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..;..\Wasabi;..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_WIN32_DCOM;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;WIN32;_WINDOWS;FFSKIN;USE_VIS_HDR_HWND;_CRT_SECURE_NO_WARNINGS;_WA_IPC_LEAN_H_;IGNORE_API_GRACENOTE;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4995;4996;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;winmm.lib;msacm32.lib;shlwapi.lib;Rpcrt4.lib;d3dx9.lib;wininet.lib;fmt.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>msacm32.dll;nsutil.dll;comctl32.dll;comdlg32.dll;tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <AdditionalLibraryDirectories>..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-rel;..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);..\nsutil\$(PlatformShortName)_$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <TargetMachine>MachineX86</TargetMachine>
+ <StackReserveSize>4194304</StackReserveSize>
+ <StackCommitSize>38892</StackCommitSize>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D /S $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S ..\resources\languages\*.wlz ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Lang\
+
+xcopy /Y /D /S ..\resources\data\whatsnew.txt ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S ..\resources\skins\Bento\ ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\
+
+del /Q /F /S ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\*.m
+
+xcopy /Y /D /S "..\resources\skins\Big Bento\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.bat"
+
+xcopy /Y /D /S "..\resources\skins\Winamp Modern\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.bat"
+
+xcopy /Y /D /S "..\resources\license" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\license\"
+
+xcopy /Y /D /S "..\resources\media" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\media\"
+
+xcopy /Y /D /S "..\resources\data\avs" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\avs\"
+
+xcopy /Y /D /S "..\resources\data\freeform\xml\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\freeform\xml\"
+
+xcopy /Y /D /S ..\resources\data\vis_avs.dat ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+
+xcopy /Y /D /S "..\resources\data\dsp_sps\*.sps" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\DSP_SPS\"
+
+xcopy /Y /D /S "..\..\Qt\DLL_5.12_$(PlatformShortName)\$(Configuration)\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\"
+</Command>
+ <Message>Copy resources: whatsnew.txt file, languages, skins (Bento, Big Bento, Winamp Modern) other files to ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\</Message>
+ </PostBuildEvent>
+ <Manifest>
+ <OutputManifestFile>$(OutDir)$(TargetName)$(TargetExt).embed.manifest</OutputManifestFile>
+ <AdditionalManifestFiles>$(ProjectDir)manifest.xml</AdditionalManifestFiles>
+ </Manifest>
+ <ManifestResourceCompile>
+ <ResourceOutputFileName>$(OutDir)$(TargetName)$(TargetExt).embed.manifest.res</ResourceOutputFileName>
+ </ManifestResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..;..\Wasabi;..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_WIN32_DCOM;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;WIN64;NDEBUG;_WINDOWS;FFSKIN;USE_VIS_HDR_HWND;_CRT_SECURE_NO_WARNINGS;_WA_IPC_LEAN_H_;IGNORE_API_GRACENOTE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4995;4996;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;winmm.lib;msacm32.lib;shlwapi.lib;Rpcrt4.lib;d3dx9.lib;wininet.lib;fmt.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>msacm32.dll;nsutil.dll;comctl32.dll;comdlg32.dll;tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <AdditionalLibraryDirectories>..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-rel;..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);..\nsutil\$(PlatformShortName)_$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <StackReserveSize>4194304</StackReserveSize>
+ <StackCommitSize>38892</StackCommitSize>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D /S $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S "..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-rel\bin\fmt.dll" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\"
+
+xcopy /Y /D /S ..\resources\languages\*.wlz ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Lang\
+
+xcopy /Y /D /S ..\resources\data\whatsnew.txt ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\
+
+xcopy /Y /D /S ..\resources\skins\Bento\ ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\
+
+del /Q /F /S ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Bento\*.m
+
+xcopy /Y /D /S "..\resources\skins\Big Bento\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Big Bento\*.bat"
+
+xcopy /Y /D /S "..\resources\skins\Winamp Modern\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.m"
+
+del /Q /F /S "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Skins\Winamp Modern\*.bat"
+
+xcopy /Y /D /S "..\resources\license" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\license\"
+
+xcopy /Y /D /S "..\resources\media" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\media\"
+
+xcopy /Y /D /S "..\resources\data\avs" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\avs\"
+
+xcopy /Y /D /S "..\resources\data\freeform\xml\" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\freeform\xml\"
+
+xcopy /Y /D /S ..\resources\data\vis_avs.dat ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+
+xcopy /Y /D /S ..\resources\plugins\dsp_sps.dll ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+
+xcopy /Y /D /S "..\resources\data\dsp_sps\*.sps" "..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\DSP_SPS\"</Command>
+ <Message>Copy resources: whatsnew.txt file, languages, skins (Bento, Big Bento, Winamp Modern) other files to ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\nsutil\nsutil.vcxproj">
+ <Project>{dabe6307-f8dd-416d-9dac-673e2decb73f}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\tataki\tataki.vcxproj">
+ <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\Wasabi\bfc\bfc.vcxproj">
+ <Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\albumart\albumart.vcxproj">
+ <Project>{388476b7-c0a1-4853-b6f4-9a64ca346ba9}</Project>
+ <IncludeIsGuid>true</IncludeIsGuid>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\Elevator\Elevator.vcxproj">
+ <Project>{977153bf-8420-4c8d-aa25-592faedb6cba}</Project>
+ <IncludeIsGuid>true</IncludeIsGuid>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\playlist\playlist.vcxproj">
+ <Project>{b2c0f048-c7fa-4864-b5b3-75e69458ba9e}</Project>
+ <IncludeIsGuid>true</IncludeIsGuid>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\WAT\WAT.vcxproj">
+ <Project>{c5714908-a71f-4644-bd95-aad8ee7914da}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\Agave\Metadata\api_metadata.cpp" />
+ <ClCompile Include="..\config\config.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)1.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)1.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)1.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)1.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="..\Elevator\FileTypeRegistrar.cpp" />
+ <ClCompile Include="..\Plugins\General\gen_crasher\GetWinVer.cpp" />
+ <ClCompile Include="..\Plugins\General\gen_ml\menu.cpp" />
+ <ClCompile Include="..\Plugins\General\gen_ml\ml_lib.cpp" />
+ <ClCompile Include="../Plugins/Library/ml_bookmarks\bookmark.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)2.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)2.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)2.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)2.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="..\nu\ConfigCOM.cpp" />
+ <ClCompile Include="..\nu\HTMLContainer.cpp" />
+ <ClCompile Include="..\nu\ServiceWatcher.cpp" />
+ <ClCompile Include="..\nu\threadpool\ThreadFunctions.cpp" />
+ <ClCompile Include="..\nu\threadpool\ThreadID.cpp" />
+ <ClCompile Include="..\nu\threadpool\ThreadPool.cpp" />
+ <ClCompile Include="..\nu\trace.cpp" />
+ <ClCompile Include="..\Wasabi\api\skin\skinitem.cpp" />
+ <ClCompile Include="..\Wasabi\api\syscb\callbacks\syscbx.cpp" />
+ <ClCompile Include="About.cpp" />
+ <ClCompile Include="AccessibilityConfigGroup.cpp" />
+ <ClCompile Include="AdData.cpp" />
+ <ClCompile Include="AlbumArtRetrieval.cpp" />
+ <ClCompile Include="api_videopreferences.cpp" />
+ <ClCompile Include="application.cpp" />
+ <ClCompile Include="ApplicationCOM.cpp" />
+ <ClCompile Include="AppRefCount.cpp" />
+ <ClCompile Include="benskiQ\benskiQ.cpp" />
+ <ClCompile Include="benskiQ\Biquad.cpp" />
+ <ClCompile Include="benskiQ\EqBand.cpp" />
+ <ClCompile Include="bm.cpp" />
+ <ClCompile Include="BookmarksCOM.cpp" />
+ <ClCompile Include="BoolAttribute.cpp" />
+ <ClCompile Include="BrowserCOM.cpp" />
+ <ClCompile Include="burn.cpp" />
+ <ClCompile Include="BurnManager.cpp" />
+ <ClCompile Include="classic_vis.cpp" />
+ <ClCompile Include="cmdline.cpp" />
+ <ClCompile Include="commandLink.cpp" />
+ <ClCompile Include="Config.cpp" />
+ <ClCompile Include="conversions.cpp" />
+ <ClCompile Include="convert.cpp" />
+ <ClCompile Include="creditsrend.c" />
+ <ClCompile Include="CurrentSongCOM.cpp" />
+ <ClCompile Include="DataStoreCOM.cpp" />
+ <ClCompile Include="DecodeFile.cpp" />
+ <ClCompile Include="DeveloperConfigGroup.cpp" />
+ <ClCompile Include="dispatchCallback.cpp" />
+ <ClCompile Include="dock.cpp" />
+ <ClCompile Include="dpi.cpp" />
+ <ClCompile Include="Draw.cpp" />
+ <ClCompile Include="draw_embed.cpp" />
+ <ClCompile Include="draw_eq.cpp" />
+ <ClCompile Include="draw_main.cpp" />
+ <ClCompile Include="draw_mb.cpp" />
+ <ClCompile Include="draw_pe.cpp" />
+ <ClCompile Include="draw_sa.cpp" />
+ <ClCompile Include="draw_vw.cpp" />
+ <ClCompile Include="dsp.cpp" />
+ <ClCompile Include="dwm.cpp" />
+ <ClCompile Include="embwnd.cpp" />
+ <ClCompile Include="Eq.cpp" />
+ <ClCompile Include="eq10dsp.cpp" />
+ <ClCompile Include="EQConfigGroup.cpp" />
+ <ClCompile Include="Equi.cpp" />
+ <ClCompile Include="ExplorerFindFile.cpp" />
+ <ClCompile Include="ExtendedInfo.cpp" />
+ <ClCompile Include="ExtendedReader.cpp" />
+ <ClCompile Include="ExternalCOM.cpp" />
+ <ClCompile Include="FeedBase.cpp" />
+ <ClCompile Include="feeds.cpp" />
+ <ClCompile Include="Fft.cpp" />
+ <ClCompile Include="FileInfo.cpp" />
+ <ClCompile Include="FloatAttribute.cpp" />
+ <ClCompile Include="fullscreen.cpp" />
+ <ClCompile Include="GammaFilter.cpp" />
+ <ClCompile Include="GammaManagerAPI.cpp" />
+ <ClCompile Include="gen.cpp" />
+ <ClCompile Include="handler.cpp" />
+ <ClCompile Include="html.cpp" />
+ <ClCompile Include="Http.cpp" />
+ <ClCompile Include="HTTPRetrieveFile.cpp" />
+ <ClCompile Include="In.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)3.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)3.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)3.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)3.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="install.cpp" />
+ <ClCompile Include="IntAttribute.cpp" />
+ <ClCompile Include="InternetConfigGroup.cpp" />
+ <ClCompile Include="InW.cpp" />
+ <ClCompile Include="ipc.cpp" />
+ <ClCompile Include="IVideoD3DOSD.cpp" />
+ <ClCompile Include="jnetcom.cpp" />
+ <ClCompile Include="JSAPI2_Application.cpp" />
+ <ClCompile Include="JSAPI2_AsyncDownloader.cpp" />
+ <ClCompile Include="JSAPI2_Bookmarks.cpp" />
+ <ClCompile Include="JSAPI2_CallbackManager.cpp" />
+ <ClCompile Include="JSAPI2_Creator.cpp" />
+ <ClCompile Include="JSAPI2_DownloaderAPI.cpp" />
+ <ClCompile Include="JSAPI2_ExternalObject.cpp" />
+ <ClCompile Include="JSAPI2_MediaCore.cpp" />
+ <ClCompile Include="JSAPI2_PlayerAPI.cpp" />
+ <ClCompile Include="JSAPI2_Security.cpp" />
+ <ClCompile Include="JSAPI2_SecurityAPI.cpp" />
+ <ClCompile Include="JSAPI2_SecurityPrompt.cpp" />
+ <ClCompile Include="JSAPI2_SkinAPI.cpp" />
+ <ClCompile Include="JSAPI2_TransportAPI.cpp" />
+ <ClCompile Include="JSAPI_CallbackParameters.cpp" />
+ <ClCompile Include="JSAPI_DispatchTable.cpp" />
+ <ClCompile Include="JSAPI_Info.cpp" />
+ <ClCompile Include="JUMP.cpp" />
+ <ClCompile Include="lang.cpp" />
+ <ClCompile Include="LazyServiceFactory.cpp" />
+ <ClCompile Include="linklist.cpp" />
+ <ClCompile Include="M3u.cpp" />
+ <ClCompile Include="main.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)4.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)4.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)4.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)4.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="main_buttons.cpp" />
+ <ClCompile Include="main_close.cpp" />
+ <ClCompile Include="main_command.cpp" />
+ <ClCompile Include="main_display.cpp" />
+ <ClCompile Include="main_init.cpp" />
+ <ClCompile Include="main_mouse.cpp" />
+ <ClCompile Include="main_nonclient.cpp" />
+ <ClCompile Include="main_timer.cpp" />
+ <ClCompile Include="main_wndproc.cpp" />
+ <ClCompile Include="MediaCoreCOM.cpp" />
+ <ClCompile Include="MemoryManager.cpp" />
+ <ClCompile Include="menuv5.cpp" />
+ <ClCompile Include="MergePlaylist.cpp" />
+ <ClCompile Include="Metadata.cpp" />
+ <ClCompile Include="metrics.cpp" />
+ <ClCompile Include="MoreItems.cpp" />
+ <ClCompile Include="ole.cpp" />
+ <ClCompile Include="OpenFileDialog.cpp" />
+ <ClCompile Include="Options.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)5.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)5.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)5.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)5.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="options_bookmarks.cpp" />
+ <ClCompile Include="options_classic.cpp" />
+ <ClCompile Include="options_dsp.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)6.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)6.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)6.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)6.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="options_filetypes.cpp" />
+ <ClCompile Include="options_gen.cpp" />
+ <ClCompile Include="options_general.cpp" />
+ <ClCompile Include="options_in.cpp" />
+ <ClCompile Include="options_lang.cpp" />
+ <ClCompile Include="options_output.cpp" />
+ <ClCompile Include="options_playback.cpp" />
+ <ClCompile Include="options_playlist.cpp" />
+ <ClCompile Include="options_plugins.cpp" />
+ <ClCompile Include="options_skin.cpp" />
+ <ClCompile Include="options_title.cpp" />
+ <ClCompile Include="options_video.cpp" />
+ <ClCompile Include="options_vis.cpp" />
+ <ClCompile Include="Out.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)7.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)7.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)7.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)7.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="OutputPluginAudioStream.cpp" />
+ <ClCompile Include="PaletteManager.cpp" />
+ <ClCompile Include="ParamList.cpp" />
+ <ClCompile Include="paths.cpp" />
+ <ClCompile Include="PathsINI.cpp" />
+ <ClCompile Include="peui.cpp" />
+ <ClCompile Include="Play.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)8.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)8.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)8.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename)8.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="PlaybackConfigGroup.cpp" />
+ <ClCompile Include="PlayList.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)%(Filename)9.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)%(Filename)9.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)%(Filename)9.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Wx64'">$(OutDir)%(Filename)9.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="PlayQueue.cpp" />
+ <ClCompile Include="Pledit.cpp" />
+ <ClCompile Include="Pls.cpp" />
+ <ClCompile Include="plush\cam.c" />
+ <ClCompile Include="plush\clip.c" />
+ <ClCompile Include="plush\light.c" />
+ <ClCompile Include="plush\make.c" />
+ <ClCompile Include="plush\mat.c" />
+ <ClCompile Include="plush\math.c" />
+ <ClCompile Include="plush\obj.c" />
+ <ClCompile Include="plush\pf_ptex.c" />
+ <ClCompile Include="plush\pf_tex.c" />
+ <ClCompile Include="plush\pf_trans.c" />
+ <ClCompile Include="plush\pf_solid.c" />
+ <ClCompile Include="plush\plush.c" />
+ <ClCompile Include="plush\render.c" />
+ <ClCompile Include="plush\spline.c" />
+ <ClCompile Include="plush\text.c" />
+ <ClCompile Include="precomp.cpp" />
+ <ClCompile Include="rand.cpp" />
+ <ClCompile Include="registry.cpp" />
+ <ClCompile Include="Resampler.cpp" />
+ <ClCompile Include="ResamplingReader.cpp" />
+ <ClCompile Include="Sa.cpp" />
+ <ClCompile Include="SABuffer.cpp" />
+ <ClCompile Include="SecurityCOM.cpp" />
+ <ClCompile Include="ServiceFactory.cpp" />
+ <ClCompile Include="ServiceManager.cpp" />
+ <ClCompile Include="Set.cpp" />
+ <ClCompile Include="setup\httpgrab.cpp" />
+ <ClCompile Include="setup\langutil.cpp" />
+ <ClCompile Include="setup\loadimage.cpp" />
+ <ClCompile Include="setup\postsetup.cpp" />
+ <ClCompile Include="setup\setup.cpp" />
+ <ClCompile Include="setup\setupfactory.cpp" />
+ <ClCompile Include="setup\sjob_register.cpp" />
+ <ClCompile Include="setup\skininfo.cpp" />
+ <ClCompile Include="setup\spage_assoc.cpp" />
+ <ClCompile Include="setup\spage_connect.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="setup\spage_feedback.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="setup\spage_lang.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="setup\spage_skin.cpp" />
+ <ClCompile Include="SHELL.CPP" />
+ <ClCompile Include="SkinBitmapElement.cpp" />
+ <ClCompile Include="SkinColorElement.cpp" />
+ <ClCompile Include="SkinCOM.cpp" />
+ <ClCompile Include="SkinCursorElement.cpp" />
+ <ClCompile Include="SkinElementAlias.cpp" />
+ <ClCompile Include="Skins.cpp" />
+ <ClCompile Include="SkinUtils.cpp" />
+ <ClCompile Include="skinWindow.cpp" />
+ <ClCompile Include="SPLASH.cpp" />
+ <ClCompile Include="stats.cpp" />
+ <ClCompile Include="strutil.cpp" />
+ <ClCompile Include="SysCallbacks.cpp" />
+ <ClCompile Include="SYSTRAY.cpp" />
+ <ClCompile Include="TagProvider.cpp" />
+ <ClCompile Include="tagz.cpp" />
+ <ClCompile Include="TempFileCOM.cpp" />
+ <ClCompile Include="TIMING.cpp" />
+ <ClCompile Include="Ui.cpp" />
+ <ClCompile Include="UnsignedAttribute.cpp" />
+ <ClCompile Include="updateService.cpp" />
+ <ClCompile Include="updateServicePopup.cpp" />
+ <ClCompile Include="UpdateWindow.cpp" />
+ <ClCompile Include="urlmanager.cpp" />
+ <ClCompile Include="util.cpp" />
+ <ClCompile Include="VersionCheck.cpp" />
+ <ClCompile Include="video.cpp" />
+ <ClCompile Include="VideoConfigGroup.cpp" />
+ <ClCompile Include="VideoOSD.cpp" />
+ <ClCompile Include="VideoOutput.cpp" />
+ <ClCompile Include="VideoOutputChild.cpp" />
+ <ClCompile Include="VideoOutputChildDDraw.cpp" />
+ <ClCompile Include="VideoPreferences.cpp" />
+ <ClCompile Include="videoui.cpp" />
+ <ClCompile Include="video_ipc.cpp" />
+ <ClCompile Include="vid_d3d.cpp" />
+ <ClCompile Include="vid_ddraw.cpp" />
+ <ClCompile Include="vid_none.cpp" />
+ <ClCompile Include="vid_overlay.cpp" />
+ <ClCompile Include="vid_subs.cpp" />
+ <ClCompile Include="Vis.cpp" />
+ <ClCompile Include="vu.cpp" />
+ <ClCompile Include="w5s.cpp" />
+ <ClCompile Include="WADrawDC.cpp" />
+ <ClCompile Include="Wasabi.cpp" />
+ <ClCompile Include="winampApi.cpp" />
+ <ClCompile Include="WinampAttributes.cpp" />
+ <ClCompile Include="WinampPlaylist.cpp" />
+ <ClCompile Include="wintheme.cpp" />
+ <ClCompile Include="wpz.cpp" />
+ <ClCompile Include="XMLString.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\Agave\ExplorerFindFile\api_explorerfindfile.h" />
+ <ClInclude Include="..\Agave\Language\api_language.h" />
+ <ClInclude Include="..\Agave\Language\lang.h" />
+ <ClInclude Include="..\Agave\Metadata\api_metadata.h" />
+ <ClInclude Include="..\Agave\Metadata\ifc_metadataReader.h" />
+ <ClInclude Include="..\Agave\Metadata\svc_metatag.h" />
+ <ClInclude Include="..\config\config.h" />
+ <ClInclude Include="..\Plugins\General\gen_crasher\GetWinVer.h" />
+ <ClInclude Include="..\Plugins\General\gen_ml\menu.h" />
+ <ClInclude Include="..\nu\AutoLock.h" />
+ <ClInclude Include="..\nu\ConfigCOM.h" />
+ <ClInclude Include="..\nu\HTMLContainer.h" />
+ <ClInclude Include="..\nu\threadpool\api_threadpool.h" />
+ <ClInclude Include="..\nu\threadpool\ThreadFunctions.h" />
+ <ClInclude Include="..\nu\threadpool\ThreadID.h" />
+ <ClInclude Include="..\nu\threadpool\ThreadPool.h" />
+ <ClInclude Include="..\nu\threadpool\threadpool_types.h" />
+ <ClInclude Include="..\Wasabi\api\application\api_application.h" />
+ <ClInclude Include="..\Wasabi\api\application\api_messageprocessor.h" />
+ <ClInclude Include="..\Wasabi\api\application\ifc_messageprocessor.h" />
+ <ClInclude Include="..\Wasabi\api\service\api_service.h" />
+ <ClInclude Include="..\Wasabi\api\skin\api_colorthemes.h" />
+ <ClInclude Include="..\Wasabi\api\skin\feeds\api_textfeed.h" />
+ <ClInclude Include="AccessibilityConfigGroup.h" />
+ <ClInclude Include="AdData.h" />
+ <ClInclude Include="api.h" />
+ <ClInclude Include="api_audiostream.h" />
+ <ClInclude Include="api_decodefile.h" />
+ <ClInclude Include="api_random.h" />
+ <ClInclude Include="api_stats.h" />
+ <ClInclude Include="api_urlmanager.h" />
+ <ClInclude Include="api_videopreferences.h" />
+ <ClInclude Include="api_winamp.h" />
+ <ClInclude Include="application.h" />
+ <ClInclude Include="ApplicationCOM.h" />
+ <ClInclude Include="AppRefCount.h" />
+ <ClInclude Include="attributes.h" />
+ <ClInclude Include="benskiQ\Biquad.h" />
+ <ClInclude Include="benskiQ\EqBand.h" />
+ <ClInclude Include="BookmarksCOM.h" />
+ <ClInclude Include="BurnManager.h" />
+ <ClInclude Include="commandLink.h" />
+ <ClInclude Include="CommonReader.h" />
+ <ClInclude Include="config.h" />
+ <ClInclude Include="CurrentSongCOM.h" />
+ <ClInclude Include="DataStoreCOM.h" />
+ <ClInclude Include="DecodeFile.h" />
+ <ClInclude Include="DeveloperConfigGroup.h" />
+ <ClInclude Include="directdraw.h" />
+ <ClInclude Include="dispatchCallback.h" />
+ <ClInclude Include="dpi.h" />
+ <ClInclude Include="draw.h" />
+ <ClInclude Include="dsp.h" />
+ <ClInclude Include="eq10dsp.h" />
+ <ClInclude Include="EQConfigGroup.h" />
+ <ClInclude Include="ExplorerFindFile.h" />
+ <ClInclude Include="ExtendedReader.h" />
+ <ClInclude Include="ExternalCOM.h" />
+ <ClInclude Include="FeedBase.h" />
+ <ClInclude Include="feeds.h" />
+ <ClInclude Include="FFT.H" />
+ <ClInclude Include="GammaFilter.h" />
+ <ClInclude Include="GammaManagerAPI.h" />
+ <ClInclude Include="gen.h" />
+ <ClInclude Include="handler.h" />
+ <ClInclude Include="in2.h" />
+ <ClInclude Include="InternetConfigGroup.h" />
+ <ClInclude Include="ipc_pe.h" />
+ <ClInclude Include="IVideoD3DOSD.h" />
+ <ClInclude Include="IWasabiDispatchable.h" />
+ <ClInclude Include="jnetcom.h" />
+ <ClInclude Include="JSAPI.h" />
+ <ClInclude Include="JSAPI2_api_security.h" />
+ <ClInclude Include="JSAPI2_Application.h" />
+ <ClInclude Include="JSAPI2_AsyncDownloader.h" />
+ <ClInclude Include="JSAPI2_Bookmarks.h" />
+ <ClInclude Include="JSAPI2_CallbackManager.h" />
+ <ClInclude Include="JSAPI2_Creator.h" />
+ <ClInclude Include="JSAPI2_Downloader.h" />
+ <ClInclude Include="JSAPI2_ExternalObject.h" />
+ <ClInclude Include="JSAPI2_MediaCore.h" />
+ <ClInclude Include="JSAPI2_PlayerAPI.h" />
+ <ClInclude Include="JSAPI2_Security.h" />
+ <ClInclude Include="JSAPI2_SecurityAPI.h" />
+ <ClInclude Include="JSAPI2_SkinAPI.h" />
+ <ClInclude Include="JSAPI2_svc_apicreator.h" />
+ <ClInclude Include="JSAPI2_TransportAPI.h" />
+ <ClInclude Include="JSAPI_CallbackParameters.h" />
+ <ClInclude Include="JSAPI_DispatchTable.h" />
+ <ClInclude Include="JSAPI_Info.h" />
+ <ClInclude Include="language.h" />
+ <ClInclude Include="LazyServiceFactory.h" />
+ <ClInclude Include="Main.h" />
+ <ClInclude Include="main.hpp" />
+ <ClInclude Include="MediaCoreCOM.h" />
+ <ClInclude Include="MemoryManager.h" />
+ <ClInclude Include="MergePlaylist.h" />
+ <ClInclude Include="Metadata.h" />
+ <ClInclude Include="MoreItems.h" />
+ <ClInclude Include="Options.h" />
+ <ClInclude Include="out.h" />
+ <ClInclude Include="OutputPluginAudioStream.h" />
+ <ClInclude Include="PaletteManager.h" />
+ <ClInclude Include="ParamList.h" />
+ <ClInclude Include="PlaybackConfigGroup.h" />
+ <ClInclude Include="Playlist.h" />
+ <ClInclude Include="precomp.h" />
+ <ClInclude Include="random.h" />
+ <ClInclude Include="Resampler.h" />
+ <ClInclude Include="ResamplingReader.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SecurityCOM.h" />
+ <ClInclude Include="ServiceManager.h" />
+ <ClInclude Include="setup\httpgrab.h" />
+ <ClInclude Include="setup\ifc_setupjob.h" />
+ <ClInclude Include="setup\ifc_setuppage.h" />
+ <ClInclude Include="setup\langutil.h" />
+ <ClInclude Include="setup\loadimage.h" />
+ <ClInclude Include="setup\postsetup.h" />
+ <ClInclude Include="setup\resource.h" />
+ <ClInclude Include="setup\setup.h" />
+ <ClInclude Include="setup\setupcommon.h" />
+ <ClInclude Include="setup\setupfactory.h" />
+ <ClInclude Include="setup\setup_api.h" />
+ <ClInclude Include="setup\setup_resource.h" />
+ <ClInclude Include="setup\sjob_register.h" />
+ <ClInclude Include="setup\skininfo.h" />
+ <ClInclude Include="setup\spage_assoc.h" />
+ <CustomBuild Include="setup\spage_connect.h">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </CustomBuild>
+ <CustomBuild Include="setup\spage_feedback.h">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </CustomBuild>
+ <CustomBuild Include="setup\spage_lang.h">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ </CustomBuild>
+ <ClInclude Include="setup\spage_skin.h" />
+ <ClInclude Include="setup\svc_setup.h" />
+ <ClInclude Include="Singleton.h" />
+ <ClInclude Include="SkinBitmapElement.h" />
+ <ClInclude Include="SkinColorElement.h" />
+ <ClInclude Include="SkinCOM.h" />
+ <ClInclude Include="SkinCursorElement.h" />
+ <ClInclude Include="SkinElementAlias.h" />
+ <ClInclude Include="skinWindow.h" />
+ <ClInclude Include="skinWindowIPC.h" />
+ <ClInclude Include="stats.h" />
+ <ClInclude Include="strutil.h" />
+ <ClInclude Include="SysCallbacks.h" />
+ <ClInclude Include="TagProvider.h" />
+ <ClInclude Include="tagz.h" />
+ <ClInclude Include="TempFileCOM.h" />
+ <ClInclude Include="TIMING.H" />
+ <ClInclude Include="updateService.h" />
+ <ClInclude Include="urlmanager.h" />
+ <ClInclude Include="video.h" />
+ <ClInclude Include="VideoAspectAdjuster.h" />
+ <ClInclude Include="VideoConfigGroup.h" />
+ <ClInclude Include="VideoFeedFactory.h" />
+ <ClInclude Include="VideoOSD.h" />
+ <ClInclude Include="VideoOutput.h" />
+ <ClInclude Include="VideoOutputChild.h" />
+ <ClInclude Include="VideoOutputChildDDraw.h" />
+ <ClInclude Include="vid_d3d.h" />
+ <ClInclude Include="vid_ddraw.h" />
+ <ClInclude Include="vid_none.h" />
+ <ClInclude Include="vid_overlay.h" />
+ <ClInclude Include="vid_subs.h" />
+ <ClInclude Include="vis.h" />
+ <ClInclude Include="w5s.h" />
+ <ClInclude Include="WADrawDC.h" />
+ <ClInclude Include="Wasabi.h" />
+ <ClInclude Include="wasabicfg.h" />
+ <ClInclude Include="wa_ipc.h" />
+ <ClInclude Include="winampApi.h" />
+ <ClInclude Include="WinampAttributes.h" />
+ <ClInclude Include="WinampPlaylist.h" />
+ <ClInclude Include="wintheme.h" />
+ <ClInclude Include="XMLString.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="resource\atf.htm">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
+ <None Include="resource\cur00001.cur" />
+ <None Include="resource\danger.cur" />
+ <None Include="resource\danger1.cur" />
+ <None Include="resource\lrscroll.cur" />
+ <None Include="resource\move.cur" />
+ <None Include="resource\resize.cur" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resource\balance.bmp" />
+ <Image Include="resource\beta.bmp" />
+ <Image Include="resource\cbuttons.bmp" />
+ <Image Include="resource\djegg.bmp" />
+ <Image Include="resource\embwnd.bmp" />
+ <Image Include="resource\eqmain.bmp" />
+ <Image Include="resource\Eqmain_ISO.bmp" />
+ <Image Include="RESOURCE\eq_ex.bmp" />
+ <Image Include="resource\gen.bmp" />
+ <Image Include="resource\genex.bmp" />
+ <Image Include="resource\ICON1.ICO" />
+ <Image Include="resource\ICON10.ICO" />
+ <Image Include="resource\Icon11.ico" />
+ <Image Include="resource\ICON12.ICO" />
+ <Image Include="resource\icon13.ico" />
+ <Image Include="resource\Icon2.ico" />
+ <Image Include="resource\ICON3.ICO" />
+ <Image Include="resource\Icon5.ico" />
+ <Image Include="resource\ICON6.ICO" />
+ <Image Include="resource\ICON7.ICO" />
+ <Image Include="resource\ICON8.ICO" />
+ <Image Include="resource\ICON9.ICO" />
+ <Image Include="resource\main.bmp" />
+ <Image Include="RESOURCE\mb.bmp" />
+ <Image Include="resource\MONOSTER.BMP" />
+ <Image Include="resource\numbers.bmp" />
+ <Image Include="resource\OSD-Sprite-Controls.png" />
+ <Image Include="resource\PLAYPAUS.BMP" />
+ <Image Include="resource\pledit.bmp" />
+ <Image Include="resource\POSBAR.BMP" />
+ <Image Include="resource\shufrep.bmp" />
+ <Image Include="resource\splash2.bmp" />
+ <Image Include="resource\TBICON1.ico" />
+ <Image Include="resource\TBICON2.ico" />
+ <Image Include="resource\TBICON3.ico" />
+ <Image Include="resource\TBICON4.ico" />
+ <Image Include="resource\TBICON5.ico" />
+ <Image Include="resource\team.bmp" />
+ <Image Include="resource\text.bmp" />
+ <Image Include="resource\titlebar.bmp" />
+ <Image Include="resource\uninstallwa.ico" />
+ <Image Include="resource\video.bmp" />
+ <Image Include="resource\video_logo.bmp" />
+ <Image Include="resource\volbar.bmp" />
+ <Image Include="resource\volume.bmp" />
+ <Image Include="resource\WinampIcon.ico" />
+ <Image Include="setup\checkbox.bmp" />
+ <Image Include="setup\headerstrip.bmp" />
+ <Image Include="setup\navitemstrip.bmp" />
+ <Image Include="setup\navstrip.bmp" />
+ <Image Include="setup\preview_classic.png" />
+ <Image Include="setup\preview_no.png" />
+ <Image Include="setup\smokingllama.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Text Include="resource\cmdline.txt" />
+ <Text Include="resource\tips.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <Xml Include="manifest.xml" />
+ <Xml Include="manifest64.xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="setup\setup.rc" />
+ <ResourceCompile Include="Winamp.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Winamp/winampv6.vcxproj.filters b/Src/Winamp/winampv6.vcxproj.filters
new file mode 100644
index 00000000..4f88226c
--- /dev/null
+++ b/Src/Winamp/winampv6.vcxproj.filters
@@ -0,0 +1,1497 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="About.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AccessibilityConfigGroup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AdData.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AlbumArtRetrieval.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Agave\Metadata\api_metadata.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="api_videopreferences.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="application.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ApplicationCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AppRefCount.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="benskiQ\Biquad.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="benskiQ\benskiQ.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="bm.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BookmarksCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BoolAttribute.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BrowserCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="burn.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BurnManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\cam.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="classic_vis.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\clip.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="cmdline.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="commandLink.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\config\config.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Config.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\ConfigCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="conversions.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="convert.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="CurrentSongCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DataStoreCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="creditsrend.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DecodeFile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DeveloperConfigGroup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dispatchCallback.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dock.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dpi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Draw.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="draw_embed.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="draw_eq.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="draw_main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="draw_mb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="draw_pe.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="draw_sa.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="draw_vw.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dsp.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dwm.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="embwnd.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Eq.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="eq10dsp.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="benskiQ\EqBand.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="EQConfigGroup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Equi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ExplorerFindFile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ExtendedInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ExtendedReader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ExternalCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="FeedBase.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="feeds.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Fft.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="FileInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Elevator\FileTypeRegistrar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="FloatAttribute.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="fullscreen.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="GammaFilter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="GammaManagerAPI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="gen.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="handler.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="html.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\HTMLContainer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Http.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\httpgrab.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="HTTPRetrieveFile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="In.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="install.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IntAttribute.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="InternetConfigGroup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="InW.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ipc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IVideoD3DOSD.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jnetcom.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI_CallbackParameters.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI_DispatchTable.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI_Info.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_Application.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_AsyncDownloader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_Bookmarks.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_CallbackManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_Creator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_DownloaderAPI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_ExternalObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_MediaCore.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_PlayerAPI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_Security.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_SecurityAPI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_SecurityPrompt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_SkinAPI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JSAPI2_TransportAPI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JUMP.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lang.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\langutil.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="LazyServiceFactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\light.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="linklist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\loadimage.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="M3u.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_buttons.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_close.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_command.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_display.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_init.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_mouse.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_video.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ole.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="OpenFileDialog.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_bookmarks.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_classic.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_dsp.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_filetypes.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_gen.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_general.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_in.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_lang.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_output.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_playback.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_playlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_plugins.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_skin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_title.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\obj.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MoreItems.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="metrics.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Metadata.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MergePlaylist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="menuv5.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MemoryManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MediaCoreCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\math.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\mat.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_wndproc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_timer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main_nonclient.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Out.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="OutputPluginAudioStream.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PaletteManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ParamList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="paths.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PathsINI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="peui.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Play.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PlaybackConfigGroup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PlayList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PlayQueue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Pledit.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Pls.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\plush.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\postsetup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precomp.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\make.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options_vis.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\pf_ptex.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\pf_solid.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\pf_tex.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\pf_trans.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rand.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="registry.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\render.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Resampler.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ResamplingReader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Sa.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SABuffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SecurityCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ServiceFactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ServiceManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\ServiceWatcher.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Set.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\setup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\setupfactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SHELL.CPP">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\sjob_register.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SkinBitmapElement.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SkinColorElement.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SkinCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SkinCursorElement.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SkinElementAlias.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\skininfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Wasabi\api\skin\skinitem.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Skins.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SkinUtils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="skinWindow.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\spage_assoc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\spage_connect.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\spage_feedback.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\spage_lang.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="setup\spage_skin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SPLASH.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\spline.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stats.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="strutil.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SysCallbacks.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Wasabi\api\syscb\callbacks\syscbx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SYSTRAY.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="TagProvider.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="tagz.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="TempFileCOM.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="plush\text.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\threadpool\ThreadFunctions.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\threadpool\ThreadID.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\threadpool\ThreadPool.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="TIMING.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\trace.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Ui.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="UnsignedAttribute.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="updateService.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="updateServicePopup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="UpdateWindow.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="urlmanager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VersionCheck.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="vid_d3d.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="vid_ddraw.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="vid_none.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="vid_overlay.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="vid_subs.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="video.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="video_ipc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="XMLString.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wpz.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wintheme.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="WinampPlaylist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="WinampAttributes.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="winampApi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Wasabi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="WADrawDC.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="w5s.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="vu.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Vis.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="videoui.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VideoPreferences.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VideoOutputChildDDraw.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VideoOutputChild.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VideoOutput.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VideoOSD.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VideoConfigGroup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="../Plugins/Library/ml_bookmarks\bookmark.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Plugins\General\gen_crasher\GetWinVer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Plugins\General\gen_ml\menu.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Plugins\General\gen_ml\ml_lib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="AccessibilityConfigGroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="AdData.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="application.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ApplicationCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="AppRefCount.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="attributes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\AutoLock.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="benskiQ\Biquad.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BookmarksCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BurnManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="commandLink.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="CommonReader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\config\config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\ConfigCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="CurrentSongCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DataStoreCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DecodeFile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DeveloperConfigGroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="directdraw.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dispatchCallback.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dpi.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="draw.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="eq10dsp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="benskiQ\EqBand.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="EQConfigGroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ExplorerFindFile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ExtendedReader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ExternalCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="FeedBase.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="feeds.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="FFT.H">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="GammaFilter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="GammaManagerAPI.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="handler.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\HTMLContainer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\httpgrab.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Wasabi\api\application\ifc_messageprocessor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Agave\Metadata\ifc_metadataReader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\ifc_setupjob.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\ifc_setuppage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="InternetConfigGroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ipc_pe.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="IVideoD3DOSD.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="IWasabiDispatchable.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jnetcom.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI_CallbackParameters.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI_DispatchTable.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI_Info.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_api_security.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_Application.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_AsyncDownloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_Bookmarks.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_CallbackManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_Creator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_Downloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_ExternalObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_MediaCore.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_PlayerAPI.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_Security.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_SecurityAPI.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_SkinAPI.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_svc_apicreator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JSAPI2_TransportAPI.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Agave\Language\lang.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="language.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\langutil.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="LazyServiceFactory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\loadimage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MediaCoreCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MemoryManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MergePlaylist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Metadata.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MoreItems.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Options.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="OutputPluginAudioStream.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PaletteManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ParamList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PlaybackConfigGroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Playlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\postsetup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="precomp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="random.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Resampler.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ResamplingReader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SecurityCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ServiceManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\setup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\setup_api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\setupfactory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\setupcommon.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\setup_resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\sjob_register.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SkinBitmapElement.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Singleton.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SkinColorElement.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SkinCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SkinCursorElement.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SkinElementAlias.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\skininfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skinWindow.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skinWindowIPC.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\spage_assoc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\spage_skin.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="stats.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="strutil.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Agave\Metadata\svc_metatag.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="setup\svc_setup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SysCallbacks.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="TagProvider.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="tagz.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="TempFileCOM.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\threadpool\ThreadFunctions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\threadpool\ThreadID.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\threadpool\ThreadPool.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\threadpool\threadpool_types.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="TIMING.H">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="updateService.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="urlmanager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="vid_d3d.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="vid_ddraw.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="vid_none.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="vid_overlay.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="vid_subs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="XMLString.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wintheme.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="WinampPlaylist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="WinampAttributes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="winampApi.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wasabicfg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Wasabi.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="WADrawDC.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wa_ipc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VideoOutputChildDDraw.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VideoOutputChild.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VideoOutput.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VideoOSD.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VideoFeedFactory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VideoConfigGroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VideoAspectAdjuster.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="video.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Plugins\General\gen_crasher\GetWinVer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Plugins\General\gen_ml\menu.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dsp.h">
+ <Filter>Header Files\Plugins</Filter>
+ </ClInclude>
+ <ClInclude Include="gen.h">
+ <Filter>Header Files\Plugins</Filter>
+ </ClInclude>
+ <ClInclude Include="in2.h">
+ <Filter>Header Files\Plugins</Filter>
+ </ClInclude>
+ <ClInclude Include="out.h">
+ <Filter>Header Files\Plugins</Filter>
+ </ClInclude>
+ <ClInclude Include="vis.h">
+ <Filter>Header Files\Plugins</Filter>
+ </ClInclude>
+ <ClInclude Include="w5s.h">
+ <Filter>Header Files\Plugins</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Wasabi\api\application\api_application.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api_audiostream.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Wasabi\api\skin\api_colorthemes.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api_decodefile.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Agave\ExplorerFindFile\api_explorerfindfile.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Agave\Language\api_language.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Wasabi\api\application\api_messageprocessor.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Agave\Metadata\api_metadata.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api_random.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Wasabi\api\service\api_service.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api_stats.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Wasabi\api\skin\feeds\api_textfeed.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\threadpool\api_threadpool.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api_urlmanager.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api_videopreferences.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api_winamp.h">
+ <Filter>Header Files\api</Filter>
+ </ClInclude>
+ <ClInclude Include="api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="setup\spage_connect.h">
+ <Filter>Header Files</Filter>
+ </CustomBuild>
+ <CustomBuild Include="setup\spage_feedback.h">
+ <Filter>Header Files</Filter>
+ </CustomBuild>
+ <CustomBuild Include="setup\spage_lang.h">
+ <Filter>Header Files</Filter>
+ </CustomBuild>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="setup\setup.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="Winamp.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Xml Include="manifest.xml">
+ <Filter>Ressource Files</Filter>
+ </Xml>
+ <Xml Include="manifest64.xml">
+ <Filter>Ressource Files</Filter>
+ </Xml>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resource\beta.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\balance.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\cbuttons.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="setup\checkbox.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\djegg.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\eqmain.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="RESOURCE\eq_ex.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\genex.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\gen.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\Eqmain_ISO.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\embwnd.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON1.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\Icon2.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON3.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\Icon5.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON6.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON7.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON8.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON9.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON10.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\Icon11.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\ICON12.ICO">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\icon13.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="setup\headerstrip.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="setup\navitemstrip.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="setup\navstrip.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\numbers.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\main.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="RESOURCE\mb.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\MONOSTER.BMP">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\PLAYPAUS.BMP">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\pledit.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\OSD-Sprite-Controls.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\POSBAR.BMP">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="setup\preview_classic.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="setup\preview_no.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="setup\smokingllama.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\shufrep.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\splash2.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\uninstallwa.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\titlebar.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\text.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\team.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\TBICON5.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\TBICON4.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\TBICON3.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\TBICON2.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\TBICON1.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\WinampIcon.ico">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\volume.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\volbar.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\video_logo.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resource\video.bmp">
+ <Filter>Image Files</Filter>
+ </Image>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="resource\atf.htm" />
+ <None Include="resource\cur00001.cur">
+ <Filter>Image Files</Filter>
+ </None>
+ <None Include="resource\danger.cur">
+ <Filter>Image Files</Filter>
+ </None>
+ <None Include="resource\danger1.cur">
+ <Filter>Image Files</Filter>
+ </None>
+ <None Include="resource\move.cur">
+ <Filter>Image Files</Filter>
+ </None>
+ <None Include="resource\lrscroll.cur">
+ <Filter>Image Files</Filter>
+ </None>
+ <None Include="resource\resize.cur">
+ <Filter>Image Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Text Include="resource\cmdline.txt" />
+ <Text Include="resource\tips.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{80c86a23-eaa3-463a-85d0-77aba14ed204}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{44fea055-607a-4cf1-8556-ec4c1c18a3cf}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{47312752-614b-4bd3-b9b6-ba4af5a26115}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Image Files">
+ <UniqueIdentifier>{e0b33a8f-33dc-43e4-a974-d263d3bb5f85}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\Plugins">
+ <UniqueIdentifier>{b78c19c5-fa4c-43bb-9f50-37610df8749a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\api">
+ <UniqueIdentifier>{09e96e4b-4596-4e5c-9685-64c7e6c8d0b5}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Winamp/wintheme.cpp b/Src/Winamp/wintheme.cpp
new file mode 100644
index 00000000..ddd5e9fa
--- /dev/null
+++ b/Src/Winamp/wintheme.cpp
@@ -0,0 +1,93 @@
+#include "main.h"
+#include "./wintheme.h"
+
+
+typedef HRESULT(WINAPI *UXTHEME_SETWINDOWTHEME)(HWND /*hwnd*/, LPCWSTR /*pszSubAppName*/, LPCWSTR /*pszSubIdList*/);
+typedef BOOL (WINAPI *UXTHEME_ISAPPTHEMED)(void);
+typedef HRESULT (WINAPI *DWM_SETWINDOWATTRIBUTE)(HWND /*hwnd*/, DWORD /*dwAttribute*/, LPCVOID /*pvAttribute*/, DWORD /*cbAttribute*/);
+typedef HRESULT (WINAPI *DWM_ISCOMPOSITIONENABLED)(BOOL* /*pfEnabled*/);
+
+
+static DWM_SETWINDOWATTRIBUTE fnSetWindowAttribute = NULL;
+static DWM_ISCOMPOSITIONENABLED fnIsCompositionEnabled = NULL;
+static UXTHEME_SETWINDOWTHEME fnSetWindowTheme = NULL;
+static UXTHEME_ISAPPTHEMED fnIsAppThemed = NULL;
+
+static HMODULE hDwmModule = NULL;
+static HMODULE hUxThemeModule = NULL;
+static HRESULT loadDwmResult = E_LIBRARY_NOTLOADED;
+static HRESULT loadUxThemeResult = E_LIBRARY_NOTLOADED;
+
+HRESULT UxTheme_LoadLibrary(void)
+{
+ if (E_LIBRARY_NOTLOADED == loadUxThemeResult)
+ {
+ hUxThemeModule = LoadLibraryW(L"uxtheme.dll");
+ if (!hUxThemeModule) loadUxThemeResult = E_LIBRARY_LOADFAILED;
+ else
+ {
+ fnSetWindowTheme = (UXTHEME_SETWINDOWTHEME)GetProcAddress(hUxThemeModule, "SetWindowTheme");
+ fnIsAppThemed = (UXTHEME_ISAPPTHEMED)GetProcAddress(hUxThemeModule, "IsAppThemed");
+ loadUxThemeResult = S_OK;
+ }
+ }
+ return loadUxThemeResult;
+}
+
+HRESULT Dwm_LoadLibrary(void)
+{
+ if (E_LIBRARY_NOTLOADED == loadDwmResult)
+ {
+ hDwmModule = LoadLibraryW(L"dwmapi.dll");
+ if (!hDwmModule) loadDwmResult = E_LIBRARY_LOADFAILED;
+ else
+ {
+ fnSetWindowAttribute = (DWM_SETWINDOWATTRIBUTE)GetProcAddress(hDwmModule, "DwmSetWindowAttribute");
+ fnIsCompositionEnabled = (DWM_ISCOMPOSITIONENABLED)GetProcAddress(hDwmModule, "DwmIsCompositionEnabled");
+ loadDwmResult = S_OK;
+ }
+ }
+ return loadDwmResult;
+}
+
+HRESULT UxTheme_GetLoadResult(void)
+{
+ return loadUxThemeResult;
+}
+
+HRESULT Dwm_GetLoadResult()
+{
+ return loadDwmResult;
+}
+
+
+HRESULT SetWindowTheme(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList)
+{
+ if (!hUxThemeModule) return loadUxThemeResult;
+ if (!fnSetWindowTheme) return E_LIBRARY_BADFUNCTION;
+ return fnSetWindowTheme(hwnd, pszSubAppName, pszSubIdList);
+}
+BOOL IsAppThemed(void)
+{
+ if (!hUxThemeModule) return FALSE;
+ if (!fnIsAppThemed) return FALSE;
+ return fnIsAppThemed();
+}
+
+
+
+
+
+HRESULT DwmSetWindowAttribute(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute)
+{
+ if (!hDwmModule) return loadDwmResult;
+ if (!fnSetWindowAttribute) return E_LIBRARY_BADFUNCTION;
+ return fnSetWindowAttribute(hwnd, dwAttribute, pvAttribute, cbAttribute);
+}
+
+HRESULT DwmIsCompositionEnabled(BOOL *pfEnabled)
+{
+ if (!hDwmModule) return loadDwmResult;
+ if (!fnIsCompositionEnabled) return E_LIBRARY_BADFUNCTION;
+ return fnIsCompositionEnabled(pfEnabled);
+}
diff --git a/Src/Winamp/wintheme.h b/Src/Winamp/wintheme.h
new file mode 100644
index 00000000..a399fd81
--- /dev/null
+++ b/Src/Winamp/wintheme.h
@@ -0,0 +1,59 @@
+#ifndef NULLOSFT_WINAMP_WINTHEME_HEADER
+#define NULLOSFT_WINAMP_WINTHEME_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#define E_LIBRARY_NOTLOADED MAKE_HRESULT(0, FACILITY_ITF, 0x0201) // library not loaded (you just need to call MlDwm_LoadLibrary)
+#define E_LIBRARY_LOADFAILED MAKE_HRESULT(1, FACILITY_ITF, 0x0202) // library load failed (probably not vista?)
+#define E_LIBRARY_BADFUNCTION MAKE_HRESULT(1, FACILITY_ITF, 0x0203) // function was not loaded
+
+// XP UxTheme
+HRESULT UxTheme_LoadLibrary(void);
+HRESULT UxTheme_GetLoadResult(void);
+
+HRESULT SetWindowTheme(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList);
+BOOL IsAppThemed(void);
+
+// Vista DWM
+
+HRESULT Dwm_LoadLibrary(void);
+HRESULT Dwm_GetLoadResult(void);
+
+#ifndef WM_DWMCOMPOSITIONCHANGED
+#define WM_DWMCOMPOSITIONCHANGED 0x031E
+#define WM_DWMNCRENDERINGCHANGED 0x031F
+#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
+#define WM_DWMWINDOWMAXIMIZEDCHANGE 0x0321
+#endif // !WM_DWMCOMPOSITIONCHANGED
+
+typedef enum _DWMWINDOWATTRIBUTE {
+ DWMWA_NCRENDERING_ENABLED = 1,
+ DWMWA_NCRENDERING_POLICY,
+ DWMWA_TRANSITIONS_FORCEDISABLED,
+ DWMWA_ALLOW_NCPAINT,
+ DWMWA_CAPTION_BUTTON_BOUNDS,
+ DWMWA_NONCLIENT_RTL_LAYOUT,
+ DWMWA_FORCE_ICONIC_REPRESENTATION,
+ DWMWA_FLIP3D_POLICY,
+ DWMWA_EXTENDED_FRAME_BOUNDS,
+ DWMWA_HAS_ICONIC_BITMAP, // [set] Indicates an available bitmap when there is no better thumbnail representation.
+ DWMWA_DISALLOW_PEEK, // [set] Don't invoke Peek on the window.
+ DWMWA_EXCLUDED_FROM_PEEK,
+ DWMWA_LAST
+} DWMWINDOWATTRIBUTE;
+
+typedef enum _DWMNCRENDERINGPOLICY {
+ DWMNCRP_USEWINDOWSTYLE,
+ DWMNCRP_DISABLED,
+ DWMNCRP_ENABLED,
+ DWMNCRP_LAST
+} DWMNCRENDERINGPOLICY;
+
+HRESULT DwmSetWindowAttribute(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
+HRESULT DwmIsCompositionEnabled(BOOL *pfEnabled);
+
+#endif //NULLOSFT_WINAMP_WINTHEME_HEADER \ No newline at end of file
diff --git a/Src/Winamp/wpl.cpp b/Src/Winamp/wpl.cpp
new file mode 100644
index 00000000..48c721bc
--- /dev/null
+++ b/Src/Winamp/wpl.cpp
@@ -0,0 +1,8 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+#include "main.h"
diff --git a/Src/Winamp/wpl.h b/Src/Winamp/wpl.h
new file mode 100644
index 00000000..31d124cb
--- /dev/null
+++ b/Src/Winamp/wpl.h
@@ -0,0 +1,4 @@
+#ifndef NULLSOFT_WINAMP_WPL_H
+#define NULLSOFT_WINAMP_WPL_H
+
+#endif \ No newline at end of file
diff --git a/Src/Winamp/wpz.cpp b/Src/Winamp/wpz.cpp
new file mode 100644
index 00000000..fa3b7fab
--- /dev/null
+++ b/Src/Winamp/wpz.cpp
@@ -0,0 +1,10 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author:
+ ** Created:
+ **/
+
+#include "main.h"
+