5
5
using System . IO ;
6
6
using System . Linq ;
7
7
using System . Runtime ;
8
+ using System . Runtime . InteropServices ;
8
9
using System . Text ;
10
+ using System . Threading ;
9
11
using System . Threading . Tasks ;
10
12
using System . Windows . Forms ;
13
+ using Windows . Win32 ;
14
+ using Windows . Win32 . Foundation ;
11
15
12
16
namespace ObsidianShell
13
17
{
@@ -20,15 +24,15 @@ public Obsidian(Settings settings)
20
24
_settings = settings ;
21
25
}
22
26
23
- public void OpenFile ( string path )
27
+ public async Task OpenFile ( string path )
24
28
{
25
29
switch ( _settings . OpenMode )
26
30
{
27
31
case OpenMode . VaultFallback :
28
32
{
29
33
if ( IsFileInVault ( path ) )
30
34
{
31
- OpenFileInVault ( path ) ;
35
+ await OpenFileInVault ( path ) ;
32
36
}
33
37
else
34
38
{
@@ -40,17 +44,17 @@ public void OpenFile(string path)
40
44
{
41
45
if ( IsFileInVault ( path ) )
42
46
{
43
- OpenFileInVault ( path ) ;
47
+ await OpenFileInVault ( path ) ;
44
48
}
45
49
else
46
50
{
47
- OpenFileInRecent ( path ) ;
51
+ await OpenFileInRecent ( path ) ;
48
52
}
49
53
break ;
50
54
}
51
55
case OpenMode . Recent :
52
56
{
53
- OpenFileInRecent ( path ) ;
57
+ await OpenFileInRecent ( path ) ;
54
58
break ;
55
59
}
56
60
}
@@ -63,7 +67,7 @@ private static string PercentEncode(string text)
63
67
return Uri . EscapeDataString ( text ) ;
64
68
}
65
69
66
- private void OpenFileInVault ( string path , string vaultPath = null )
70
+ private async Task OpenFileInVault ( string path , string vaultPath = null )
67
71
{
68
72
if ( _settings . EnableAdvancedURI is false )
69
73
{
@@ -73,7 +77,7 @@ private void OpenFileInVault(string path, string vaultPath = null)
73
77
{
74
78
vaultPath = vaultPath ?? GetFileVaultPath ( path ) ;
75
79
string vault = GetVaultName ( vaultPath ) ;
76
- string filename = Utils . GetRelativePath ( vaultPath , path ) ;
80
+ string filepath = Utils . GetRelativePath ( vaultPath , path ) ;
77
81
78
82
ObsidianOpenMode obsidianOpenMode = _settings . ObsidianDefaultOpenMode ;
79
83
if ( Utils . IsKeyPressed ( Keys . ControlKey ) )
@@ -85,20 +89,60 @@ private void OpenFileInVault(string path, string vaultPath = null)
85
89
if ( Utils . IsKeyPressed ( Keys . LWin ) || Utils . IsKeyPressed ( Keys . RWin ) )
86
90
obsidianOpenMode = _settings . ObsidianWinOpenMode ;
87
91
88
- string openmode = obsidianOpenMode switch
92
+ if ( obsidianOpenMode is ObsidianOpenMode . NewWindow )
89
93
{
90
- ObsidianOpenMode . CurrentTab => "false" ,
91
- ObsidianOpenMode . NewTab => "tab" ,
92
- ObsidianOpenMode . NewWindow => "window" ,
93
- ObsidianOpenMode . NewPane => "split" ,
94
- ObsidianOpenMode . HoverPopover => "popover" ,
95
- _ => throw new ArgumentException ( )
96
- } ;
97
-
98
- Process . Start ( $ "obsidian://advanced-uri?vault={ PercentEncode ( vault ) } &filepath={ PercentEncode ( filename ) } &openmode={ openmode } ") ;
94
+ await OpenFileInNewWindow ( vault , filepath ) ;
95
+ }
96
+ else
97
+ {
98
+ string openmode = obsidianOpenMode switch
99
+ {
100
+ ObsidianOpenMode . CurrentTab => "false" ,
101
+ ObsidianOpenMode . NewTab => "tab" ,
102
+ //ObsidianOpenMode.NewWindow => "window",
103
+ ObsidianOpenMode . NewPane => "split" ,
104
+ ObsidianOpenMode . HoverPopover => "popover" ,
105
+ ObsidianOpenMode . VaultAndNewWindow => "window" ,
106
+ _ => throw new ArgumentException ( )
107
+ } ;
108
+ Process . Start ( $ "obsidian://advanced-uri?vault={ PercentEncode ( vault ) } &filepath={ PercentEncode ( filepath ) } &openmode={ openmode } ") ;
109
+ }
99
110
}
100
111
}
101
112
113
+ private async Task OpenFileInNewWindow ( string vault , string filepath )
114
+ {
115
+ List < WindowVisualState > states = Utils . EnumerateProcessWindowHandles ( "Obsidian" , "Chrome_WidgetWin_1" ) . Select ( w => new WindowVisualState ( w ) ) . ToList ( ) ;
116
+ Process . Start ( $ "obsidian://advanced-uri?vault={ PercentEncode ( vault ) } &filepath={ PercentEncode ( filepath ) } &openmode=window") ;
117
+
118
+ Stopwatch stopwach = Stopwatch . StartNew ( ) ;
119
+ do
120
+ {
121
+ await Task . Delay ( 50 ) ;
122
+ // This is not precise enough. If the vault hasn't been opend before, Obsidian will create two or more windows.
123
+ // But that case is hard to detect.
124
+ if ( Utils . EnumerateProcessWindowHandles ( "Obsidian" , "Chrome_WidgetWin_1" ) . Count ( ) > states . Count )
125
+ {
126
+ // 250~477ms
127
+ Debug . WriteLine ( $ "Found new window after { stopwach . ElapsedMilliseconds } ms") ;
128
+ break ;
129
+ }
130
+ } while ( stopwach . ElapsedMilliseconds < 10000 ) ;
131
+
132
+ foreach ( WindowVisualState state in states )
133
+ {
134
+ state . Restore ( ) ;
135
+ }
136
+
137
+ /*
138
+ // If not specify Chrome_WidgetWin_1, we will get Chrome_WidgetWin_0.
139
+ HWND newWindow = Utils.EnumerateProcessWindowHandles("Obsidian", "Chrome_WidgetWin_1").Where(x => !states.Select(x => x.Handle).Contains(x)).First();
140
+ Debug.WriteLine($"New window: {new WindowVisualState(newWindow)}");
141
+
142
+ PInvoke.BringWindowToTop(newWindow);
143
+ */
144
+ }
145
+
102
146
private static string GetVaultName ( string path )
103
147
{
104
148
return Path . GetFileName ( path ) ;
@@ -142,7 +186,7 @@ private void OpenFileByFallback(string path)
142
186
Process . Start ( editor , String . Format ( _settings . FallbackMarkdownEditorArguments , $@ """{ path } """));
143
187
}
144
188
145
- private void OpenFileInRecent(string path)
189
+ private async Task OpenFileInRecent(string path)
146
190
{
147
191
// hard link stays valid when the source file is deleted;
148
192
// symbolic link requires SeCreateSymbolicLinkPrivilege;
@@ -177,7 +221,7 @@ private void OpenFileInRecent(string path)
177
221
path_in_recent = CreateLinkInRecent( directory . Parent , false ) + '\\ ' + directory . Name ;
178
222
}
179
223
180
- OpenFileInVault ( path_in_recent , _settings . RecentVault ) ;
224
+ await OpenFileInVault ( path_in_recent , _settings . RecentVault ) ;
181
225
}
182
226
183
227
private static string FormatLinkName( string prefixed_name , bool explicitDirectory )
0 commit comments