/******************************************************************************** Copyright (C) 2012 Hugh Bailey This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ********************************************************************************/ #include "Main.h" #include #include //primarily main window stuff an initialization/destruction code typedef bool (*LOADPLUGINPROC)(); typedef void (*UNLOADPLUGINPROC)(); ImageSource* STDCALL CreateDesktopSource(XElement *data); bool STDCALL ConfigureDesktopSource(XElement *data, bool bCreating); ImageSource* STDCALL CreateBitmapSource(XElement *data); bool STDCALL ConfigureBitmapSource(XElement *element, bool bCreating); ImageSource* STDCALL CreateBitmapTransitionSource(XElement *data); bool STDCALL ConfigureBitmapTransitionSource(XElement *element, bool bCreating); ImageSource* STDCALL CreateTextSource(XElement *data); bool STDCALL ConfigureTextSource(XElement *element, bool bCreating); ImageSource* STDCALL CreateGlobalSource(XElement *data); void STDCALL SceneHotkey(DWORD hotkey, UPARAM param, bool bDown); APIInterface* CreateOBSApiInterface(); #define QuickClearHotkey(hotkeyID) \ if(hotkeyID) \ { \ API->DeleteHotkey(hotkeyID); \ hotkeyID = NULL; \ } //---------------------------- WNDPROC listboxProc = NULL; WNDPROC listviewProc = NULL; //---------------------------- const float defaultBlendFactor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; //---------------------------- BOOL CALLBACK MonitorInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, List &monitors) { monitors << MonitorInfo(hMonitor, lprcMonitor); return TRUE; } const int controlPadding = 3; const int totalControlAreaWidth = minClientWidth; const int miscAreaWidth = 290; const int totalControlAreaHeight = 171;//170;// const int listAreaWidth = totalControlAreaWidth-miscAreaWidth; const int controlWidth = miscAreaWidth/2; const int controlHeight = 22; const int volControlHeight = 32; const int volMeterHeight = 10; const int textControlHeight = 16; const int listControlWidth = listAreaWidth/2; Scene* STDCALL CreateNormalScene(XElement *data) { return new Scene; } OBS::OBS() { App = this; __cpuid(cpuInfo, 1); bSSE2Available = (cpuInfo[3] & (1<<26)) != 0; hSceneMutex = OSCreateMutex(); hAuxAudioMutex = OSCreateMutex(); monitors.Clear(); EnumDisplayMonitors(NULL, NULL, (MONITORENUMPROC)MonitorInfoEnumProc, (LPARAM)&monitors); INITCOMMONCONTROLSEX ecce; ecce.dwSize = sizeof(ecce); ecce.dwICC = ICC_STANDARD_CLASSES; if(!InitCommonControlsEx(&ecce)) CrashError(TEXT("Could not initalize common shell controls")); InitHotkeyExControl(hinstMain); InitColorControl(hinstMain); InitVolumeControl(); InitVolumeMeter(); //----------------------------------------------------- // load locale if(!locale->LoadStringFile(TEXT("locale/en.txt"))) AppWarning(TEXT("Could not open locale string file '%s'"), TEXT("locale/en.txt")); strLanguage = GlobalConfig->GetString(TEXT("General"), TEXT("Language"), TEXT("en")); if(!strLanguage.CompareI(TEXT("en"))) { String langFile; langFile << TEXT("locale/") << strLanguage << TEXT(".txt"); if(!locale->LoadStringFile(langFile)) AppWarning(TEXT("Could not open locale string file '%s'"), langFile.Array()); } //----------------------------------------------------- // load classes RegisterSceneClass(TEXT("Scene"), Str("Scene"), (OBSCREATEPROC)CreateNormalScene, NULL); RegisterImageSourceClass(TEXT("DesktopImageSource"), Str("Sources.SoftwareCaptureSource"), (OBSCREATEPROC)CreateDesktopSource, (OBSCONFIGPROC)ConfigureDesktopSource); RegisterImageSourceClass(TEXT("BitmapImageSource"), Str("Sources.BitmapSource"), (OBSCREATEPROC)CreateBitmapSource, (OBSCONFIGPROC)ConfigureBitmapSource); RegisterImageSourceClass(TEXT("BitmapTransitionSource"), Str("Sources.TransitionSource"), (OBSCREATEPROC)CreateBitmapTransitionSource, (OBSCONFIGPROC)ConfigureBitmapTransitionSource); RegisterImageSourceClass(TEXT("GlobalSource"), Str("Sources.GlobalSource"), (OBSCREATEPROC)CreateGlobalSource, (OBSCONFIGPROC)OBS::ConfigGlobalSource); RegisterImageSourceClass(TEXT("TextSource"), Str("Sources.TextSource"), (OBSCREATEPROC)CreateTextSource, (OBSCONFIGPROC)ConfigureTextSource); //----------------------------------------------------- // render frame class WNDCLASS wc; zero(&wc, sizeof(wc)); wc.hInstance = hinstMain; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = OBS_RENDERFRAME_CLASS; wc.lpfnWndProc = (WNDPROC)OBS::RenderFrameProc; wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); if(!RegisterClass(&wc)) CrashError(TEXT("Could not register render frame class")); //----------------------------------------------------- // main window class wc.lpszClassName = OBS_WINDOW_CLASS; wc.lpfnWndProc = (WNDPROC)OBSProc; wc.hIcon = LoadIcon(hinstMain, MAKEINTRESOURCE(IDI_ICON1)); wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); if(!RegisterClass(&wc)) CrashError(TEXT("Could not register main window class")); //----------------------------------------------------- // create main window int fullscreenX = GetSystemMetrics(SM_CXFULLSCREEN); int fullscreenY = GetSystemMetrics(SM_CYFULLSCREEN); borderXSize = borderYSize = 0; borderXSize += GetSystemMetrics(SM_CXSIZEFRAME)*2; borderYSize += GetSystemMetrics(SM_CYSIZEFRAME)*2; borderYSize += GetSystemMetrics(SM_CYMENU); borderYSize += GetSystemMetrics(SM_CYCAPTION); clientWidth = GlobalConfig->GetInt(TEXT("General"), TEXT("Width"), 700); clientHeight = GlobalConfig->GetInt(TEXT("General"), TEXT("Height"), 553); if(clientWidth < minClientWidth) clientWidth = minClientWidth; if(clientHeight < minClientHeight) clientHeight = minClientHeight; int maxCX = fullscreenX-borderXSize; int maxCY = fullscreenY-borderYSize; if(clientWidth > maxCX) clientWidth = maxCX; if(clientHeight > maxCY) clientHeight = maxCY; int cx = clientWidth + borderXSize; int cy = clientHeight + borderYSize; int x = (fullscreenX/2)-(cx/2); int y = (fullscreenY/2)-(cy/2); int posX = GlobalConfig->GetInt(TEXT("General"), TEXT("PosX")); int posY = GlobalConfig->GetInt(TEXT("General"), TEXT("PosY")); bool bInsideMonitors = false; if(posX || posY) { for(UINT i=0; i= monitors[i].rect.left && posX < monitors[i].rect.right && posY >= monitors[i].rect.top && posY < monitors[i].rect.bottom ) { bInsideMonitors = true; break; } } } if(bInsideMonitors) { x = posX; y = posY; } hwndMain = CreateWindowEx(WS_EX_CONTROLPARENT|WS_EX_WINDOWEDGE, OBS_WINDOW_CLASS, OBS_VERSION_STRING, WS_OVERLAPPED | WS_THICKFRAME | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN, x, y, cx, cy, NULL, NULL, hinstMain, NULL); if(!hwndMain) CrashError(TEXT("Could not create main window")); HMENU hMenu = GetMenu(hwndMain); LocalizeMenu(hMenu); //----------------------------------------------------- // render frame hwndRenderFrame = CreateWindow(OBS_RENDERFRAME_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE, 0, 0, 0, 0, hwndMain, NULL, hinstMain, NULL); if(!hwndRenderFrame) CrashError(TEXT("Could not create render frame")); //----------------------------------------------------- // scenes listbox HWND hwndTemp; hwndTemp = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("LISTBOX"), NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|LBS_HASSTRINGS|WS_VSCROLL|LBS_NOTIFY|LBS_NOINTEGRALHEIGHT|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SCENES, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); listboxProc = (WNDPROC)GetWindowLongPtr(hwndTemp, GWLP_WNDPROC); SetWindowLongPtr(hwndTemp, GWLP_WNDPROC, (LONG_PTR)OBS::ListboxHook); //----------------------------------------------------- // elements listview hwndTemp = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|WS_CLIPSIBLINGS|LVS_REPORT|LVS_NOCOLUMNHEADER| LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOLABELWRAP, 0, 0, 0, 0, hwndMain, (HMENU)ID_SOURCES, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); ListView_SetExtendedListViewStyle(hwndTemp, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); //add single column needed for report style LVCOLUMN column; column.mask = LVCF_TEXT; column.fmt = LVCFMT_FIXED_WIDTH; column.cx = 0; column.pszText = TEXT(""); ListView_InsertColumn(hwndTemp, 0, &column); ListView_InsertColumn(hwndTemp, 1, &column); listviewProc = (WNDPROC)GetWindowLongPtr(hwndTemp, GWLP_WNDPROC); SetWindowLongPtr(hwndTemp, GWLP_WNDPROC, (LONG_PTR)OBS::ListboxHook); HWND hwndSources = hwndTemp; //----------------------------------------------------- // status control hwndTemp = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_STATUS, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // mic volume control hwndTemp = CreateWindow(VOLUME_CONTROL_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_MICVOLUME, 0, 0); SetVolumeControlIcons(hwndTemp, GetIcon(hinstMain, IDI_SOUND_MIC), GetIcon(hinstMain, IDI_SOUND_MIC_MUTED)); //----------------------------------------------------- // mic volume meter hwndTemp = CreateWindow(VOLUME_METER_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_MICVOLUMEMETER, 0, 0); //----------------------------------------------------- // desktop volume meter hwndTemp = CreateWindow(VOLUME_METER_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_DESKTOPVOLUMEMETER, 0, 0); //----------------------------------------------------- // desktop volume control hwndTemp = CreateWindow(VOLUME_CONTROL_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_DESKTOPVOLUME, 0, 0); SetVolumeControlIcons(hwndTemp, GetIcon(hinstMain, IDI_SOUND_DESKTOP), GetIcon(hinstMain, IDI_SOUND_DESKTOP_MUTED)); //----------------------------------------------------- // settings button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("Settings"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SETTINGS, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // start/stop stream button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.StartStream"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_STARTSTOP, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // edit scene button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.SceneEditor"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_AUTOCHECKBOX|BS_PUSHLIKE|WS_DISABLED|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SCENEEDITOR, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // global sources button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("GlobalSources"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_GLOBALSOURCES, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // test stream button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.TestStream"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_TESTSTREAM, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // plugins button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.Plugins"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_PLUGINS, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // dashboard button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.Dashboard"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_DASHBOARD, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // exit button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.Exit"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_EXIT, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // scenes text hwndTemp = CreateWindow(TEXT("STATIC"), Str("MainWindow.Scenes"), WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SCENES_TEXT, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // scenes text hwndTemp = CreateWindow(TEXT("STATIC"), Str("MainWindow.Sources"), WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SOURCES_TEXT, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // populate scenes hwndTemp = GetDlgItem(hwndMain, ID_SCENES); String strScenesConfig; strScenesConfig << lpAppDataPath << TEXT("\\scenes.xconfig"); if(!scenesConfig.Open(strScenesConfig)) CrashError(TEXT("Could not open '%s'"), strScenesConfig); XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); if(!scenes) scenes = scenesConfig.CreateElement(TEXT("scenes")); UINT numScenes = scenes->NumElements(); if(!numScenes) { XElement *scene = scenes->CreateElement(Str("Scene")); scene->SetString(TEXT("class"), TEXT("Scene")); numScenes++; } for(UINT i=0; iGetElementByID(i); scene->SetString(TEXT("class"), TEXT("Scene")); SendMessage(hwndTemp, LB_ADDSTRING, 0, (LPARAM)scene->GetName()); } //----------------------------------------------------- // populate sources if(numScenes) { String strScene = AppConfig->GetString(TEXT("General"), TEXT("CurrentScene")); int id = (int)SendMessage(hwndTemp, LB_FINDSTRINGEXACT, -1, 0); if(id == LB_ERR) id = 0; SendMessage(hwndTemp, LB_SETCURSEL, (WPARAM)id, 0); SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(ID_SCENES, LBN_SELCHANGE), (LPARAM)GetDlgItem(hwndMain, ID_SCENES)); } //----------------------------------------------------- hHotkeyMutex = OSCreateMutex(); hInfoMutex = OSCreateMutex(); //----------------------------------------------------- API = CreateOBSApiInterface(); ResizeWindow(false); ShowWindow(hwndMain, SW_SHOW); // make sure sources listview column widths are as expected after obs window is shown ListView_SetColumnWidth(hwndSources,0,LVSCW_AUTOSIZE_USEHEADER); ListView_SetColumnWidth(hwndSources,1,LVSCW_AUTOSIZE_USEHEADER); //----------------------------------------------------- for(UINT i=0; iGetElementByID(i); DWORD hotkey = scene->GetInt(TEXT("hotkey")); if(hotkey) { SceneHotkeyInfo hotkeyInfo; hotkeyInfo.hotkey = hotkey; hotkeyInfo.scene = scene; hotkeyInfo.hotkeyID = API->CreateHotkey(hotkey, SceneHotkey, 0); if(hotkeyInfo.hotkeyID) sceneHotkeys << hotkeyInfo; } } //----------------------------------------------------- // load plugins OSFindData ofd; HANDLE hFind = OSFindFirstFile(TEXT("plugins/*.dll"), ofd); if(hFind) { do { if(!ofd.bDirectory) //why would someone give a directory a .dll extension in the first place? pranksters. { String strLocation; strLocation << TEXT("plugins/") << ofd.fileName; HMODULE hPlugin = LoadLibrary(strLocation); if(hPlugin) { LOADPLUGINPROC loadPlugin = (LOADPLUGINPROC)GetProcAddress(hPlugin, "LoadPlugin"); if(loadPlugin && loadPlugin()) { PluginInfo *pluginInfo = plugins.CreateNew(); pluginInfo->hModule = hPlugin; pluginInfo->strFile = ofd.fileName; } else FreeLibrary(hPlugin); } } } while (OSFindNextFile(hFind, ofd)); OSFindClose(hFind); } //----------------------------------------------------- ReloadIniSettings(); //----------------------------------------------------- bAutoReconnect = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnect"), 1) != 0; reconnectTimeout = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnectTimeout"), 10); if(reconnectTimeout < 5) reconnectTimeout = 5; hHotkeyThread = OSCreateThread((XTHREAD)HotkeyThread, NULL); #ifndef OBS_DISABLE_AUTOUPDATE OSCloseThread(OSCreateThread((XTHREAD)CheckUpdateThread, NULL)); #endif bRenderViewEnabled = true; } OBS::~OBS() { Stop(); bShuttingDown = true; OSTerminateThread(hHotkeyThread, 250); for(UINT i=0; iSetInt(TEXT("General"), TEXT("PosX"), rcWindow.left); GlobalConfig->SetInt(TEXT("General"), TEXT("PosY"), rcWindow.top); GlobalConfig->SetInt(TEXT("General"), TEXT("Width"), clientWidth); GlobalConfig->SetInt(TEXT("General"), TEXT("Height"), clientHeight); scenesConfig.Close(true); for(UINT i=0; iGetInt(TEXT("Video"), TEXT("Monitor")); if(monitorID >= (int)monitors.Num()) monitorID = 0; RECT &screenRect = monitors[monitorID].rect; int defCX = screenRect.right - screenRect.left; int defCY = screenRect.bottom - screenRect.top; int curCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"), defCX); int curCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY); mainAspect = float(curCX)/float(curCY); } if(renderAspect > mainAspect) { renderSize.x = renderSize.y*mainAspect; x += int((float(newRenderFrameWidth)-renderSize.x)*0.5f); } else { renderSize.y = renderSize.x/mainAspect; y += int((float(newRenderFrameHeight)-renderSize.y)*0.5f); } newRenderFrameWidth = int(renderSize.x+0.5f)&0xFFFFFFFE; newRenderFrameHeight = int(renderSize.y+0.5f)&0xFFFFFFFE; SetWindowPos(hwndRenderFrame, NULL, x, y, newRenderFrameWidth, newRenderFrameHeight, SWP_NOOWNERZORDER); //---------------------------------------------- if(bRunning) { if(bRedrawRenderFrame) { renderFrameWidth = newRenderFrameWidth; renderFrameHeight = newRenderFrameHeight; bResizeRenderView = true; } } else { renderFrameWidth = newRenderFrameWidth; renderFrameHeight = newRenderFrameHeight; } } void OBS::GetBaseSize(UINT &width, UINT &height) const { if(bRunning) { width = baseCX; height = baseCY; } else { int monitorID = AppConfig->GetInt(TEXT("Video"), TEXT("Monitor")); if(monitorID >= (int)monitors.Num()) monitorID = 0; RECT &screenRect = monitors[monitorID].rect; int defCX = screenRect.right - screenRect.left; int defCY = screenRect.bottom - screenRect.top; width = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"), defCX); height = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY); } } void OBS::ResizeWindow(bool bRedrawRenderFrame) { //const int listControlHeight = totalControlAreaHeight - textControlHeight - controlHeight - controlPadding; //----------------------------------------------------- /*ShowWindow(GetDlgItem(hwndMain, ID_SCENES), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_SOURCES), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_SCENES_TEXT), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_SOURCES_TEXT), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_MICVOLUME), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_DESKTOPVOLUME), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_SETTINGS), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_STARTSTOP), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_EXIT), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_TESTSTREAM), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_DASHBOARD), SW_HIDE); ShowWindow(GetDlgItem(hwndMain, ID_GLOBALSOURCES), SW_HIDE);*/ //----------------------------------------------------- ResizeRenderFrame(bRedrawRenderFrame); //----------------------------------------------------- DWORD flags = SWP_NOOWNERZORDER|SWP_SHOWWINDOW; int xStart = clientWidth/2 - totalControlAreaWidth/2 + (controlPadding/2 + 1); int yStart = clientHeight - totalControlAreaHeight; int xPos = xStart; int yPos = yStart; //----------------------------------------------------- HWND hwndTemp = GetDlgItem(hwndMain, ID_STATUS); //SetWindowPos(GetDlgItem(hwndMain, ID_STATUS), NULL, xPos, yPos+listControlHeight, totalWidth-controlPadding, statusHeight, 0); SendMessage(hwndTemp, WM_SIZE, SIZE_RESTORED, 0); int parts[5]; parts[4] = -1; parts[3] = clientWidth-100; parts[2] = parts[3]-60; parts[1] = parts[2]-170; parts[0] = parts[1]-80; SendMessage(hwndTemp, SB_SETPARTS, 5, (LPARAM)parts); int resetXPos = xStart+listControlWidth*2; //----------------------------------------------------- xPos = resetXPos; yPos = yStart; SetWindowPos(GetDlgItem(hwndMain, ID_MICVOLUME), NULL, xPos, yPos, controlWidth-controlPadding, volControlHeight, flags); xPos += controlWidth; SetWindowPos(GetDlgItem(hwndMain, ID_DESKTOPVOLUME), NULL, xPos, yPos, controlWidth-controlPadding, volControlHeight, flags); xPos += controlWidth; yPos += volControlHeight+controlPadding; //----------------------------------------------------- xPos = resetXPos; SetWindowPos(GetDlgItem(hwndMain, ID_MICVOLUMEMETER), NULL, xPos, yPos, controlWidth-controlPadding, volMeterHeight, flags); xPos += controlWidth; SetWindowPos(GetDlgItem(hwndMain, ID_DESKTOPVOLUMEMETER), NULL, xPos, yPos, controlWidth-controlPadding, volMeterHeight, flags); xPos += controlWidth; yPos += volMeterHeight+controlPadding; //----------------------------------------------------- xPos = resetXPos; SetWindowPos(GetDlgItem(hwndMain, ID_SETTINGS), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; SetWindowPos(GetDlgItem(hwndMain, ID_STARTSTOP), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; yPos += controlHeight+controlPadding; //----------------------------------------------------- xPos = resetXPos; SetWindowPos(GetDlgItem(hwndMain, ID_SCENEEDITOR), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; SetWindowPos(GetDlgItem(hwndMain, ID_TESTSTREAM), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; yPos += controlHeight+controlPadding; //----------------------------------------------------- xPos = resetXPos; SetWindowPos(GetDlgItem(hwndMain, ID_GLOBALSOURCES), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; SetWindowPos(GetDlgItem(hwndMain, ID_PLUGINS), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; yPos += controlHeight+controlPadding; //----------------------------------------------------- xPos = resetXPos; BOOL bStreamOutput = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode")) == 0; BOOL bShowDashboardButton = strDashboard.IsValid() && bStreamOutput; SetWindowPos(GetDlgItem(hwndMain, ID_DASHBOARD), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; ShowWindow(GetDlgItem(hwndMain, ID_DASHBOARD), bShowDashboardButton ? SW_SHOW : SW_HIDE); SetWindowPos(GetDlgItem(hwndMain, ID_EXIT), NULL, xPos, yPos, controlWidth-controlPadding, controlHeight, flags); xPos += controlWidth; yPos += controlHeight; //----------------------------------------------------- int listControlHeight = yPos-yStart-textControlHeight; xPos = xStart; yPos = yStart; SetWindowPos(GetDlgItem(hwndMain, ID_SCENES_TEXT), NULL, xPos+2, yPos, listControlWidth-controlPadding-2, textControlHeight, flags); xPos += listControlWidth; SetWindowPos(GetDlgItem(hwndMain, ID_SOURCES_TEXT), NULL, xPos+2, yPos, listControlWidth-controlPadding-2, textControlHeight, flags); xPos += listControlWidth; yPos += textControlHeight; xPos = xStart; //----------------------------------------------------- SetWindowPos(GetDlgItem(hwndMain, ID_SCENES), NULL, xPos, yPos, listControlWidth-controlPadding, listControlHeight, flags); xPos += listControlWidth; SetWindowPos(GetDlgItem(hwndMain, ID_SOURCES), NULL, xPos, yPos, listControlWidth-controlPadding, listControlHeight, flags); xPos += listControlWidth; } void OBS::ReloadIniSettings() { HWND hwndTemp; //------------------------------------------- // mic volume data hwndTemp = GetDlgItem(hwndMain, ID_MICVOLUME); if(!AppConfig->HasKey(TEXT("Audio"), TEXT("MicVolume"))) AppConfig->SetFloat(TEXT("Audio"), TEXT("MicVolume"), 0.0f); SetVolumeControlValue(hwndTemp, AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"), 0.0f)); AudioDeviceList audioDevices; GetAudioDevices(audioDevices, ADT_RECORDING); String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL); if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable")); strDevice = TEXT("Disable"); } audioDevices.FreeData(); EnableWindow(hwndTemp, !strDevice.CompareI(TEXT("Disable"))); //------------------------------------------- // desktop volume hwndTemp = GetDlgItem(hwndMain, ID_DESKTOPVOLUME); if(!AppConfig->HasKey(TEXT("Audio"), TEXT("DesktopVolume"))) AppConfig->SetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f); SetVolumeControlValue(hwndTemp, AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 0.0f)); //------------------------------------------- // mic boost DWORD micBoostPercentage = AppConfig->GetInt(TEXT("Audio"), TEXT("MicBoostMultiple"), 1); if(micBoostPercentage < 1) micBoostPercentage = 1; else if(micBoostPercentage > 20) micBoostPercentage = 20; micBoost = float(micBoostPercentage); //------------------------------------------- // dashboard strDashboard = AppConfig->GetString(TEXT("Publish"), TEXT("Dashboard")); strDashboard.KillSpaces(); //------------------------------------------- // hotkeys QuickClearHotkey(pushToTalkHotkeyID); QuickClearHotkey(muteMicHotkeyID); QuickClearHotkey(muteDesktopHotkeyID); QuickClearHotkey(stopStreamHotkeyID); QuickClearHotkey(startStreamHotkeyID); bUsingPushToTalk = AppConfig->GetInt(TEXT("Audio"), TEXT("UsePushToTalk")) != 0; DWORD hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("PushToTalkHotkey")); pushToTalkDelay = AppConfig->GetInt(TEXT("Audio"), TEXT("PushToTalkDelay"), 200); if(bUsingPushToTalk && hotkey) pushToTalkHotkeyID = API->CreateHotkey(hotkey, OBS::PushToTalkHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("MuteMicHotkey")); if(hotkey) muteMicHotkeyID = API->CreateHotkey(hotkey, OBS::MuteMicHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("MuteDesktopHotkey")); if(hotkey) muteDesktopHotkeyID = API->CreateHotkey(hotkey, OBS::MuteDesktopHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StopStreamHotkey")); if(hotkey) stopStreamHotkeyID = API->CreateHotkey(hotkey, OBS::StopStreamHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StartStreamHotkey")); if(hotkey) startStreamHotkeyID = API->CreateHotkey(hotkey, OBS::StartStreamHotkey, NULL); } void OBS::UpdateAudioMeters() { SetVolumeMeterValue(GetDlgItem(hwndMain, ID_DESKTOPVOLUMEMETER), desktopMag, desktopMax, desktopPeak); SetVolumeMeterValue(GetDlgItem(hwndMain, ID_MICVOLUMEMETER), micMag, micMax, micPeak); } HICON OBS::GetIcon(HINSTANCE hInst, int resource) { for(UINT i=0; ibRunning) return; HDC hdcTemp = CreateCompatibleDC(dis.hDC); HBITMAP hbmpTemp = CreateCompatibleBitmap(dis.hDC, dis.rcItem.right-dis.rcItem.left, dis.rcItem.bottom-dis.rcItem.top); SelectObject(hdcTemp, hbmpTemp); SelectObject(hdcTemp, GetCurrentObject(dis.hDC, OBJ_FONT)); //HBRUSH hColorBrush = CreateSolidBrush((green<<8)|red); RECT rc; mcpy(&rc, &dis.rcItem, sizeof(rc)); rc.left -= dis.rcItem.left; rc.right -= dis.rcItem.left; rc.top -= dis.rcItem.top; rc.bottom -= dis.rcItem.top; FillRect(hdcTemp, &rc, (HBRUSH)(COLOR_BTNFACE+1)); //DeleteObject(hColorBrush); //-------------------------------- if(dis.itemID == 4) { DWORD green = 0xFF, red = 0xFF; statusBarData.bytesPerSec = App->bytesPerSec; statusBarData.strain = App->curStrain; //statusBarData.strain = rand()%101; if(statusBarData.strain > 50.0) green = DWORD(((50.0-(statusBarData.strain-50.0))/50.0)*255.0); double redStrain = statusBarData.strain/50.0; if(redStrain > 1.0) redStrain = 1.0; red = DWORD(redStrain*255.0); //-------------------------------- HBRUSH hColorBrush = CreateSolidBrush((green<<8)|red); RECT rcBox = {0, 0, 20, 20}; /*rc.left += dis.rcItem.left; rc.right += dis.rcItem.left; rc.top += dis.rcItem.top; rc.bottom += dis.rcItem.top;*/ FillRect(hdcTemp, &rcBox, hColorBrush); DeleteObject(hColorBrush); //-------------------------------- SetBkMode(hdcTemp, TRANSPARENT); rc.left += 22; String strKBPS; strKBPS << IntString((statusBarData.bytesPerSec*8) / 1000) << TEXT("kb/s"); //strKBPS << IntString(rand()) << TEXT("kb/s"); DrawText(hdcTemp, strKBPS, strKBPS.Length(), &rc, DT_VCENTER|DT_SINGLELINE|DT_LEFT); } else { String strOutString; switch(dis.itemID) { case 0: strOutString << App->GetMostImportantInfo(); break; case 1: { DWORD streamTimeSecondsTotal = App->totalStreamTime/1000; DWORD streamTimeMinutesTotal = streamTimeSecondsTotal/60; DWORD streamTimeSeconds = streamTimeSecondsTotal%60; DWORD streamTimeHours = streamTimeMinutesTotal/60; DWORD streamTimeMinutes = streamTimeMinutesTotal%60; strOutString = FormattedString(TEXT("%u:%02u:%02u"), streamTimeHours, streamTimeMinutes, streamTimeSeconds); } break; case 2: { double percentageDropped = 0.0; if(App->network) { UINT numTotalFrames = App->network->NumTotalVideoFrames(); if(numTotalFrames) percentageDropped = (double(App->network->NumDroppedFrames())/double(numTotalFrames))*100.0; } strOutString << Str("MainWindow.DroppedFrames") << FormattedString(TEXT(" %u (%0.2f%%)"), App->curFramesDropped, percentageDropped); } break; case 3: strOutString << TEXT("FPS: ") << IntString(App->captureFPS); break; } if(strOutString.IsValid()) { SetBkMode(hdcTemp, TRANSPARENT); DrawText(hdcTemp, strOutString, strOutString.Length(), &rc, DT_VCENTER|DT_SINGLELINE|DT_LEFT); } } //-------------------------------- BitBlt(dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right-dis.rcItem.left, dis.rcItem.bottom-dis.rcItem.top, hdcTemp, 0, 0, SRCCOPY); DeleteObject(hdcTemp); DeleteObject(hbmpTemp); } void OBS::SelectSources() { if(scene) scene->DeselectAll(); HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); UINT numSelected = ListView_GetSelectedCount(hwndSources); if(numSelected) { List selectedItems; selectedItems.SetSize(numSelected); //SendMessage(hwndSources, LB_GETSELITEMS, numSelected, (LPARAM)selectedItems.Array()); if(scene) { int iPos = ListView_GetNextItem(hwndSources, -1, LVNI_SELECTED); while (iPos != -1) { SceneItem *sceneItem = scene->GetSceneItem(iPos); sceneItem->bSelected = true; iPos = ListView_GetNextItem(hwndSources, iPos, LVNI_SELECTED); } } } } void OBS::CheckSources() { XElement *curSceneElement = App->sceneElement; XElement *sources = curSceneElement->GetElement(TEXT("sources")); if(!sources) return; HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); UINT numSources = ListView_GetItemCount(hwndSources); for(UINT i = 0; i < numSources; i++) { bool checked = ListView_GetCheckState(hwndSources, i) > 0; XElement *source =sources->GetElementByID(i); source->SetInt(TEXT("render"), (checked)?1:0); if(scene && i < scene->NumSceneItems()) { SceneItem *sceneItem = scene->GetSceneItem(i); sceneItem->bRender = checked; sceneItem->SetRender(checked); } } }