1 /*
2 * (c) 2004 by Kalle Wallin (kaw@linux.se)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <glib.h>
23 #include <ncurses.h>
25 #include "config.h"
27 #ifdef ENABLE_KEYDEF_SCREEN
28 #include "libmpdclient.h"
29 #include "options.h"
30 #include "conf.h"
31 #include "mpc.h"
32 #include "command.h"
33 #include "screen.h"
34 #include "screen_utils.h"
36 #define STATIC_ITEMS 0
37 #define STATIC_SUB_ITEMS 1
38 #define BUFSIZE 256
40 #define LIST_ITEM_APPLY() (command_list_length)
41 #define LIST_ITEM_SAVE() (LIST_ITEM_APPLY()+1)
42 #define LIST_LENGTH() (LIST_ITEM_SAVE()+1)
44 #define LIST_ITEM_SAVE_LABEL "===> Apply & Save key bindings "
45 #define LIST_ITEM_APPLY_LABEL "===> Apply key bindings "
48 static list_window_t *lw = NULL;
49 static int command_list_length = 0;
50 static command_definition_t *cmds = NULL;
52 static int subcmd = -1;
53 static int subcmd_length = 0;
54 static int subcmd_addpos = 0;
56 static int
57 keybindings_changed(void)
58 {
59 command_definition_t *orginal_cmds = get_command_definitions();
60 size_t size = command_list_length*sizeof(command_definition_t);
62 return memcmp(orginal_cmds, cmds, size);
63 }
65 static void
66 apply_keys(void)
67 {
68 if( keybindings_changed() )
69 {
70 command_definition_t *orginal_cmds = get_command_definitions();
71 size_t size = command_list_length*sizeof(command_definition_t);
73 memcpy(orginal_cmds, cmds, size);
74 screen_status_printf("You have new key bindings!");
75 }
76 else
77 screen_status_printf("Keybindings unchanged.");
78 }
80 static int
81 save_keys(void)
82 {
83 FILE *f;
84 char *filename;
86 if( check_user_conf_dir() )
87 {
88 screen_status_printf("Error: Unable to create direcory ~/.ncmpc - %s",
89 strerror(errno));
90 beep();
91 return -1;
92 }
94 filename = get_user_key_binding_filename();
96 if( (f=fopen(filename,"w")) == NULL )
97 {
98 screen_status_printf("Error: %s - %s", filename, strerror(errno));
99 beep();
100 g_free(filename);
101 return -1;
102 }
103 if( write_key_bindings(f) )
104 screen_status_printf("Error: %s - %s", filename, strerror(errno));
105 else
106 screen_status_printf("Wrote %s", filename);
108 g_free(filename);
109 return fclose(f);
110 }
112 static void
113 check_subcmd_length(void)
114 {
115 subcmd_length = 0;
116 while( subcmd_length<MAX_COMMAND_KEYS && cmds[subcmd].keys[subcmd_length]>0 )
117 subcmd_length ++;
119 if( subcmd_length<MAX_COMMAND_KEYS )
120 {
121 subcmd_addpos = subcmd_length;
122 subcmd_length++;
123 }
124 else
125 subcmd_addpos = 0;
126 subcmd_length += STATIC_SUB_ITEMS;
127 }
129 static void
130 delete_key(int cmd_index, int key_index)
131 {
132 int i = key_index+1;
134 screen_status_printf("Delete...");
135 while( i<MAX_COMMAND_KEYS && cmds[cmd_index].keys[i] )
136 cmds[cmd_index].keys[key_index++] = cmds[cmd_index].keys[i++];
137 cmds[cmd_index].keys[key_index] = 0;
139 check_subcmd_length();
140 lw->clear = 1;
141 lw->repaint = 1;
142 }
144 static void
145 assign_new_key(WINDOW *w, int cmd_index, int key_index)
146 {
147 int key;
148 char buf[BUFSIZE];
149 command_t cmd;
151 snprintf(buf, BUFSIZE, "Enter new key for %s: ", cmds[cmd_index].name);
152 key = screen_getch(w, buf);
153 if( key==KEY_RESIZE )
154 screen_resize();
155 if( key==ERR )
156 {
157 screen_status_printf("Aborted!");
158 return;
159 }
160 cmd = find_key_command(key, cmds);
161 if( cmd!=CMD_NONE && cmd!= cmds[cmd_index].command )
162 {
163 screen_status_printf("Error: key %s is already used for %s",
164 key2str(key),
165 get_key_command_name(cmd));
166 beep();
167 return;
168 }
169 cmds[cmd_index].keys[key_index] = key;
170 screen_status_printf("Assigned %s to %s", key2str(key),cmds[cmd_index].name);
171 check_subcmd_length();
172 lw->repaint = 1;
173 }
175 static char *
176 list_callback(int index, int *highlight, void *data)
177 {
178 static char buf[BUFSIZE];
180 if( subcmd <0 )
181 {
182 if( index<command_list_length )
183 return cmds[index].name;
184 else if( index==LIST_ITEM_APPLY() )
185 return LIST_ITEM_APPLY_LABEL;
186 else if( index==LIST_ITEM_SAVE() )
187 return LIST_ITEM_SAVE_LABEL;
188 }
189 else
190 {
191 if( index== 0 )
192 return "[..]";
193 index--;
194 if( index<MAX_COMMAND_KEYS && cmds[subcmd].keys[index]>0 )
195 {
196 snprintf(buf,
197 BUFSIZE, "%d. %-20s (%d) ",
198 index+1,
199 key2str(cmds[subcmd].keys[index]),
200 cmds[subcmd].keys[index]);
201 return buf;
202 }
203 else if ( index==subcmd_addpos )
204 {
205 snprintf(buf, BUFSIZE, "%d. Add new key ", index+1 );
206 return buf;
207 }
208 }
210 return NULL;
211 }
213 static void
214 keydef_init(WINDOW *w, int cols, int rows)
215 {
216 lw = list_window_init(w, cols, rows);
217 }
219 static void
220 keydef_resize(int cols, int rows)
221 {
222 lw->cols = cols;
223 lw->rows = rows;
224 }
226 static void
227 keydef_exit(void)
228 {
229 list_window_free(lw);
230 if( cmds )
231 g_free(cmds);
232 cmds = NULL;
233 lw = NULL;
234 }
236 static void
237 keydef_open(screen_t *screen, mpd_client_t *c)
238 {
239 if( cmds == NULL )
240 {
241 command_definition_t *current_cmds = get_command_definitions();
242 size_t cmds_size;
244 command_list_length = 0;
245 while( current_cmds[command_list_length].name )
246 command_list_length++;
248 cmds_size = (command_list_length+1)*sizeof(command_definition_t);
249 cmds = g_malloc0(cmds_size);
250 memcpy(cmds, current_cmds, cmds_size);
251 command_list_length += STATIC_ITEMS;
252 screen_status_printf("Welcome to the key editor!");
253 }
255 subcmd = -1;
256 list_window_check_selected(lw, LIST_LENGTH());
257 }
259 static void
260 keydef_close(void)
261 {
262 if( cmds && !keybindings_changed() )
263 {
264 g_free(cmds);
265 cmds = NULL;
266 }
267 else
268 screen_status_printf("Note: Did you forget to \'Apply\' your changes?");
269 }
271 static char *
272 keydef_title(void)
273 {
274 static char buf[BUFSIZE];
276 if( subcmd<0 )
277 return (TOP_HEADER_PREFIX "Edit key bindings");
279 snprintf(buf, BUFSIZE,
280 TOP_HEADER_PREFIX "Edit keys for %s",
281 cmds[subcmd].name);
282 return buf;
283 }
285 static void
286 keydef_paint(screen_t *screen, mpd_client_t *c)
287 {
288 lw->clear = 1;
289 list_window_paint(lw, list_callback, NULL);
290 wrefresh(lw->w);
291 }
293 static void
294 keydef_update(screen_t *screen, mpd_client_t *c)
295 {
296 if( lw->repaint )
297 {
298 list_window_paint(lw, list_callback, NULL);
299 wrefresh(lw->w);
300 lw->repaint = 0;
301 }
302 }
304 static int
305 keydef_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
306 {
307 int length = LIST_LENGTH();
309 if( subcmd>=0 )
310 length = subcmd_length;
312 switch(cmd)
313 {
314 case CMD_PLAY:
315 if( subcmd<0 )
316 {
317 if( lw->selected == LIST_ITEM_APPLY() )
318 apply_keys();
319 else if( lw->selected == LIST_ITEM_SAVE() )
320 {
321 apply_keys();
322 save_keys();
323 }
324 else
325 {
326 subcmd = lw->selected;
327 lw->selected=0;
328 check_subcmd_length();
329 }
330 }
331 else
332 {
333 if( lw->selected == 0 ) /* up */
334 {
335 lw->selected = subcmd;
336 subcmd = -1;
337 }
338 else
339 assign_new_key(screen->status_window.w,
340 subcmd,
341 lw->selected-STATIC_SUB_ITEMS);
342 }
343 lw->repaint = 1;
344 lw->clear = 1;
345 return 1;
346 case CMD_DELETE:
347 if( subcmd>=0 && lw->selected-STATIC_SUB_ITEMS>=0 )
348 delete_key(subcmd, lw->selected-STATIC_SUB_ITEMS);
349 return 1;
350 break;
351 case CMD_LIST_FIND:
352 case CMD_LIST_RFIND:
353 case CMD_LIST_FIND_NEXT:
354 case CMD_LIST_RFIND_NEXT:
355 return screen_find(screen, c,
356 lw, length,
357 cmd, list_callback);
359 default:
360 break;
361 }
363 return list_window_cmd(lw, length, cmd);
364 }
366 static list_window_t *
367 keydef_lw(void)
368 {
369 return lw;
370 }
372 screen_functions_t *
373 get_screen_keydef(void)
374 {
375 static screen_functions_t functions;
377 memset(&functions, 0, sizeof(screen_functions_t));
378 functions.init = keydef_init;
379 functions.exit = keydef_exit;
380 functions.open = keydef_open;
381 functions.close = keydef_close;
382 functions.resize = keydef_resize;
383 functions.paint = keydef_paint;
384 functions.update = keydef_update;
385 functions.cmd = keydef_cmd;
386 functions.get_lw = keydef_lw;
387 functions.get_title = keydef_title;
389 return &functions;
390 }
393 #endif