1// profile.vala 2// 3// Copyright 2011 Hong Jen Yee (PCMan) <pcman.tw@pcman.tw@gmail.com> 4// 5// This program is free software; you can redistribute it and/or modify 6// it under the terms of the GNU General Public License as published by 7// the Free Software Foundation; either version 2 of the License, or 8// (at your option) any later version. 9// 10// This program is distributed in the hope that it will be useful, 11// but WITHOUT ANY WARRANTY; without even the implied warranty of 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13// GNU General Public License for more details. 14// 15// You should have received a copy of the GNU General Public License 16// along with this program; if not, write to the Free Software 17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18// MA 02110-1301, USA. 19// 20// 21 22namespace Fm { 23 24public enum FileActionExecMode { 25 NORMAL, 26 TERMINAL, 27 EMBEDDED, 28 DISPLAY_OUTPUT 29} 30 31[Compact] 32public class FileActionProfile { 33 34 public FileActionProfile(KeyFile kf, string profile_name) { 35 id = profile_name; 36 string group_name = @"X-Action-Profile $profile_name"; 37 name = Utils.key_file_get_string(kf, group_name, "Name"); 38 exec = Utils.key_file_get_string(kf, group_name, "Exec"); 39 // stdout.printf("id: %s, Exec: %s\n", id, exec); 40 41 path = Utils.key_file_get_string(kf, group_name, "Path"); 42 var s = Utils.key_file_get_string(kf, group_name, "ExecutionMode"); 43 if(s == "Normal") 44 exec_mode = FileActionExecMode.NORMAL; 45 else if( s == "Terminal") 46 exec_mode = FileActionExecMode.TERMINAL; 47 else if(s == "Embedded") 48 exec_mode = FileActionExecMode.EMBEDDED; 49 else if( s == "DisplayOutput") 50 exec_mode = FileActionExecMode.DISPLAY_OUTPUT; 51 else 52 exec_mode = FileActionExecMode.NORMAL; 53 54 startup_notify = Utils.key_file_get_bool(kf, group_name, "StartupNotify"); 55 startup_wm_class = Utils.key_file_get_string(kf, group_name, "StartupWMClass"); 56 exec_as = Utils.key_file_get_string(kf, group_name, "ExecuteAs"); 57 58 condition = new FileActionCondition(kf, group_name); 59 } 60 61 private bool launch_once(AppLaunchContext ctx, FileInfo? first_file, List<FileInfo> files, out string? output) { 62 if(exec == null) 63 return false; 64 var exec_cmd = FileActionParameters.expand(exec, files, false, first_file); 65 stdout.printf("Profile: %s\nlaunch command: %s\n\n", id, exec_cmd); 66 bool ret = false; 67 if(exec_mode == FileActionExecMode.DISPLAY_OUTPUT) { 68 try{ 69 int exit_status; 70 ret = Process.spawn_command_line_sync(exec_cmd, out output, 71 null, out exit_status); 72 if(ret) 73 ret = (exit_status == 0); 74 } 75 catch(SpawnError err) { 76 } 77 } 78 else { 79 /* 80 AppInfoCreateFlags flags = AppInfoCreateFlags.NONE; 81 if(startup_notify) 82 flags |= AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION; 83 if(exec_mode == FileActionExecMode.TERMINAL || 84 exec_mode == FileActionExecMode.EMBEDDED) 85 flags |= AppInfoCreateFlags.NEEDS_TERMINAL; 86 GLib.AppInfo app = Fm.AppInfo.create_from_commandline(exec, null, flags); 87 stdout.printf("Execute command line: %s\n\n", exec); 88 ret = app.launch(null, ctx); 89 */ 90 91 // NOTE: we cannot use GAppInfo here since GAppInfo does 92 // command line parsing which involving %u, %f, and other 93 // code defined in desktop entry spec. 94 // This may conflict with DES EMA parameters. 95 // FIXME: so how to handle this cleaner? 96 // Maybe we should leave all %% alone and don't translate 97 // them to %. Then GAppInfo will translate them to %, not 98 // codes specified in DES. 99 try { 100 ret = Process.spawn_command_line_async(exec_cmd); 101 } 102 catch(SpawnError err) { 103 } 104 } 105 return ret; 106 } 107 108 public bool launch(AppLaunchContext ctx, List<FileInfo> files, out string? output) { 109 bool plural_form = FileActionParameters.is_plural(exec); 110 bool ret; 111 if(plural_form) { // plural form command, handle all files at a time 112 ret = launch_once(ctx, files.first().data, files, out output); 113 } 114 else { // singular form command, run once for each file 115 StringBuilder all_output = null; 116 if(output != null) 117 all_output = new StringBuilder(); 118 foreach(unowned FileInfo fi in files) { 119 string one_output; 120 launch_once(ctx, fi, files, out one_output); 121 if(all_output != null && one_output != null) { 122 // FIXME: how to handle multiple output strings properly? 123 all_output.append(one_output); // is it ok to join them all? 124 all_output.append("\n"); 125 } 126 } 127 if(all_output != null && output != null) 128 output = (owned) all_output.str; 129 ret = true; 130 } 131 return ret; 132 } 133 134 public bool match(List<FileInfo> files) { 135 stdout.printf(" match profile: %s\n", id); 136 return condition.match(files); 137 } 138 139 public string id; 140 public string? name; 141 public string exec; 142 public string? path; 143 public FileActionExecMode exec_mode; 144 public bool startup_notify; 145 public string? startup_wm_class; 146 public string? exec_as; 147 148 public FileActionCondition condition; 149} 150 151} 152