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