1 /* LASH Control Panel
2 * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
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 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <string.h>
20 #include <errno.h>
21 #include <unistd.h>
22
23 #include <lash/lash.h>
24 #include <gtk/gtk.h>
25
26 #include "panel.h"
27 #include "project.h"
28 #include "config.h"
29
30 #define WINDOW_TITLE "LASH Control Panel"
31
32 void quit_cb(GtkButton * button, void *data);
33
34 project_t *
get_project(panel_t * panel,const char * const name)35 get_project(panel_t * panel, const char *const name)
36 {
37 project_t *project = NULL;
38 GtkTreeModel *tree_model = GTK_TREE_MODEL(panel->projects);
39 GtkTreeIter iter;
40
41 if (gtk_tree_model_get_iter_first(tree_model, &iter))
42 do {
43 gtk_tree_model_get(tree_model, &iter, PROJECT_PROJECT_COLUMN,
44 &project, -1);
45
46 if (!strcmp(name, project->name))
47 return project;
48
49 } while (gtk_tree_model_iter_next(tree_model, &iter));
50
51 fprintf(stderr, "Error: Unable to find project '%s'!", name);
52 return NULL;
53 }
54
55 void
error_dialog(panel_t * client,const char * message)56 error_dialog(panel_t * client, const char *message)
57 {
58 GtkWidget *dialog;
59 gint response;
60
61 dialog =
62 gtk_message_dialog_new(GTK_WINDOW(client->window),
63 GTK_DIALOG_DESTROY_WITH_PARENT |
64 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
65 GTK_BUTTONS_OK, "%s", message);
66
67 response = gtk_dialog_run(GTK_DIALOG(dialog));
68 gtk_widget_destroy(dialog);
69 }
70
71
72 void
about_cb(GtkButton * button,void * client)73 about_cb(GtkButton* button, void* client)
74 {
75 /*panel_t* panel = (panel_t*)client;*/
76 GtkWidget *dialog;
77 gint response;
78
79 dialog = gtk_about_dialog_new();
80 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), "LASH Panel");
81 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), PACKAGE_VERSION);
82 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog),
83 "Copyright (C) 2006 Dave Robillard");
84 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog),
85 "http://www.nongnu.org/lash");
86
87
88
89 response = gtk_dialog_run(GTK_DIALOG(dialog));
90 gtk_widget_destroy(dialog);
91 }
92
93
94 void
server_disconnect(panel_t * panel)95 server_disconnect(panel_t * panel)
96 {
97 error_dialog(panel, "The server disconnected!");
98
99 exit(0);
100 }
101
102 void
event_project_add(panel_t * panel,lash_event_t * event)103 event_project_add(panel_t * panel, lash_event_t * event)
104 {
105 project_t *project = NULL;
106 const char *name = lash_event_get_string(event);
107 GtkTreeIter iter;
108
109 printf("Add project: %s\n", name);
110
111 if (panel->num_projects == 0)
112 gtk_label_set_text(GTK_LABEL(panel->no_projects_label), "");
113
114 gtk_list_store_append(panel->projects, &iter);
115
116 project = project_create(panel->lash_client, name);
117
118 gtk_list_store_set(panel->projects, &iter,
119 PROJECT_PROJECT_COLUMN, project, -1);
120
121 project->page_number =
122 gtk_notebook_append_page(GTK_NOTEBOOK(panel->project_notebook),
123 project->box, project->tab_label);
124
125 panel->num_projects++;
126 }
127
128 void
event_project_remove(panel_t * panel,lash_event_t * event)129 event_project_remove(panel_t * panel, lash_event_t * event)
130 {
131 const char *name = lash_event_get_string(event);
132 project_t *project = get_project(panel, name);
133 GtkTreeModel *tree_model = GTK_TREE_MODEL(panel->projects);
134 GtkTreeIter iter;
135
136 printf("Remove project: %s\n", name);
137
138 if (panel->num_projects == 1)
139 gtk_label_set_text(GTK_LABEL(panel->no_projects_label),
140 "(No projects open. Start a LASH client, or load a project from the File menu)");
141
142 if (project != NULL)
143 if (gtk_tree_model_get_iter_first(tree_model, &iter))
144 do {
145 gtk_tree_model_get(tree_model, &iter, PROJECT_PROJECT_COLUMN,
146 &project, -1);
147
148 if (!strcmp(name, project->name)) {
149 gtk_list_store_remove(panel->projects, &iter);
150 gtk_notebook_remove_page(GTK_NOTEBOOK
151 (panel->project_notebook),
152 project->page_number);
153 project_destroy(project);
154 break;
155 }
156 } while (gtk_tree_model_iter_next(tree_model, &iter));
157
158 panel->num_projects--;
159 }
160
161 void
event_project_dir(panel_t * panel,lash_event_t * event)162 event_project_dir(panel_t * panel, lash_event_t * event)
163 {
164 const char *name = lash_event_get_project(event);
165 const char *dir = lash_event_get_string(event);
166 project_t *project = get_project(panel, name);
167
168 printf("Change project dir: %s = %s\n", name, dir);
169
170 if (project != NULL) {
171 project_set_dir(project, dir);
172 }
173 }
174
175 void
event_project_name(panel_t * panel,lash_event_t * event)176 event_project_name(panel_t * panel, lash_event_t * event)
177 {
178 const char *old_name = lash_event_get_project(event);
179 const char *new_name = lash_event_get_string(event);
180 project_t *project = get_project(panel, old_name);
181
182 printf("Change project name: %s = %s\n", old_name, new_name);
183
184 if (project != NULL)
185 project_set_name(project, new_name);
186 }
187
188 void
event_client_add(panel_t * panel,lash_event_t * event)189 event_client_add(panel_t * panel, lash_event_t * event)
190 {
191 const char *project_name = lash_event_get_project(event);
192 project_t *project = get_project(panel, project_name);
193 char *client_id_str = malloc(37);
194 char *search_id_str = NULL;
195 uuid_t client_id;
196 GtkTreeIter iter;
197 GtkTreeModel *tree_model;
198 int client_exists = FALSE;
199
200 lash_event_get_client_id(event, client_id);
201 uuid_unparse(client_id, client_id_str);
202
203 printf("Add client (%s): %s\n", project_name, client_id_str);
204
205 if (client_id != NULL && project != NULL) {
206 tree_model = GTK_TREE_MODEL(project->clients);
207
208 if (gtk_tree_model_get_iter_first(tree_model, &iter)) {
209 do {
210 gtk_tree_model_get(tree_model, &iter, CLIENT_ID_COLUMN, &search_id_str, -1);
211
212 if (!strcmp(search_id_str, client_id_str)) {
213 client_exists = TRUE;
214 break;
215 }
216 } while (gtk_tree_model_iter_next(tree_model, &iter));
217 }
218 if (!client_exists) {
219 gtk_list_store_append(project->clients, &iter);
220 gtk_list_store_set(project->clients, &iter,
221 CLIENT_ID_COLUMN, client_id_str, -1);
222 }
223 }
224 }
225
226 void
event_client_name(panel_t * panel,lash_event_t * event)227 event_client_name(panel_t * panel, lash_event_t * event)
228 {
229 const char *project_name = lash_event_get_project(event);
230 const char *client_name = lash_event_get_string(event);
231 project_t *project = get_project(panel, project_name);
232 GtkTreeModel *tree_model = NULL;
233 GtkTreeIter iter;
234 uuid_t client_id;
235 char *search_id_str = NULL;
236 char *client_id_str = malloc(37);
237
238 lash_event_get_client_id(event, client_id);
239 uuid_unparse(client_id, client_id_str);
240
241 printf("Change client name (%s): %s = %s\n", project_name, client_id_str,
242 client_name);
243
244 if (project != NULL) {
245 tree_model = GTK_TREE_MODEL(project->clients);
246
247 if (gtk_tree_model_get_iter_first(tree_model, &iter))
248 do {
249 gtk_tree_model_get(tree_model, &iter, CLIENT_ID_COLUMN,
250 &search_id_str, -1);
251
252 if (!strcmp(search_id_str, client_id_str)) {
253 gtk_list_store_set(project->clients, &iter,
254 CLIENT_NAME_COLUMN, client_name, -1);
255 break;
256 }
257 } while (gtk_tree_model_iter_next(tree_model, &iter));
258 }
259 }
260
261 void
deal_with_event(panel_t * panel,lash_event_t * event)262 deal_with_event(panel_t * panel, lash_event_t * event)
263 {
264 switch (lash_event_get_type(event)) {
265 case LASH_Project_Add:
266 event_project_add(panel, event);
267 break;
268 case LASH_Project_Remove:
269 event_project_remove(panel, event);
270 break;
271 case LASH_Project_Dir:
272 event_project_dir(panel, event);
273 break;
274 case LASH_Project_Name:
275 event_project_name(panel, event);
276 break;
277 case LASH_Client_Add:
278 event_client_add(panel, event);
279 break;
280 case LASH_Client_Name:
281 event_client_name(panel, event);
282 break;
283 case LASH_Jack_Client_Name:
284 break;
285 case LASH_Alsa_Client_ID:
286 break;
287 case LASH_Percentage:
288 break;
289 default:
290 break;
291 }
292 }
293
294 gboolean
idle_cb(gpointer data)295 idle_cb(gpointer data)
296 {
297 panel_t *panel;
298 lash_event_t *event;
299
300 /*lash_config_t * config; */
301
302 panel = (panel_t *) data;
303
304 while ((event = lash_get_event(panel->lash_client))) {
305 deal_with_event(panel, event);
306 }
307
308 /*while ((config = lash_get_config(panel->lash_client)) ) {
309 * add_config(panel, config);
310 * } */
311
312 return TRUE;
313 }
314
315 void
quit_cb(GtkButton * button,void * data)316 quit_cb(GtkButton * button, void *data)
317 {
318 gtk_main_quit();
319 }
320
321 void
open_cb(GtkButton * button,void * data)322 open_cb(GtkButton * button, void *data)
323 {
324 panel_t *panel = (panel_t *) data;
325 int response = GTK_RESPONSE_NONE;
326 char *filename = NULL;
327 lash_event_t *event = NULL;
328
329 GtkWidget *open_dialog =
330 gtk_file_chooser_dialog_new("Open Project", GTK_WINDOW(panel->window),
331 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
332 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
333 GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
334
335 char default_dir[256];
336 snprintf(default_dir, 256, "%s/%s", getenv("HOME"), DEFAULT_PROJECT_DIR);
337 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(open_dialog),
338 default_dir);
339
340 response = gtk_dialog_run(GTK_DIALOG(open_dialog));
341
342 if (response == GTK_RESPONSE_OK) {
343 filename =
344 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(open_dialog));
345 event = lash_event_new_with_type(LASH_Project_Add);
346 lash_event_set_string(event, filename);
347 lash_send_event(panel->lash_client, event);
348 }
349
350 gtk_widget_destroy(open_dialog);
351 }
352
353 panel_t *
panel_create(lash_client_t * lash_client)354 panel_create(lash_client_t * lash_client)
355 {
356 panel_t *panel = NULL;
357 GtkWidget *main_box = NULL;
358
359 GtkWidget *menu_bar = NULL;
360 GtkWidget *file_menu = NULL;
361 GtkWidget *file_menuitem = NULL;
362 GtkWidget *help_menu = NULL;
363 GtkWidget *help_menuitem = NULL;
364 GtkWidget *open_menu_item = NULL;
365 GtkWidget *menu_separator = NULL;
366 GtkWidget *quit_menu_item = NULL;
367 GtkWidget *about_menu_item = NULL;
368
369 guint status_context;
370
371 panel = malloc(sizeof(panel_t));
372 panel->lash_client = lash_client;
373
374 panel->projects = gtk_list_store_new(PROJECT_NUM_COLUMNS, G_TYPE_POINTER);
375 panel->num_projects = 0;
376
377 panel->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
378 gtk_window_set_title(GTK_WINDOW(panel->window), WINDOW_TITLE);
379 gtk_window_set_default_size(GTK_WINDOW(panel->window), 450, 282);
380 g_signal_connect(G_OBJECT(panel->window), "delete_event",
381 G_CALLBACK(quit_cb), NULL);
382
383 main_box = gtk_vbox_new(FALSE, 0);
384 gtk_widget_show(main_box);
385 gtk_container_add(GTK_CONTAINER(panel->window), main_box);
386
387 /*
388 * menu bar
389 */
390 file_menu = gtk_menu_new();
391
392 open_menu_item = gtk_image_menu_item_new_with_label("Open Project...");
393 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(open_menu_item),
394 gtk_image_new_from_stock(GTK_STOCK_OPEN,
395 GTK_ICON_SIZE_MENU));
396 gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), open_menu_item);
397 g_signal_connect(G_OBJECT(open_menu_item), "activate",
398 G_CALLBACK(open_cb), panel);
399 gtk_widget_show(open_menu_item);
400
401 menu_separator = gtk_separator_menu_item_new();
402 gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), menu_separator);
403 gtk_widget_show(menu_separator);
404
405 quit_menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
406 gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), quit_menu_item);
407 g_signal_connect(G_OBJECT(quit_menu_item), "activate",
408 G_CALLBACK(quit_cb), panel);
409 gtk_widget_show(quit_menu_item);
410
411 file_menuitem = gtk_menu_item_new_with_label("File");
412 gtk_widget_show(file_menuitem);
413 gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_menuitem), file_menu);
414
415 help_menu = gtk_menu_new();
416 help_menuitem = gtk_menu_item_new_with_label("Help");
417 gtk_widget_show(help_menuitem);
418 gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_menuitem), help_menu);
419
420 about_menu_item = gtk_image_menu_item_new_with_label("About...");
421 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(about_menu_item),
422 gtk_image_new_from_stock(GTK_STOCK_ABOUT,
423 GTK_ICON_SIZE_MENU));
424 gtk_menu_shell_append(GTK_MENU_SHELL(help_menu), about_menu_item);
425 g_signal_connect(G_OBJECT(about_menu_item), "activate",
426 G_CALLBACK(about_cb), panel);
427
428 gtk_widget_show(about_menu_item);
429
430 menu_bar = gtk_menu_bar_new();
431 gtk_widget_show(menu_bar);
432 gtk_box_pack_start(GTK_BOX(main_box), menu_bar, FALSE, TRUE, 0);
433
434 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), file_menuitem);
435 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), help_menuitem);
436
437 /*
438 * projects notebook
439 */
440 panel->project_notebook = gtk_notebook_new();
441 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(panel->project_notebook),
442 GTK_POS_TOP);
443 gtk_widget_show(panel->project_notebook);
444 gtk_box_pack_start(GTK_BOX(main_box), panel->project_notebook, TRUE, TRUE, 0);
445
446 /*
447 * "no project" label (shown instead of a notebook tab when no projects are present)
448 */
449 panel->no_projects_label = gtk_label_new("No projects open. Start a LASH client, or load a project from the File menu.");
450 gtk_widget_show(panel->no_projects_label);
451 gtk_box_pack_start(GTK_BOX(main_box), panel->no_projects_label, FALSE, TRUE, 10);
452
453 /*
454 * status bar
455 */
456 panel->status_bar = gtk_statusbar_new();
457 gtk_widget_show(panel->status_bar);
458 status_context =
459 gtk_statusbar_get_context_id(GTK_STATUSBAR(panel->status_bar),
460 "connected");
461 gtk_statusbar_push(GTK_STATUSBAR(panel->status_bar), status_context,
462 g_strdup_printf("Connected to server %s",
463 lash_get_server_name(lash_client)));
464 gtk_box_pack_start(GTK_BOX(main_box), panel->status_bar, FALSE, TRUE, 0);
465
466 gtk_timeout_add(1000, idle_cb, panel);
467 gtk_widget_show(panel->window);
468
469 return panel;
470 }
471