Changeset 91 for trunk/appswitch/main.c
- Timestamp:
- 02/10/03 20:08:11 (22 years ago)
- Location:
- trunk/appswitch
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/appswitch
-
Property svn:ignore
set to
build
*~
.DS_Store
-
Property svn:ignore
set to
-
trunk/appswitch/main.c
r85 r91 19 19 20 20 #include <unistd.h> 21 #include <sys/ioctl.h> 21 22 #include "CPS.h" 22 23 23 24 const char *APP_NAME; 24 25 25 #define VERSION "1.0 d1"26 #define VERSION "1.0b1" 26 27 27 28 struct { … … 32 33 char *path; 33 34 enum { 34 MATCH_UNKNOWN, MATCH_ CREATOR, MATCH_BUNDLE_ID, MATCH_NAME, MATCH_PID, MATCH_PATH35 MATCH_UNKNOWN, MATCH_FRONT, MATCH_CREATOR, MATCH_BUNDLE_ID, MATCH_NAME, MATCH_PID, MATCH_PATH, MATCH_ALL 35 36 } matchType; 37 enum { 38 APP_NONE, APP_SWITCH, APP_SHOW, APP_HIDE, APP_KILL, APP_LIST, APP_PRINT_PID 39 } appAction; 40 enum { 41 ACTION_NONE, ACTION_SHOW_ALL, ACTION_HIDE_OTHERS 42 } action; 43 enum { 44 FINAL_NONE, FINAL_SWITCH 45 } finalAction; 36 46 } OPTS = 37 47 { 38 kLSUnknownCreator, NULL, NULL, -1, NULL, MATCH_UNKNOWN 48 kLSUnknownCreator, NULL, NULL, -1, NULL, MATCH_UNKNOWN, APP_NONE, ACTION_NONE, FINAL_NONE 39 49 }; 40 50 … … 55 65 56 66 void usage() { 57 fprintf(stderr, "usage: %s [-c creator] [-i bundleID] [-a name] [-p pid] [path]\n" 67 fprintf(stderr, "usage: %s [-sShHkFlP] [-c creator] [-i bundleID] [-a name] [-p pid] [path]\n" 68 " -s show application, bring windows to front (do not switch)\n" 69 " -S show all applications\n" 70 " -h hide application\n" 71 " -H hide other applications\n" 72 " -k kill application\n" 73 " -l list applications\n" 74 " -P print application process ID\n" 75 " -F bring current application's windows to front\n" 58 76 " -c creator match application by four-character creator code ('ToyS')\n" 59 77 " -i bundle ID match application by bundle identifier (com.apple.scripteditor)\n" 60 78 " -p pid match application by process identifier [slower]\n" 61 " -a name match application by name\n", APP_NAME); 79 " -a name match application by name\n" 80 , APP_NAME); 62 81 fprintf(stderr, "appswitch "VERSION" (c) 2003 Nicholas Riley <http://web.sabi.net/nriley/software/>.\n" 63 82 "Please send bugs, suggestions, etc. to <appswitch@sabi.net>.\n"); … … 113 132 if (argc == 1) usage(); 114 133 115 const char *opts = "c:i:p:a:"; 116 117 ch = getopt(argc, argv, opts); 118 119 switch (ch) { 120 case 'p': 121 if (sscanf(optarg, "%d", &OPTS.pid) != 1 || OPTS.pid < 0) 122 errexit("invalid process identifier (argument of -p)"); 123 OPTS.matchType = MATCH_PID; 124 break; 125 case 'c': 126 if (strlen(optarg) != 4) errexit("creator (argument of -c) must be four characters long"); 127 OPTS.creator = *(OSTypePtr)optarg; 128 OPTS.matchType = MATCH_CREATOR; 129 break; 130 case 'i': 131 OPTS.bundleID = CFStringCreateWithCString(NULL, optarg, CFStringGetSystemEncoding()); 132 OPTS.matchType = MATCH_BUNDLE_ID; 133 break; 134 case 'a': 135 OPTS.name = strdup(optarg); 136 OPTS.matchType = MATCH_NAME; 137 break; 138 case -1: 139 break; 140 default: usage(); 141 } 142 143 if (getopt(argc, argv, opts) != -1) 144 errexit("choose only one of -c, -i, -u, -p, -a options"); 134 const char *opts = "c:i:p:a:sShHklPF"; 135 136 while ( (ch = getopt(argc, argv, opts)) != -1) { 137 switch (ch) { 138 case 'p': 139 if (OPTS.matchType != MATCH_UNKNOWN) errexit("choose only one of -c, -i, -p, -a options"); 140 if (sscanf(optarg, "%d", &OPTS.pid) != 1 || OPTS.pid < 0) 141 errexit("invalid process identifier (argument of -p)"); 142 OPTS.matchType = MATCH_PID; 143 break; 144 case 'c': 145 if (OPTS.matchType != MATCH_UNKNOWN) errexit("choose only one of -c, -i, -p, -a options"); 146 if (strlen(optarg) != 4) errexit("creator (argument of -c) must be four characters long"); 147 OPTS.creator = *(OSTypePtr)optarg; 148 OPTS.matchType = MATCH_CREATOR; 149 break; 150 case 'i': 151 if (OPTS.matchType != MATCH_UNKNOWN) errexit("choose only one of -c, -i, -p, -a options"); 152 OPTS.bundleID = CFStringCreateWithCString(NULL, optarg, CFStringGetSystemEncoding()); 153 OPTS.matchType = MATCH_BUNDLE_ID; 154 break; 155 case 'a': 156 if (OPTS.matchType != MATCH_UNKNOWN) errexit("choose only one of -c, -i, -p, -a options"); 157 OPTS.name = strdup(optarg); 158 OPTS.matchType = MATCH_NAME; 159 break; 160 case 's': 161 if (OPTS.appAction != APP_NONE) errexit("choose only one of -s, -h, -k, -l, -P options"); 162 OPTS.appAction = APP_SHOW; 163 break; 164 case 'h': 165 if (OPTS.appAction != APP_NONE) errexit("choose only one of -s, -h, -k, -l, -P options"); 166 OPTS.appAction = APP_HIDE; 167 break; 168 case 'k': 169 if (OPTS.appAction != APP_NONE) errexit("choose only one of -s, -h, -k, -l, -P options"); 170 OPTS.appAction = APP_KILL; 171 break; 172 case 'l': 173 if (OPTS.appAction != APP_NONE) errexit("choose only one of -s, -h, -k, -l, -P options"); 174 OPTS.appAction = APP_LIST; 175 break; 176 case 'P': 177 if (OPTS.appAction != APP_NONE) errexit("choose only one of -s, -h, -k, -l, -P options"); 178 OPTS.appAction = APP_PRINT_PID; 179 break; 180 case 'S': 181 if (OPTS.action != ACTION_NONE) errexit("choose -S, -H or neither option"); 182 OPTS.action = ACTION_SHOW_ALL; 183 break; 184 case 'H': 185 if (OPTS.action != ACTION_NONE) errexit("choose -S, -H or neither option"); 186 OPTS.action = ACTION_HIDE_OTHERS; 187 break; 188 case 'F': 189 if (OPTS.finalAction != FINAL_NONE) errexit("choose only one -F option"); 190 OPTS.finalAction = FINAL_SWITCH; 191 break; 192 default: usage(); 193 } 194 } 145 195 146 196 argc -= optind; … … 150 200 151 201 if (OPTS.matchType == MATCH_UNKNOWN) { 152 if (argc != 1) usage(); 153 OPTS.path = argv[0]; 154 OPTS.matchType = MATCH_PATH; 155 } 156 } 157 158 int main (int argc, char * const argv[]) { 159 OSStatus err; 160 161 APP_NAME = argv[0]; 162 getargs(argc, argv); 163 202 if (argc == 0) { 203 if (OPTS.appAction == APP_LIST) { 204 OPTS.matchType = MATCH_ALL; 205 } else if (OPTS.action != ACTION_NONE || OPTS.finalAction != FINAL_NONE) { 206 OPTS.matchType = MATCH_FRONT; 207 } else usage(); 208 } else if (argc == 1) { 209 OPTS.path = argv[0]; 210 OPTS.matchType = MATCH_PATH; 211 } else usage(); 212 } 213 214 if (OPTS.matchType != MATCH_FRONT && OPTS.appAction == APP_NONE) 215 OPTS.appAction = APP_SWITCH; 216 217 } 218 219 CPSProcessSerNum frontApplication() { 220 CPSProcessSerNum psn; 221 OSStatus err = CPSGetFrontProcess(&psn); 222 if (err != noErr) osstatusexit(err, "can't get frontmost process"); 223 #if DEBUG 224 fprintf(stderr, "front application PSN %ld.%ld\n", psn.hi, psn.lo); 225 #endif 226 return psn; 227 } 228 229 CPSProcessSerNum matchApplication(CPSProcessInfoRec *info) { 164 230 long pathMaxLength = pathconf("/", _PC_PATH_MAX); 165 231 long nameMaxLength = pathconf("/", _PC_NAME_MAX); … … 170 236 if (path == NULL || name == NULL) errexit("can't allocate memory for path or filename buffer"); 171 237 172 // need to establish connection with window server173 InitCursor(); 174 238 if (OPTS.matchType == MATCH_FRONT) return frontApplication(); 239 240 OSStatus err; 175 241 CPSProcessSerNum psn = { 176 242 kNoProcess, kNoProcess 177 243 }; 178 CPSProcessInfoRec info;179 244 int len; 245 char *format = NULL; 246 if (OPTS.appAction == APP_LIST) { 247 int termwidth = 80; 248 struct winsize ws; 249 char *banner = " PSN PID TYPE CREA NAME "; 250 // 12345678.0 12345 1234 1234 12345678901234567890 251 printf("%s PATH\n", banner); 252 if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) != -1 || 253 ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) != -1 || 254 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) != -1) || 255 ws.ws_col != 0) termwidth = ws.ws_col; 256 int pathlen = termwidth - strlen(banner) - 1; 257 asprintf(&format, "%%8ld.%%ld %%5ld %%c%%c%%c%%c %%c%%c%%c%%c %%-20.20s %%-%d.%ds\n", pathlen, pathlen); 258 } 259 180 260 while ( (err = CPSGetNextProcess(&psn)) == noErr) { 181 err = CPSGetProcessInfo(&psn, &info, path, pathMaxLength, &len, name, nameMaxLength);261 err = CPSGetProcessInfo(&psn, info, path, pathMaxLength, &len, name, nameMaxLength); 182 262 if (err != noErr) osstatusexit(err, "can't get information for process PSN %ld.%ld", psn.hi, psn.lo); 183 263 … … 185 265 fprintf(stderr, "%ld.%ld: %s : %s\n", psn.hi, psn.lo, name, path); 186 266 #endif 187 267 188 268 switch (OPTS.matchType) { 189 case MATCH_ UNKNOWN:190 break; 191 case MATCH_CREATOR: if (OPTS.creator != info .ExecFileCreator) continue;269 case MATCH_ALL: 270 break; 271 case MATCH_CREATOR: if (OPTS.creator != info->ExecFileCreator) continue; 192 272 break; 193 273 case MATCH_NAME: if (strcmp(name, OPTS.name) != 0) continue; 194 274 break; 195 case MATCH_PID: if (OPTS.pid != info .UnixPID) continue;275 case MATCH_PID: if (OPTS.pid != info->UnixPID) continue; 196 276 break; 197 277 case MATCH_PATH: if (strcmp(path, OPTS.path) != 0) continue; 198 278 break; 199 279 case MATCH_BUNDLE_ID: 200 {201 CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, path, strlen(path), false);202 if (url == NULL) errexit("can't get bundle location for process '%s' (PSN %ld.%ld, pid %d)", name, psn.hi, psn.lo, info.UnixPID);203 CFBundleRef bundle = CFBundleCreate(NULL, url);204 if (bundle != NULL) {205 CFStringRef bundleID = CFBundleGetIdentifier(bundle);280 { 281 CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, path, strlen(path), false); 282 if (url == NULL) errexit("can't get bundle location for process '%s' (PSN %ld.%ld, pid %ld)", name, psn.hi, psn.lo, info->UnixPID); 283 CFBundleRef bundle = CFBundleCreate(NULL, url); 284 if (bundle != NULL) { 285 CFStringRef bundleID = CFBundleGetIdentifier(bundle); 206 286 #if DEBUG 207 CFShow(bundleID);287 CFShow(bundleID); 208 288 #endif 209 if (bundleID != NULL && CFStringCompare(OPTS.bundleID, bundleID, kCFCompareCaseInsensitive) == kCFCompareEqualTo)210 break;211 }212 CFRelease(url);213 continue;214 }289 if (bundleID != NULL && CFStringCompare(OPTS.bundleID, bundleID, kCFCompareCaseInsensitive) == kCFCompareEqualTo) 290 break; 291 } 292 CFRelease(url); 293 continue; 294 } 215 295 default: 216 errexit(" unknownmatch type");296 errexit("internal error: invalid match type"); 217 297 } 218 err = CPSSetFrontProcess(&psn); 219 if (err != noErr) osstatusexit(err, "can't set front process"); 220 exit(0); 298 if (OPTS.appAction == APP_LIST) { 299 char *type = (char *)&(info->ExecFileType), *crea = (char *)&(info->ExecFileCreator); 300 printf(format, psn.hi, psn.lo, info->UnixPID, 301 type[0], type[1], type[2], type[3], 302 crea[0], crea[1], crea[2], crea[3], 303 name, path); 304 continue; 305 } 306 return psn; 221 307 } 222 308 if (err != procNotFound) osstatusexit(err, "can't get next process"); 223 309 310 if (OPTS.appAction == APP_LIST) return frontApplication(); 311 224 312 errexit("can't find matching process"); 225 return 0; 226 } 313 return psn; 314 } 315 316 int main (int argc, char * const argv[]) { 317 OSStatus err = noErr; 318 319 APP_NAME = argv[0]; 320 getargs(argc, argv); 321 322 // need to establish connection with window server 323 InitCursor(); 324 325 CPSProcessInfoRec info; 326 CPSProcessSerNum psn = matchApplication(&info); 327 328 const char *verb; 329 switch (OPTS.appAction) { 330 case APP_NONE: break; 331 case APP_LIST: break; // already handled in matchApplication 332 case APP_SWITCH: err = CPSSetFrontProcess(&psn); verb = "set front"; break; 333 case APP_SHOW: err = CPSPostShowReq(&psn); verb = "show"; break; 334 case APP_HIDE: err = CPSPostHideReq(&psn); verb = "hide"; break; 335 case APP_KILL: err = CPSPostKillRequest(&psn, kNilOptions); verb = "kill"; break; 336 case APP_PRINT_PID: 337 if (info.UnixPID <= 0) errexit("can't get process ID"); 338 printf("%lu\n", info.UnixPID); // pid_t is signed, but this field isn't 339 break; 340 default: 341 errexit("internal error: invalid application action"); 342 } 343 if (err != noErr) osstatusexit(err, "can't %s process", verb); 344 345 switch (OPTS.action) { 346 case ACTION_NONE: break; 347 case ACTION_SHOW_ALL: err = CPSPostShowAllReq(&psn); verb = "show all"; break; 348 case ACTION_HIDE_OTHERS: err = CPSPostHideMostReq(&psn); verb = "hide other"; break; 349 default: 350 errexit("internal error: invalid action"); 351 } 352 if (err != noErr) osstatusexit(err, "can't %s processes", verb); 353 354 switch (OPTS.finalAction) { 355 case FINAL_NONE: break; 356 case FINAL_SWITCH: 357 psn = frontApplication(); 358 #if DEBUG 359 fprintf(stderr, "posting show request for %ld.%ld\n", psn.hi, psn.lo); 360 #endif 361 if (OPTS.action != ACTION_NONE) usleep(750000); // XXX 362 err = CPSPostShowReq(&psn) || CPSSetFrontProcess(&psn); 363 verb = "bring current application's windows to the front"; 364 break; 365 default: 366 errexit("internal error: invalid final action"); 367 } 368 if (err != noErr) osstatusexit(err, "can't %s", verb); 369 370 exit(0); 371 }
Note:
See TracChangeset
for help on using the changeset viewer.