summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXLaunch.c
blob: 5004bf2ca6657fcadfecb38616d0ded2dbf7a9d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*

 * tkMacOSXLaunch.c --

 * Launches URL's using native API's on OS X without shelling out to "/usr/bin/open". Also gets and sets default app handlers.

 * Copyright (c) 2015-2019 Kevin Walzer/WordTech Communications LLC.

 *

 * See the file "license.terms" for information on usage and redistribution of

 * this file, and for a DISCLAIMER OF ALL WARRANTIES.

 *

 */

#include <tcl.h>

#include <tk.h>

#undef panic

#include <CoreFoundation/CoreFoundation.h>

#include <CoreServices/CoreServices.h>

#include <Carbon/Carbon.h>

#include <ApplicationServices/ApplicationServices.h>

#define panic Tcl_Panic



/*Tcl function to launch URL with default app.*/
int LaunchURL(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[]) {

  if(objc != 2) {
    Tcl_WrongNumArgs(ip, 1, objv, "url");
    return TCL_ERROR;
  }


  /* Get url string, convert to CFURL. */
  CFStringRef url = CFStringCreateWithCString(NULL, Tcl_GetString(objv[1]),
					      kCFStringEncodingUTF8);
  CFURLRef launchurl = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
  CFRelease(url);

  /* Fire url in default app. */
  LSOpenCFURLRef(launchurl, NULL);

  CFRelease(launchurl);

  return TCL_OK;

}

/*Tcl function to launch file with default app.*/
int LaunchFile(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[]) {

  if(objc != 2) {
    Tcl_WrongNumArgs(ip, 1, objv, "file");
    return TCL_ERROR;
  }

  /* Get url string, convert to CFURL. */
  CFStringRef url = CFStringCreateWithCString(NULL, Tcl_GetString(objv[1]),
					      kCFStringEncodingUTF8);
  CFRelease(url);

  CFURLRef launchurl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, url, kCFURLPOSIXPathStyle, false);

  /* Fire url in default app. */
  LSOpenCFURLRef(launchurl, NULL);
  CFRelease(launchurl);

  return TCL_OK;

}


/*Tcl function to get path to app bundle.*/
int GetAppPath(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[]) {

  CFURLRef mainBundleURL = CFBundleCopyBundleURL(CFBundleGetMainBundle());

  
  /* Convert the URL reference into a string reference. */
  CFStringRef appPath = CFURLCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
 
  /* Get the system encoding method. */
  CFStringEncoding encodingMethod = CFStringGetSystemEncoding();
 
  /* Convert the string reference into a C string. */
  char *path = CFStringGetCStringPtr(appPath, encodingMethod);

  Tcl_SetResult(ip, path, NULL);

  CFRelease(mainBundleURL);
  CFRelease(appPath);
  return TCL_OK;

}

/*Tcl function to launch file with default app.*/
int GetDefaultApp(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[]) {

  if(objc != 2) {
    Tcl_WrongNumArgs(ip, 1, objv, "url");
    return TCL_ERROR;
  }

  /* Get url string, convert to CFStringRef. */
  CFStringRef url = CFStringCreateWithCString(NULL, Tcl_GetString(objv[1]),
					      kCFStringEncodingUTF8);

  CFStringRef defaultApp;
  defaultApp =  LSCopyDefaultHandlerForURLScheme(url);

  OSStatus result;
  CFURLRef appURL = NULL;
  result = LSFindApplicationForInfo(kLSUnknownCreator, defaultApp, NULL, NULL, &appURL);

  /* Convert the URL reference into a string reference. */
  CFStringRef appPath = CFURLCopyFileSystemPath(appURL, kCFURLPOSIXPathStyle);
 
  /* Get the system encoding method. */
  CFStringEncoding encodingMethod = CFStringGetSystemEncoding();
 
  /* Convert the string reference into a C string. */
  char *path = CFStringGetCStringPtr(appPath, encodingMethod);

  Tcl_SetResult(ip, path, NULL);

  CFRelease(defaultApp);
  CFRelease(appPath);
  CFRelease(url);

  return TCL_OK;

}

/*Tcl function to set default app for URL.*/
int SetDefaultApp(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[]) {

  if(objc != 3) {
    Tcl_WrongNumArgs(ip, 1, objv, "url path");
    return TCL_ERROR;
  }
  
  /* Get url and path strings, convert to CFStringRef. */
  CFStringRef url = CFStringCreateWithCString(NULL, Tcl_GetString(objv[1]),
					      kCFStringEncodingUTF8);
  CFURLRef appURL = NULL;
  CFBundleRef bundle = NULL;

  CFStringRef apppath = CFStringCreateWithCString(NULL, Tcl_GetString(objv[2]),  kCFStringEncodingUTF8);

  /* Convert filepath to URL, create bundle object, get bundle ID. */
  appURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, apppath, kCFURLPOSIXPathStyle, false);
  bundle = CFBundleCreate(NULL, appURL);

  CFStringRef bundleID = CFBundleGetIdentifier(bundle); 

  /* Finally, set default app. */
  OSStatus err;
  err= LSSetDefaultHandlerForURLScheme(url, bundleID);

  /* Free memory.  */
  CFRelease(url);
  CFRelease(apppath);
  CFRelease(bundleID);

  return TCL_OK;

}


/*Initalize the package in the tcl interpreter, create Tcl commands. */
int  TkMacOSXLauncher_Init (Tcl_Interp *interp) {

 
  if (Tcl_InitStubs(interp, "8.5", 0) == NULL) {
    return TCL_ERROR;  
  }
  if (Tk_InitStubs(interp, "8.5", 0) == NULL) {
    return TCL_ERROR;
  }


  Tcl_CreateObjCommand(interp, "::tk::mac::LaunchURL", LaunchURL,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateObjCommand(interp, "::tk::mac::LaunchFile", LaunchFile,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateObjCommand(interp, "::tk::mac::GetAppPath", GetAppPath,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateObjCommand(interp, "::tk::mac::GetDefaultApp", GetDefaultApp,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateObjCommand(interp, "::tk::mac::SetDefaultApp",SetDefaultApp,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);

 
  return TCL_OK;
	
}