]> sigrok.org Git - sigrok-gtk.git/blob - toolbar.c
sr: Implement proper logging framework.
[sigrok-gtk.git] / toolbar.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdlib.h>
21
22 #include <sigrok.h>
23
24 #include <gtk/gtk.h>
25
26 #include <stdlib.h>
27
28 #include "sigrok-gtk.h"
29
30 enum {
31         DEV_PROP_CAPABILITY,
32         DEV_PROP_TYPE,
33         DEV_PROP_SHORTNAME,
34         DEV_PROP_DESCRIPTION,
35         DEV_PROP_IS_TEXT,
36         DEV_PROP_TEXTVALUE,
37         DEV_PROP_BOOLVALUE,
38         MAX_DEV_PROP
39 };
40
41 static void prop_edited(GtkCellRendererText *cel, gchar *path, gchar *text,
42                         GtkListStore *props)
43 {
44         (void)cel;
45
46         struct sr_device *device = g_object_get_data(G_OBJECT(props), "device");
47         GtkTreeIter iter;
48         int type, cap;
49         guint64 tmp_u64;
50         int ret = SR_ERR;
51
52         gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(props), &iter, path);
53         gtk_tree_model_get(GTK_TREE_MODEL(props), &iter,
54                                         DEV_PROP_CAPABILITY, &cap, 
55                                         DEV_PROP_TYPE, &type, -1);
56
57         switch (type) {
58         case SR_T_UINT64:
59                 if (sr_parse_sizestring(text, &tmp_u64) != SR_OK)
60                         return;
61
62                 ret = device->plugin->set_configuration(device->plugin_index,
63                                 cap, &tmp_u64);
64                 break;
65         case SR_T_CHAR:
66                 ret = device->plugin-> set_configuration(device->plugin_index,
67                                 cap, text);
68                 break;
69         /* SR_T_BOOL will be handled by prop_toggled */
70         }
71
72         if (!ret)
73                 gtk_list_store_set(props, &iter, DEV_PROP_TEXTVALUE, text, -1);
74 }
75
76 static void prop_toggled(GtkCellRendererToggle *cel, gchar *path,
77                         GtkListStore *props)
78 {
79         struct sr_device *device = g_object_get_data(G_OBJECT(props), "device");
80         GtkTreeIter iter;
81         int type, cap;
82         int ret;
83         gboolean val;
84         gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(props), &iter, path);
85         gtk_tree_model_get(GTK_TREE_MODEL(props), &iter,
86                                         DEV_PROP_CAPABILITY, &cap, 
87                                         DEV_PROP_TYPE, &type, -1);
88
89         val = !gtk_cell_renderer_toggle_get_active(cel);
90         ret = device->plugin-> set_configuration(device->plugin_index, cap, 
91                                         GINT_TO_POINTER(val));
92
93         if (!ret)
94                 gtk_list_store_set(props, &iter, DEV_PROP_BOOLVALUE, val, -1);
95 }
96
97 void dev_prop_bool_data_func(GtkCellLayout *cell_layout,
98                                 GtkCellRenderer *cell,
99                                 GtkTreeModel *tree_model,
100                                 GtkTreeIter *iter,
101                                 gpointer data)
102 {
103         (void)cell_layout;
104         (void)data;
105
106         gboolean istext, val;
107         gtk_tree_model_get(tree_model, iter, 
108                                 DEV_PROP_IS_TEXT, &istext, 
109                                 DEV_PROP_BOOLVALUE, &val, -1);
110         g_object_set(G_OBJECT(cell), "visible", !istext, "active", val, NULL);
111 }
112
113 static void dev_set_options(GtkAction *action, GtkWindow *parent)
114 {
115         (void)action;
116
117         struct sr_device *device = g_object_get_data(G_OBJECT(parent), "device");
118         if (!device)
119                 return;
120
121         GtkWidget *dialog = gtk_dialog_new_with_buttons("Device Properties",
122                                         parent, GTK_DIALOG_MODAL,
123                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
124                                         NULL);
125         GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
126         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
127                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
128         gtk_widget_set_size_request(sw, 300, 200);
129         GtkWidget *tv = gtk_tree_view_new();
130         gtk_container_add(GTK_CONTAINER(sw), tv);
131         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), sw,
132                                 TRUE, TRUE, 0);
133
134         /* Populate list store with config options */
135         GtkListStore *props = gtk_list_store_new(MAX_DEV_PROP, 
136                                         G_TYPE_INT, G_TYPE_INT,
137                                         G_TYPE_STRING, G_TYPE_STRING,
138                                         G_TYPE_BOOLEAN, G_TYPE_STRING,
139                                         G_TYPE_BOOLEAN);
140         gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(props));
141         int *capabilities = device->plugin->get_capabilities();
142         int cap;
143         GtkTreeIter iter;
144         for (cap = 0; capabilities[cap]; cap++) {
145                 struct sr_hwcap_option *hwo;
146                 if (!(hwo = sr_find_hwcap_option(capabilities[cap])))
147                         continue;
148                 gtk_list_store_append(props, &iter);
149                 gtk_list_store_set(props, &iter, 
150                                         DEV_PROP_CAPABILITY, capabilities[cap],
151                                         DEV_PROP_TYPE, hwo->type,
152                                         DEV_PROP_SHORTNAME, hwo->shortname,
153                                         DEV_PROP_DESCRIPTION, hwo->description,
154                                         DEV_PROP_IS_TEXT, hwo->type != SR_T_BOOL,
155                                         -1);
156         }
157
158         /* Popup tooltop containing description if mouse hovers */
159         gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(tv), 
160                                         DEV_PROP_DESCRIPTION);
161
162         /* Save device with list so that property can be set by edited
163          * handler. */
164         g_object_set_data(G_OBJECT(props), "device", device);
165
166         /* Add columns to the tree view */
167         GtkTreeViewColumn *col;
168         col = gtk_tree_view_column_new_with_attributes("Property",
169                                 gtk_cell_renderer_text_new(),
170                                 "text", DEV_PROP_SHORTNAME, NULL);
171         gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col);
172         /* We pack both a text and toggle renderer.  Only one will be visible.
173          * depending on type.
174          */
175         GtkCellRenderer *cel = gtk_cell_renderer_text_new();
176         g_object_set(cel, "editable", TRUE, NULL);
177         g_signal_connect(cel, "edited", G_CALLBACK(prop_edited), props);
178         col = gtk_tree_view_column_new_with_attributes("Value",
179                                 cel, "text", DEV_PROP_TEXTVALUE, 
180                                 "visible", DEV_PROP_IS_TEXT, NULL);
181         cel = gtk_cell_renderer_toggle_new();
182         g_signal_connect(cel, "toggled", G_CALLBACK(prop_toggled), props);
183         gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(col), cel, TRUE);
184         gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(col), cel, 
185                                 dev_prop_bool_data_func, NULL, NULL);
186         gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col);
187
188
189         gtk_widget_show_all(dialog);
190         gtk_dialog_run(GTK_DIALOG(dialog));
191
192         gtk_widget_destroy(dialog);
193 }
194
195 enum {
196         PROBE_NUMBER,
197         PROBE_ENABLED,
198         PROBE_NAME,
199         PROBE_TRIGGER,
200         MAX_PROBE
201 };
202
203 static void probe_toggled(GtkCellRenderer *cel, gchar *path,
204                         GtkTreeModel *probes)
205 {
206         struct sr_device *device = g_object_get_data(G_OBJECT(probes), "device");
207         GtkTreeIter iter;
208         struct sr_probe *probe;
209         gint i;
210         gboolean en;
211
212         (void)cel;
213
214         gtk_tree_model_get_iter_from_string(probes, &iter, path);
215         gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, 
216                                         PROBE_ENABLED, &en, -1);
217         probe = sr_device_probe_find(device, i);
218         probe->enabled = !en;
219         gtk_list_store_set(GTK_LIST_STORE(probes), &iter, 
220                                         PROBE_ENABLED, probe->enabled, -1);
221 }
222
223 static void probe_named(GtkCellRendererText *cel, gchar *path, gchar *text,
224                         GtkTreeModel *probes)
225 {
226         struct sr_device *device = g_object_get_data(G_OBJECT(probes), "device");
227         GtkTreeIter iter;
228         gint i;
229
230         (void)cel;
231
232         gtk_tree_model_get_iter_from_string(probes, &iter, path);
233         gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, -1);
234         sr_device_probe_name(device, i, text);
235         gtk_list_store_set(GTK_LIST_STORE(probes), &iter, PROBE_NAME, text, -1);
236 }
237
238 static void probe_trigger_set(GtkCellRendererText *cel, gchar *path, 
239                         gchar *text, GtkTreeModel *probes)
240 {
241         struct sr_device *device = g_object_get_data(G_OBJECT(probes), "device");
242         GtkTreeIter iter;
243         gint i;
244
245         (void)cel;
246
247         gtk_tree_model_get_iter_from_string(probes, &iter, path);
248         gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, -1);
249         sr_device_trigger_set(device, i, text);
250         gtk_list_store_set(GTK_LIST_STORE(probes), &iter, 
251                                         PROBE_TRIGGER, text, -1);
252 }
253
254 static void dev_set_probes(GtkAction *action, GtkWindow *parent)
255 {
256         (void)action;
257
258         struct sr_device *device = g_object_get_data(G_OBJECT(parent), "device");
259         if (!device)
260                 return;
261
262         GtkWidget *dialog = gtk_dialog_new_with_buttons("Configure Probes",
263                                         parent, GTK_DIALOG_MODAL,
264                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
265                                         NULL);
266         GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
267         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
268                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
269         gtk_widget_set_size_request(sw, 300, 200);
270         GtkWidget *tv = gtk_tree_view_new();
271         gtk_container_add(GTK_CONTAINER(sw), tv);
272         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), sw,
273                                 TRUE, TRUE, 0);
274
275         /* Populate list store with probe options */
276         GtkListStore *probes = gtk_list_store_new(MAX_PROBE, 
277                                         G_TYPE_INT, G_TYPE_BOOLEAN,
278                                         G_TYPE_STRING, GTK_TYPE_STRING);
279         gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(probes));
280         GtkTreeIter iter;
281         GSList *p;
282         int i;
283         for (p = device->probes, i = 1; p; p = g_slist_next(p), i++) {
284                 struct sr_probe *probe = p->data;
285                 gtk_list_store_append(probes, &iter);
286                 gtk_list_store_set(probes, &iter, PROBE_NUMBER, i,
287                                         PROBE_ENABLED, probe->enabled, 
288                                         PROBE_NAME, probe->name, 
289                                         PROBE_TRIGGER, probe->trigger, 
290                                         -1);
291         }
292
293         /* Save device with list so that property can be set by edited
294          * handler. */
295         g_object_set_data(G_OBJECT(probes), "device", device);
296
297         /* Add columns to the tree view */
298         GtkTreeViewColumn *col;
299         col = gtk_tree_view_column_new_with_attributes("Probe",
300                                 gtk_cell_renderer_text_new(),
301                                 "text", PROBE_NUMBER, NULL);
302         gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col);
303         GtkCellRenderer *cel = gtk_cell_renderer_toggle_new();
304         g_object_set(cel, "activatable", TRUE, NULL);
305         g_signal_connect(cel, "toggled", G_CALLBACK(probe_toggled), probes);
306         col = gtk_tree_view_column_new_with_attributes("En",
307                                 cel, "active", PROBE_ENABLED, NULL);
308         gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col);
309         cel = gtk_cell_renderer_text_new();
310         g_object_set(cel, "editable", TRUE, NULL);
311         g_signal_connect(cel, "edited", G_CALLBACK(probe_named), probes);
312         col = gtk_tree_view_column_new_with_attributes("Signal Name", cel, 
313                                         "text", PROBE_NAME, 
314                                         "sensitive", PROBE_ENABLED, NULL);
315         gtk_tree_view_column_set_resizable(col, TRUE);
316         gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col);
317         cel = gtk_cell_renderer_text_new();
318         g_object_set(cel, "editable", TRUE, NULL);
319         g_signal_connect(cel, "edited", G_CALLBACK(probe_trigger_set), probes);
320         col = gtk_tree_view_column_new_with_attributes("Trigger", cel, 
321                                         "text", PROBE_TRIGGER, 
322                                         "sensitive", PROBE_ENABLED, NULL);
323         gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col);
324
325         gtk_widget_show_all(dialog);
326         gtk_dialog_run(GTK_DIALOG(dialog));
327
328         gtk_widget_destroy(dialog);
329 }
330
331 static void capture_run(GtkAction *action, GObject *parent)
332 {
333         (void)action;
334
335         struct sr_device *device = g_object_get_data(G_OBJECT(parent), "device");
336         GtkEntry *timesamples = g_object_get_data(parent, "timesamples");
337         GtkComboBox *timeunit = g_object_get_data(parent, "timeunit");
338         gint i = gtk_combo_box_get_active(timeunit);
339         guint64 time_msec = 0;
340         guint64 limit_samples = 0;
341         
342         switch (i) {
343         case 0: /* Samples */
344                 sr_parse_sizestring(gtk_entry_get_text(timesamples), 
345                                 &limit_samples);
346                 break;
347         case 1: /* Milliseconds */
348                 time_msec = strtoull(gtk_entry_get_text(timesamples), NULL, 10);
349                 break;
350         case 2: /* Seconds */
351                 time_msec = strtoull(gtk_entry_get_text(timesamples), NULL, 10)
352                                 * 1000;
353                 break;
354         }
355
356         if (time_msec) {
357                 int *capabilities = device->plugin->get_capabilities();
358                 if (sr_find_hwcap(capabilities, SR_HWCAP_LIMIT_MSEC)) {
359                         if (device->plugin->set_configuration(device->plugin_index,
360                                                         SR_HWCAP_LIMIT_MSEC,
361                                                         &time_msec) != SR_OK) {
362                                 g_critical("Failed to configure time limit.");
363                                 sr_session_destroy();
364                                 return;
365                         }
366                 } else {
367                         /* time limit set, but device doesn't support this...
368                          * convert to samples based on the samplerate.
369                          */
370                         limit_samples = 0;
371                         if (sr_device_has_hwcap(device, SR_HWCAP_SAMPLERATE)) {
372                                 guint64 tmp_u64;
373                                 tmp_u64 = *((uint64_t *) device->plugin->get_device_info(
374                                                         device->plugin_index,
375                                                         SR_DI_CUR_SAMPLERATE));
376                                 limit_samples = tmp_u64 * time_msec / (uint64_t) 1000;
377                         }
378                         if (limit_samples == 0) {
379                                 g_critical("Not enough time at this samplerate.");
380                                 return;
381                         }
382
383                         if (device->plugin->set_configuration(device->plugin_index,
384                                                 SR_HWCAP_LIMIT_SAMPLES,
385                                                 &limit_samples) != SR_OK) {
386                                 g_critical("Failed to configure time-based sample limit.");
387                                 return;
388                         }
389                 }
390         }
391         if (limit_samples) {
392                 if (device->plugin->set_configuration(device->plugin_index,
393                                                 SR_HWCAP_LIMIT_SAMPLES,
394                                                 &limit_samples) != SR_OK) {
395                         g_critical("Failed to configure sample limit.");
396                         return;
397                 }
398         }
399
400         if (device->plugin->set_configuration(device->plugin_index,
401                   SR_HWCAP_PROBECONFIG, (char *)device->probes) != SR_OK) {
402                 printf("Failed to configure probes.\n");
403                 sr_session_destroy();
404                 return;
405         }
406
407         if (sr_session_start() != SR_OK) {
408                 g_critical("Failed to start session.");
409                 return;
410         }
411
412         sr_session_run();
413 }
414
415 static void dev_file_open(GtkAction *action, GtkWindow *parent)
416 {
417         (void)action;
418         static GtkWidget *dialog;
419         const gchar *filename;
420
421         if(!dialog)
422                 dialog = gtk_file_chooser_dialog_new("Open", parent,
423                                 GTK_FILE_CHOOSER_ACTION_OPEN,
424                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
425                                 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
426         g_signal_connect(dialog, "delete-event",
427                                         G_CALLBACK(gtk_widget_hide_on_delete),
428                                         NULL);
429
430         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
431                 /* Dialog was cancelled or closed */
432                 gtk_widget_hide(dialog);
433                 return;
434         }
435
436         gtk_widget_hide(dialog);
437
438         filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
439         load_input_file(parent, filename);
440 }
441
442 void toggle_log(GtkToggleAction *action, GObject *parent)
443 {
444         GtkWidget *log = g_object_get_data(parent, "logview");
445         gtk_widget_set_visible(log, gtk_toggle_action_get_active(action));
446 }
447
448 void zoom_in(GtkAction *action, GObject *parent)
449 {
450         (void)action;
451
452         GtkWidget *sigview = g_object_get_data(parent, "sigview");
453         sigview_zoom(sigview, 1.5, 0);
454 }
455
456 void zoom_out(GtkAction *action, GObject *parent)
457 {
458         (void)action;
459
460         GtkWidget *sigview = g_object_get_data(parent, "sigview");
461         sigview_zoom(sigview, 1/1.5, 0);
462 }
463
464 void zoom_fit(GtkAction *action, GObject *parent)
465 {
466         (void)action;
467
468         GtkWidget *sigview = g_object_get_data(parent, "sigview");
469         sigview_zoom(sigview, 0, 0);
470 }
471
472 static const GtkActionEntry action_items[] = {
473         /* name, stock-id, label, accel, tooltip, callback */
474         {"DevMenu", NULL, "_Device", NULL, NULL, NULL},
475         {"DevOpen", GTK_STOCK_OPEN, "_Open", "<control>O",
476                 "Open Session File", G_CALLBACK(dev_file_open)},
477         {"DevSelectMenu", NULL, "Select Device", NULL, NULL, NULL},
478         {"DevRescan", GTK_STOCK_REFRESH, "_Rescan", "<control>R",
479                 "Rescan for LA devices", G_CALLBACK(dev_select_rescan)},
480         {"DevProperties", GTK_STOCK_PROPERTIES, "_Properties", "<control>P",
481                 "Configure LA", G_CALLBACK(dev_set_options)},
482         {"DevProbes", GTK_STOCK_COLOR_PICKER, "_Probes", "<control>O",
483                 "Configure Probes", G_CALLBACK(dev_set_probes)},
484         {"DevAcquire", GTK_STOCK_EXECUTE, "_Acquire", "<control>A",
485                 "Acquire Samples", G_CALLBACK(capture_run)},
486         {"Exit", GTK_STOCK_QUIT, "E_xit", "<control>Q",
487                 "Exit the program", G_CALLBACK(gtk_main_quit) },
488
489         {"ViewMenu", NULL, "_View", NULL, NULL, NULL},
490         {"ViewZoomIn", GTK_STOCK_ZOOM_IN, "Zoom _In", "<control>z", NULL,
491                 G_CALLBACK(zoom_in)},
492         {"ViewZoomOut", GTK_STOCK_ZOOM_OUT, "Zoom _Out", "<control><shift>Z",
493                 NULL, G_CALLBACK(zoom_out)},
494         {"ViewZoomFit", GTK_STOCK_ZOOM_FIT, NULL, NULL,
495                 NULL, G_CALLBACK(zoom_fit)},
496
497         {"HelpMenu", NULL, "_Help", NULL, NULL, NULL},
498         {"HelpWiki", GTK_STOCK_ABOUT, "Sigrok _Wiki", NULL, NULL,
499                 G_CALLBACK(help_wiki)},
500         {"HelpAbout", GTK_STOCK_ABOUT, "_About", NULL, NULL,
501                 G_CALLBACK(help_about)},
502 };
503
504 static const GtkToggleActionEntry toggle_items[] = {
505         /* name, stock-id, label, accel, tooltip, callback, isactive */
506         {"ViewLog", GTK_STOCK_JUSTIFY_LEFT, "_Log", NULL, NULL,
507                 G_CALLBACK(toggle_log), FALSE},
508 };
509
510 static const char ui_xml[] =
511 "<ui>"
512 "  <menubar>"
513 "    <menu action='DevMenu'>"
514 "      <menuitem action='DevOpen'/>"
515 "      <separator/>"
516 "      <menu action='DevSelectMenu'>"
517 "        <separator/>"
518 "        <menuitem action='DevRescan'/>"
519 "      </menu>"
520 "      <menuitem action='DevProperties'/>"
521 "      <menuitem action='DevProbes'/>"
522 "      <separator/>"
523 "      <menuitem action='DevAcquire'/>"
524 "      <separator/>"
525 "      <menuitem action='Exit'/>"
526 "    </menu>"
527 "    <menu action='ViewMenu'>"
528 "      <menuitem action='ViewZoomIn'/>"
529 "      <menuitem action='ViewZoomOut'/>"
530 "      <menuitem action='ViewZoomFit'/>"
531 "      <separator/>"
532 "      <menuitem action='ViewLog'/>"
533 "    </menu>"
534 "    <menu action='HelpMenu'>"
535 "      <menuitem action='HelpWiki'/>"
536 "      <menuitem action='HelpAbout'/>"
537 "    </menu>"
538 "  </menubar>"
539 "  <toolbar>"
540 "    <placeholder name='DevSelect'/>"
541 "    <toolitem action='DevRescan'/>"
542 "    <toolitem action='DevProperties'/>"
543 "    <toolitem action='DevProbes'/>"
544 "    <separator/>"
545 "    <placeholder name='DevSampleCount' />"
546 "    <toolitem action='DevAcquire'/>"
547 "    <separator/>"
548 "    <toolitem action='ViewZoomIn'/>"
549 "    <toolitem action='ViewZoomOut'/>"
550 "    <toolitem action='ViewZoomFit'/>"
551 "    <separator/>"
552 "  </toolbar>"
553 "</ui>";
554
555 GtkWidget *toolbar_init(GtkWindow *parent)
556 {
557         GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
558         GtkToolbar *toolbar;
559         GtkActionGroup *ag = gtk_action_group_new("Actions");
560         gtk_action_group_add_actions(ag, action_items,
561                                         G_N_ELEMENTS(action_items), parent);
562         gtk_action_group_add_toggle_actions(ag, toggle_items,
563                                         G_N_ELEMENTS(toggle_items), parent);
564
565         GtkUIManager *ui = gtk_ui_manager_new();
566         g_object_set_data(G_OBJECT(parent), "ui_manager", ui);
567         gtk_ui_manager_insert_action_group(ui, ag, 0);
568         GtkAccelGroup *accel = gtk_ui_manager_get_accel_group(ui);
569         gtk_window_add_accel_group(parent, accel);
570
571         GError *error = NULL;
572         if (!gtk_ui_manager_add_ui_from_string (ui, ui_xml, -1, &error)) {
573                 g_message ("building menus failed: %s", error->message);
574                 g_error_free (error);
575                 exit (-1);
576         }
577
578         GtkWidget *menubar = gtk_ui_manager_get_widget(ui, "/menubar");
579         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(menubar), FALSE, TRUE, 0);
580         toolbar = GTK_TOOLBAR(gtk_ui_manager_get_widget(ui, "/toolbar"));
581         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), FALSE, TRUE, 0);
582
583         /* Device selection GtkComboBox */
584         GtkToolItem *toolitem = gtk_tool_item_new();
585         GtkWidget *align = gtk_alignment_new(0.5, 0.5, 2, 0);
586         GtkWidget *dev = dev_select_combo_box_new(parent);
587
588         gtk_container_add(GTK_CONTAINER(align), dev);
589         gtk_container_add(GTK_CONTAINER(toolitem), align);
590         gtk_toolbar_insert(toolbar, toolitem, 0);
591
592         /* Time/Samples entry */
593         toolitem = gtk_tool_item_new();
594         GtkWidget *timesamples = gtk_entry_new();
595         gtk_entry_set_text(GTK_ENTRY(timesamples), "100");
596         gtk_entry_set_alignment(GTK_ENTRY(timesamples), 1.0);
597         gtk_widget_set_size_request(timesamples, 100, -1);
598         gtk_container_add(GTK_CONTAINER(toolitem), timesamples);
599         gtk_toolbar_insert(toolbar, toolitem, 7);
600
601         /* Time unit combo box */
602         toolitem = gtk_tool_item_new();
603         align = gtk_alignment_new(0.5, 0.5, 2, 0);
604         GtkWidget *timeunit = gtk_combo_box_new_text();
605         gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "samples");
606         gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "ms");
607         gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "s");
608         gtk_combo_box_set_active(GTK_COMBO_BOX(timeunit), 0);
609         gtk_container_add(GTK_CONTAINER(align), timeunit);
610         gtk_container_add(GTK_CONTAINER(toolitem), align);
611         gtk_toolbar_insert(toolbar, toolitem, 8);
612
613         g_object_set_data(G_OBJECT(parent), "timesamples", timesamples);
614         g_object_set_data(G_OBJECT(parent), "timeunit", timeunit);
615
616         return GTK_WIDGET(vbox);
617 }
618