| 
					
				 | 
			
			
				@@ -2,11 +2,17 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <util/dstr.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "dc-capture.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "window-helpers.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "../../libobs/util/platform.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "../../libobs-winrt/winrt-capture.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* clang-format off */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TEXT_WINDOW_CAPTURE obs_module_text("WindowCapture") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TEXT_WINDOW         obs_module_text("WindowCapture.Window") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define TEXT_METHOD         obs_module_text("WindowCapture.Method") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define TEXT_METHOD_AUTO    obs_module_text("WindowCapture.Method.Auto") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define TEXT_METHOD_BITBLT  obs_module_text("WindowCapture.Method.BitBlt") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define TEXT_METHOD_WGC     obs_module_text("WindowCapture.Method.WindowsGraphicsCapture") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TEXT_MATCH_PRIORITY obs_module_text("WindowCapture.Priority") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TEXT_MATCH_TITLE    obs_module_text("WindowCapture.Priority.Title") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TEXT_MATCH_CLASS    obs_module_text("WindowCapture.Priority.Class") 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -18,19 +24,42 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define WC_CHECK_TIMER 1.0f 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct winrt_exports { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	bool *(*winrt_capture_supported)(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct winrt_capture *(*winrt_capture_init)(bool cursor, HWND window); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void (*winrt_capture_free)(struct winrt_capture *capture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void (*winrt_capture_render)(struct winrt_capture *capture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				     gs_effect_t *effect); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int32_t (*winrt_capture_width)(const struct winrt_capture *capture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int32_t (*winrt_capture_height)(const struct winrt_capture *capture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+enum window_capture_method { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	METHOD_AUTO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	METHOD_BITBLT, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	METHOD_WGC, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 struct window_capture { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	obs_source_t *source; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	char *title; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	char *class; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	char *executable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	enum window_capture_method method; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	enum window_priority priority; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	bool auto_choose_method; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	bool cursor; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	bool compatibility; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	bool use_wildcards; /* TODO */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	struct dc_capture capture; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	bool wgc_supported; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void *winrt_module; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct winrt_exports exports; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct winrt_capture *capture_winrt; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	float resize_timer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	float check_window_timer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	float cursor_check_time; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -41,6 +70,7 @@ struct window_capture { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void update_settings(struct window_capture *wc, obs_data_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int method = (int)obs_data_get_int(s, "method"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const char *window = obs_data_get_string(s, "window"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	int priority = (int)obs_data_get_int(s, "priority"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -58,7 +88,13 @@ static void update_settings(struct window_capture *wc, obs_data_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		blog(LOG_DEBUG, "\tclass:      %s", wc->class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!wc->wgc_supported) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		method = METHOD_BITBLT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	wc->method = method; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	wc->priority = (enum window_priority)priority; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	wc->auto_choose_method = (method == METHOD_AUTO); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	wc->cursor = obs_data_get_bool(s, "cursor"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	wc->use_wildcards = obs_data_get_bool(s, "use_wildcards"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	wc->compatibility = obs_data_get_bool(s, "compatibility"); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -72,11 +108,54 @@ static const char *wc_getname(void *unused) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return TEXT_WINDOW_CAPTURE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define WINRT_IMPORT(func)                                        \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	do {                                                      \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		exports->func = os_dlsym(module, #func);          \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!exports->func) {                             \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			success = false;                          \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			blog(LOG_ERROR,                           \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			     "Could not load function '%s' from " \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			     "module '%s'",                       \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			     #func, module_name);                 \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}                                                 \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} while (false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static bool load_winrt_imports(struct winrt_exports *exports, void *module, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			       const char *module_name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	bool success = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WINRT_IMPORT(winrt_capture_supported); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WINRT_IMPORT(winrt_capture_init); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WINRT_IMPORT(winrt_capture_free); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WINRT_IMPORT(winrt_capture_render); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WINRT_IMPORT(winrt_capture_width); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WINRT_IMPORT(winrt_capture_height); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return success; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void *wc_create(obs_data_t *settings, obs_source_t *source) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	struct window_capture *wc = bzalloc(sizeof(struct window_capture)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	wc->source = source; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_enter_graphics(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const bool uses_d3d11 = gs_get_device_type() == GS_DEVICE_DIRECT3D_11; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_leave_graphics(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (uses_d3d11) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		static const char *const module = "libobs-winrt"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		bool use_winrt_capture = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		wc->winrt_module = os_dlopen(module); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (wc->winrt_module && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		    load_winrt_imports(&wc->exports, wc->winrt_module, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				       module) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		    wc->exports.winrt_capture_supported()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->wgc_supported = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	update_settings(wc, settings); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return wc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -94,6 +173,9 @@ static void wc_destroy(void *data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		bfree(wc->class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		bfree(wc->executable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (wc->winrt_module) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			os_dlclose(wc->winrt_module); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		bfree(wc); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -111,28 +193,56 @@ static void wc_update(void *data, obs_data_t *settings) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static uint32_t wc_width(void *data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	struct window_capture *wc = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return wc->capture.width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return (wc->method == METHOD_WGC) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		       ? wc->exports.winrt_capture_width(wc->capture_winrt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		       : wc->capture.width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static uint32_t wc_height(void *data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	struct window_capture *wc = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return wc->capture.height; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return (wc->method == METHOD_WGC) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		       ? wc->exports.winrt_capture_height(wc->capture_winrt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		       : wc->capture.height; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void wc_defaults(obs_data_t *defaults) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_data_set_default_int(defaults, "method", METHOD_AUTO); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	obs_data_set_default_bool(defaults, "cursor", true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	obs_data_set_default_bool(defaults, "compatibility", false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static obs_properties_t *wc_properties(void *unused) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static bool wc_capture_method_changed(obs_properties_t *props, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				      obs_property_t *p, obs_data_t *settings) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	UNUSED_PARAMETER(unused); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const int method = (int)obs_data_get_int(settings, "method"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const bool show_options = method != METHOD_WGC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	p = obs_properties_get(props, "cursor"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_property_set_visible(p, show_options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	p = obs_properties_get(props, "compatibility"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_property_set_visible(p, show_options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static obs_properties_t *wc_properties(void *data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct window_capture *wc = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	obs_properties_t *ppts = obs_properties_create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	obs_property_t *p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	p = obs_properties_add_list(ppts, "method", TEXT_METHOD, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				    OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_property_list_add_int(p, TEXT_METHOD_AUTO, METHOD_AUTO); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_property_list_add_int(p, TEXT_METHOD_BITBLT, METHOD_BITBLT); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_property_list_add_int(p, TEXT_METHOD_WGC, METHOD_WGC); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_property_list_item_disable(p, 1, !wc->wgc_supported); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	obs_property_set_modified_callback(p, wc_capture_method_changed); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	p = obs_properties_add_list(ppts, "window", TEXT_WINDOW, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				    OBS_COMBO_TYPE_LIST, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				    OBS_COMBO_FORMAT_STRING); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -151,6 +261,60 @@ static obs_properties_t *wc_properties(void *unused) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return ppts; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void wc_hide(void *data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct window_capture *wc = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (wc->capture_winrt) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		wc->exports.winrt_capture_free(wc->capture_winrt); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		wc->capture_winrt = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	memset(&wc->last_rect, 0, sizeof(wc->last_rect)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const char *wgc_partial_match_classes[] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"Chrome", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"Mozilla", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NULL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const char *wgc_whole_match_classes[] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"ApplicationFrameWindow", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"Windows.UI.Core.CoreWindow", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"XLMAIN",        /* excel*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"PPTFrameClass", /* powerpoint */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"OpusApp",       /* word */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NULL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void auto_choose_method(struct window_capture *wc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	wc->method = METHOD_BITBLT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!wc->class) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const char **class = wgc_partial_match_classes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	while (*class) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (astrstri(wc->class, *class) != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->method = METHOD_WGC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		class ++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	class = wgc_whole_match_classes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	while (*class) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (astrcmpi(wc->class, *class) == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->method = METHOD_WGC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		class ++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define RESIZE_CHECK_TIME 0.2f 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define CURSOR_CHECK_TIME 0.2f 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -175,10 +339,26 @@ static void wc_tick(void *data, float seconds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (wc->capture_winrt) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->exports.winrt_capture_free(wc->capture_winrt); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->capture_winrt = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (wc->auto_choose_method) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			auto_choose_method(wc); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		wc->check_window_timer = 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		wc->window = find_window(EXCLUDE_MINIMIZED, wc->priority, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					 wc->class, wc->title, wc->executable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		wc->window = (wc->method == METHOD_WGC) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				     ? find_window_top_level(EXCLUDE_MINIMIZED, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							     wc->priority, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							     wc->class, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							     wc->title, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							     wc->executable) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				     : find_window(EXCLUDE_MINIMIZED, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						   wc->priority, wc->class, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						   wc->title, wc->executable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (!wc->window) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if (wc->capture.valid) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				dc_capture_free(&wc->capture); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -203,47 +383,62 @@ static void wc_tick(void *data, float seconds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (!GetWindowThreadProcessId(wc->window, &target_pid)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			target_pid = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if (foreground_pid && target_pid && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		    foreground_pid != target_pid) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			wc->capture.cursor_hidden = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			wc->capture.cursor_hidden = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		wc->capture.cursor_hidden = foreground_pid && target_pid && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					    foreground_pid != target_pid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		wc->cursor_check_time = 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	obs_enter_graphics(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	GetClientRect(wc->window, &rect); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (wc->method == METHOD_BITBLT) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		GetClientRect(wc->window, &rect); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if (!reset_capture) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		wc->resize_timer += seconds; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!reset_capture) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->resize_timer += seconds; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if (wc->resize_timer >= RESIZE_CHECK_TIME) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (rect.bottom != wc->last_rect.bottom || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			    rect.right != wc->last_rect.right) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				reset_capture = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (wc->resize_timer >= RESIZE_CHECK_TIME) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if ((rect.bottom - rect.top) != 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					    (wc->last_rect.bottom - 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					     wc->last_rect.top) || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				    (rect.right - rect.left) != 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					    (wc->last_rect.right - 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					     wc->last_rect.left)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					reset_capture = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				wc->resize_timer = 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (reset_capture) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			wc->resize_timer = 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->last_rect = rect; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dc_capture_free(&wc->capture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dc_capture_init(&wc->capture, 0, 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					rect.right - rect.left, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					rect.bottom - rect.top, wc->cursor, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					wc->compatibility); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if (reset_capture) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		wc->resize_timer = 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		wc->last_rect = rect; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		dc_capture_free(&wc->capture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		dc_capture_init(&wc->capture, 0, 0, rect.right, rect.bottom, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				wc->cursor, wc->compatibility); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		dc_capture_capture(&wc->capture, wc->window); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else if (wc->method == METHOD_WGC) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (wc->window && (wc->capture_winrt == NULL)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			wc->capture_winrt = wc->exports.winrt_capture_init( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				wc->cursor, wc->window); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	dc_capture_capture(&wc->capture, wc->window); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	obs_leave_graphics(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void wc_render(void *data, gs_effect_t *effect) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	struct window_capture *wc = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	dc_capture_render(&wc->capture, obs_get_base_effect(OBS_EFFECT_OPAQUE)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	gs_effect_t *const opaque = obs_get_base_effect(OBS_EFFECT_OPAQUE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (wc->method == METHOD_WGC) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		wc->exports.winrt_capture_render(wc->capture_winrt, opaque); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		dc_capture_render(&wc->capture, opaque); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	UNUSED_PARAMETER(effect); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -257,6 +452,7 @@ struct obs_source_info window_capture_info = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	.destroy = wc_destroy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	.update = wc_update, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	.video_render = wc_render, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	.hide = wc_hide, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	.video_tick = wc_tick, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	.get_width = wc_width, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	.get_height = wc_height, 
			 |