Fix tar.gz build by removing legacy include to ltt directory
[lttv.git] / lttv / modules / gui / lttvwindow / lttvwindow / lttvwindow.c
CommitLineData
501e4e70 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 XangXiu Yang
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 Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
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,
16 * MA 02111-1307, USA.
17 */
18
19/*! \file lttvwindow.c
20 * \brief API used by the graphical viewers to interact with their tab.
21 *
22 * Main window (gui module) is the place to contain and display viewers.
23 * Viewers (lttv plugins) interact with tab and main window through this API
24 * and events sent by gtk.
25 * This header file should be included in each graphic module.
26 * This library is used by graphical modules to interact with their tab and
27 * main window.
28 *
29 */
30
4e4d11b3 31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
501e4e70 35#include <lttv/lttv.h>
36#include <lttv/state.h>
9a366873 37#include <lttv/traceset.h>
451aaf27 38#ifdef BABEL_CLEANUP
501e4e70 39#include <lttv/stats.h>
451aaf27 40#endif /* BABEL_CLEANUP */
501e4e70 41#include <lttvwindow/mainwindow.h>
9a366873 42#include <lttvwindow/mainwindow-private.h>
501e4e70 43#include <lttvwindow/lttvwindow.h>
44#include <lttvwindow/toolbar.h>
45#include <lttvwindow/menu.h>
46#include <lttvwindow/callbacks.h> // for execute_events_requests
47#include <lttvwindow/support.h>
48
501e4e70 49/**
50 * Internal function parts
51 */
52
53extern GSList * g_main_window_list;
54
f9240312 55__EXPORT gint lttvwindow_preempt_count = 0;
3c456a8a 56
b052368a 57/* set_time_window
58 *
59 * It updates the time window of the tab, then calls the updatetimewindow
60 * hooks of each viewer.
61 *
62 * This is called whenever the scrollbar value changes.
63 */
501e4e70 64
65void set_time_window(Tab *tab, const TimeWindow *time_window)
66{
67 LttvAttributeValue value;
68 LttvHooks * tmp;
8f318283 69 gboolean retval;
501e4e70 70
71 TimeWindowNotifyData time_window_notify_data;
72 TimeWindow old_time_window = tab->time_window;
73 time_window_notify_data.old_time_window = &old_time_window;
74 tab->time_window = *time_window;
75 time_window_notify_data.new_time_window =
76 &(tab->time_window);
77
8f318283
BP
78 retval= lttv_iattribute_find_by_path(tab->attributes,
79 "hooks/updatetimewindow", LTTV_POINTER, &value);
80 g_assert(retval);
501e4e70 81 tmp = (LttvHooks*)*(value.v_pointer);
b052368a 82 if(tmp != NULL) lttv_hooks_call(tmp, &time_window_notify_data);
501e4e70 83
b052368a 84 //gtk_multi_vpaned_set_adjust(tab->multi_vpaned, new_time_window, FALSE);
501e4e70 85
86}
87
db8bc917 88/* set_current_time
89 *
90 * It updates the current time of the tab, then calls the updatetimewindow
91 * hooks of each viewer.
92 *
93 * This is called whenever the current time value changes.
94 */
95
96void set_current_time(Tab *tab, const LttTime *current_time)
97{
98 LttvAttributeValue value;
99 LttvHooks * tmp;
8f318283 100 gboolean retval;
db8bc917 101
102 tab->current_time = *current_time;
103
8f318283
BP
104 retval= lttv_iattribute_find_by_path(tab->attributes,
105 "hooks/updatecurrenttime", LTTV_POINTER, &value);
106 g_assert(retval);
db8bc917 107 tmp = (LttvHooks*)*(value.v_pointer);
108 if(tmp != NULL) lttv_hooks_call(tmp, &tab->current_time);
109}
110
5290ec02 111/* set_current_position
112 *
113 * It updates the current time of the tab, then calls the updatetimewindow
114 * hooks of each viewer.
115 *
116 * This is called whenever the current time value changes.
117 */
118
451aaf27 119void set_current_position(Tab *tab, const LttvTracesetPosition *pos)
5290ec02 120{
121 LttvAttributeValue value;
122 LttvHooks * tmp;
8f318283 123 gboolean retval;
5290ec02 124
9a366873 125 tab->current_time = lttv_traceset_position_get_time(pos);
5290ec02 126
8f318283
BP
127 retval= lttv_iattribute_find_by_path(tab->attributes,
128 "hooks/updatecurrentposition", LTTV_POINTER, &value);
129 g_assert(retval);
5290ec02 130 tmp = (LttvHooks*)*(value.v_pointer);
8d8c5ea7
AM
131 if (tmp != NULL) {
132 lttv_hooks_call(tmp, (void *) pos);
133 }
5290ec02 134}
135
501e4e70 136void add_toolbar_constructor(MainWindow *mw, LttvToolbarClosure *toolbar_c)
137{
138 LttvIAttribute *attributes = mw->attributes;
139 LttvAttributeValue value;
140 LttvToolbars * instance_toolbar;
141 lttvwindow_viewer_constructor constructor;
142 GtkWidget * tool_menu_title_menu, *new_widget, *pixmap;
143 GdkPixbuf *pixbuf;
8f318283 144 gboolean retval;
501e4e70 145
8f318283
BP
146 retval= lttv_iattribute_find_by_path(attributes, "viewers/toolbar",
147 LTTV_POINTER, &value);
148 g_assert(retval);
501e4e70 149 if(*(value.v_pointer) == NULL)
150 *(value.v_pointer) = lttv_toolbars_new();
151 instance_toolbar = (LttvToolbars*)*(value.v_pointer);
152
153 constructor = toolbar_c->con;
154 tool_menu_title_menu = lookup_widget(mw->mwindow,"MToolbar1");
155 pixbuf = gdk_pixbuf_new_from_xpm_data((const char**)toolbar_c->pixmap);
156 pixmap = gtk_image_new_from_pixbuf(pixbuf);
157 new_widget =
158 gtk_toolbar_append_element (GTK_TOOLBAR (tool_menu_title_menu),
159 GTK_TOOLBAR_CHILD_BUTTON,
160 NULL,
161 "",
162 toolbar_c->tooltip, NULL,
163 pixmap, NULL, NULL);
164 gtk_label_set_use_underline(
165 GTK_LABEL (((GtkToolbarChild*) (
166 g_list_last (GTK_TOOLBAR
167 (tool_menu_title_menu)->children)->data))->label),
168 TRUE);
169 gtk_container_set_border_width (GTK_CONTAINER (new_widget), 1);
170 g_signal_connect ((gpointer) new_widget,
171 "clicked",
172 G_CALLBACK (insert_viewer_wrap),
173 constructor);
174 gtk_widget_show (new_widget);
175
176 lttv_toolbars_add(instance_toolbar, toolbar_c->con,
177 toolbar_c->tooltip,
178 toolbar_c->pixmap,
179 new_widget);
180
181}
182
183void add_menu_constructor(MainWindow *mw, LttvMenuClosure *menu_c)
184{
185 LttvIAttribute *attributes = mw->attributes;
186 LttvAttributeValue value;
187 LttvToolbars * instance_menu;
188 lttvwindow_viewer_constructor constructor;
189 GtkWidget * tool_menu_title_menu, *new_widget;
8f318283 190 gboolean retval;
501e4e70 191
8f318283
BP
192 retval= lttv_iattribute_find_by_path(attributes, "viewers/menu",
193 LTTV_POINTER, &value);
194 g_assert(retval);
501e4e70 195 if(*(value.v_pointer) == NULL)
196 *(value.v_pointer) = lttv_menus_new();
197 instance_menu = (LttvMenus*)*(value.v_pointer);
198
199
200 constructor = menu_c->con;
201 tool_menu_title_menu = lookup_widget(mw->mwindow,"ToolMenuTitle_menu");
202 new_widget =
203 gtk_menu_item_new_with_mnemonic (menu_c->menu_text);
204 gtk_container_add (GTK_CONTAINER (tool_menu_title_menu),
205 new_widget);
206 g_signal_connect ((gpointer) new_widget, "activate",
207 G_CALLBACK (insert_viewer_wrap),
208 constructor);
209 gtk_widget_show (new_widget);
210 lttv_menus_add(instance_menu, menu_c->con,
211 menu_c->menu_path,
212 menu_c->menu_text,
213 new_widget);
214}
215
216void remove_toolbar_constructor(MainWindow *mw, lttvwindow_viewer_constructor viewer_constructor)
217{
218 LttvIAttribute *attributes = mw->attributes;
219 LttvAttributeValue value;
220 LttvToolbars * instance_toolbar;
501e4e70 221 GtkWidget * tool_menu_title_menu, *widget;
8f318283 222 gboolean retval;
501e4e70 223
8f318283
BP
224 retval= lttv_iattribute_find_by_path(attributes, "viewers/toolbar",
225 LTTV_POINTER, &value);
226 g_assert(retval);
501e4e70 227 if(*(value.v_pointer) == NULL)
228 *(value.v_pointer) = lttv_toolbars_new();
229 instance_toolbar = (LttvToolbars*)*(value.v_pointer);
230
231 tool_menu_title_menu = lookup_widget(mw->mwindow,"MToolbar1");
232 widget = lttv_menus_remove(instance_toolbar, viewer_constructor);
233 gtk_container_remove (GTK_CONTAINER (tool_menu_title_menu),
234 widget);
235}
236
237
238void remove_menu_constructor(MainWindow *mw, lttvwindow_viewer_constructor viewer_constructor)
239{
240 LttvIAttribute *attributes = mw->attributes;
241 LttvAttributeValue value;
242 LttvMenus * instance_menu;
501e4e70 243 GtkWidget * tool_menu_title_menu, *widget;
8f318283 244 gboolean retval;
501e4e70 245
8f318283
BP
246 retval= lttv_iattribute_find_by_path(attributes, "viewers/menu",
247 LTTV_POINTER, &value);
248 g_assert(retval);
501e4e70 249 if(*(value.v_pointer) == NULL)
250 *(value.v_pointer) = lttv_menus_new();
251 instance_menu = (LttvMenus*)*(value.v_pointer);
252
253 widget = lttv_menus_remove(instance_menu, viewer_constructor);
254 tool_menu_title_menu = lookup_widget(mw->mwindow,"ToolMenuTitle_menu");
255 gtk_container_remove (GTK_CONTAINER (tool_menu_title_menu), widget);
256}
257
258
259/**
260 * API parts
261 */
262
263
264/**
265 * Function to register a view constructor so that main window can generate
266 * a menu item and a toolbar item for the viewer in order to generate a new
267 * instance easily. A menu entry and toolbar item will be added to each main
268 * window.
269 *
270 * It should be called by init function of the module.
271 *
e025a729 272 * @param name name of the viewer
501e4e70 273 * @param menu_path path of the menu item.
274 * @param menu_text text of the menu item.
275 * @param pixmap Image shown on the toolbar item.
276 * @param tooltip tooltip of the toolbar item.
277 * @param view_constructor constructor of the viewer.
278 */
279
f9240312 280__EXPORT void lttvwindow_register_constructor
e025a729 281 (char * name,
282 char * menu_path,
501e4e70 283 char * menu_text,
284 char ** pixmap,
285 char * tooltip,
286 lttvwindow_viewer_constructor view_constructor)
287{
288 LttvIAttribute *attributes_global = LTTV_IATTRIBUTE(lttv_global_attributes());
289 LttvToolbars * toolbar;
290 LttvMenus * menu;
291 LttvToolbarClosure toolbar_c;
292 LttvMenuClosure menu_c;
293 LttvAttributeValue value;
8f318283 294 gboolean retval;
501e4e70 295
e025a729 296 if(view_constructor == NULL) return;
297
501e4e70 298 if(pixmap != NULL) {
8f318283
BP
299 retval= lttv_iattribute_find_by_path(attributes_global, "viewers/toolbar",
300 LTTV_POINTER, &value);
301 g_assert(retval);
501e4e70 302 toolbar = (LttvToolbars*)*(value.v_pointer);
303
304 if(toolbar == NULL) {
305 toolbar = lttv_toolbars_new();
306 *(value.v_pointer) = toolbar;
307 }
308 toolbar_c = lttv_toolbars_add(toolbar, view_constructor, tooltip, pixmap,
309 NULL);
310
311 g_slist_foreach(g_main_window_list,
312 (gpointer)add_toolbar_constructor,
313 &toolbar_c);
314 }
315
316 if(menu_path != NULL) {
8f318283
BP
317 retval= lttv_iattribute_find_by_path(attributes_global, "viewers/menu",
318 LTTV_POINTER, &value);
319 g_assert(retval);
501e4e70 320 menu = (LttvMenus*)*(value.v_pointer);
321
322 if(menu == NULL) {
323 menu = lttv_menus_new();
324 *(value.v_pointer) = menu;
325 }
326 menu_c = lttv_menus_add(menu, view_constructor, menu_path, menu_text,NULL);
327
328 g_slist_foreach(g_main_window_list,
329 (gpointer)add_menu_constructor,
330 &menu_c);
331 }
e025a729 332 {
333 LttvAttribute *attribute;
96c9eb79 334 gboolean result;
335
336 attribute = LTTV_ATTRIBUTE(lttv_iattribute_find_subdir(
337 LTTV_IATTRIBUTE(attributes_global),
338 LTTV_VIEWER_CONSTRUCTORS));
339 g_assert(attribute);
e025a729 340
96c9eb79 341 result = lttv_iattribute_find_by_path(LTTV_IATTRIBUTE(attribute),
342 name, LTTV_POINTER, &value);
343 g_assert(result);
e025a729 344
345 *(value.v_pointer) = view_constructor;
346
347 }
501e4e70 348}
349
350
351/**
352 * Function to unregister the viewer's constructor, release the space
353 * occupied by menu_path, menu_text, pixmap, tooltip and constructor of the
354 * viewer.
355 *
356 * It will be called when a module is unloaded.
357 *
358 * @param view_constructor constructor of the viewer.
359 */
360
361
f9240312 362__EXPORT void lttvwindow_unregister_constructor
501e4e70 363 (lttvwindow_viewer_constructor view_constructor)
364{
365 LttvIAttribute *attributes_global = LTTV_IATTRIBUTE(lttv_global_attributes());
366 LttvToolbars * toolbar;
367 LttvMenus * menu;
368 LttvAttributeValue value;
8f318283
BP
369 gboolean is_named;
370 gboolean retval;
501e4e70 371
8f318283
BP
372 retval= lttv_iattribute_find_by_path(attributes_global, "viewers/toolbar",
373 LTTV_POINTER, &value);
374 g_assert(retval);
501e4e70 375 toolbar = (LttvToolbars*)*(value.v_pointer);
376
377 if(toolbar != NULL) {
378 g_slist_foreach(g_main_window_list,
379 (gpointer)remove_toolbar_constructor,
380 view_constructor);
381 lttv_toolbars_remove(toolbar, view_constructor);
382 }
383
8f318283
BP
384 retval= lttv_iattribute_find_by_path(attributes_global, "viewers/menu",
385 LTTV_POINTER, &value);
386 g_assert(retval);
501e4e70 387 menu = (LttvMenus*)*(value.v_pointer);
388
389 if(menu != NULL) {
390 g_slist_foreach(g_main_window_list,
391 (gpointer)remove_menu_constructor,
392 view_constructor);
393 lttv_menus_remove(menu, view_constructor);
394 }
e025a729 395
396 {
397 LttvAttribute *attribute;
96c9eb79 398 attribute = LTTV_ATTRIBUTE(lttv_iattribute_find_subdir(
399 LTTV_IATTRIBUTE(attributes_global),
400 LTTV_VIEWER_CONSTRUCTORS));
401 g_assert(attribute);
e025a729 402
403 guint num = lttv_iattribute_get_number(LTTV_IATTRIBUTE(attribute));
404 guint i;
405 LttvAttributeName name;
406 LttvAttributeValue value;
407 LttvAttributeType type;
408
409 for(i=0;i<num;i++) {
c0cb4d12 410 type = lttv_iattribute_get(LTTV_IATTRIBUTE(attribute), i, &name, &value,
411 &is_named);
e025a729 412 g_assert(type == LTTV_POINTER);
413 if(*(value.v_pointer) == view_constructor) {
414 lttv_iattribute_remove(LTTV_IATTRIBUTE(attribute), i);
415 break;
416 }
417 }
418 }
501e4e70 419}
420
421
422/**
423 * Function to register a hook function for a viewer to set/update its
424 * time interval.
425 * @param tab viewer's tab
426 * @param hook hook function of the viewer.
427 * @param hook_data hook data associated with the hook function.
428 */
f9240312 429__EXPORT void lttvwindow_register_time_window_notify(Tab *tab,
501e4e70 430 LttvHook hook, gpointer hook_data)
431{
432 LttvAttributeValue value;
433 LttvHooks * tmp;
8f318283
BP
434 gboolean retval;
435
436 retval= lttv_iattribute_find_by_path(tab->attributes,
437 "hooks/updatetimewindow", LTTV_POINTER, &value);
438 g_assert(retval);
501e4e70 439 tmp = (LttvHooks*)*(value.v_pointer);
440 if(tmp == NULL){
441 tmp = lttv_hooks_new();
442 *(value.v_pointer) = tmp;
443 }
444 lttv_hooks_add(tmp, hook,hook_data, LTTV_PRIO_DEFAULT);
445}
446
447
448/**
449 * Function to unregister a viewer's hook function which is used to
450 * set/update the time interval of the viewer.
451 * @param tab viewer's tab
452 * @param hook hook function of the viewer.
453 * @param hook_data hook data associated with the hook function.
454 */
455
f9240312 456__EXPORT void lttvwindow_unregister_time_window_notify(Tab *tab,
501e4e70 457 LttvHook hook, gpointer hook_data)
458{
459 LttvAttributeValue value;
460 LttvHooks * tmp;
8f318283
BP
461 gboolean retval;
462
463 retval= lttv_iattribute_find_by_path(tab->attributes,
464 "hooks/updatetimewindow", LTTV_POINTER, &value);
465 g_assert(retval);
1e3594a3
YB
466 tmp = (LttvHooks*)*(value.v_pointer);
467 if(tmp == NULL) return;
468 lttv_hooks_remove_data(tmp, hook, hook_data);
469}
470
471/**
472 * Function to register a hook function for a viewer to set/update its
473 * allowed time span.
474 * @param tab viewer's tab
475 * @param hook hook function of the viewer.
476 * @param hook_data hook data associated with the hook function.
477 */
68764dff 478__EXPORT void lttvwindow_register_timespan_notify(Tab *tab,
1e3594a3
YB
479 LttvHook hook, gpointer hook_data)
480{
481 LttvAttributeValue value;
482 LttvHooks * tmp;
483 gboolean retval;
484
485 retval= lttv_iattribute_find_by_path(tab->attributes,
486 "hooks/updatetimespan", LTTV_POINTER, &value);
487 g_assert(retval);
488 tmp = (LttvHooks*)*(value.v_pointer);
489 if(tmp == NULL){
490 tmp = lttv_hooks_new();
491 *(value.v_pointer) = tmp;
492 }
493 lttv_hooks_add(tmp, hook,hook_data, LTTV_PRIO_DEFAULT);
494}
495/**
496 * Function to unregister a viewer's hook function which is used to
497 * set/update the time span allowed for the viewer.
498 * @param tab viewer's tab
499 * @param hook hook function of the viewer.
500 * @param hook_data hook data associated with the hook function.
501 */
502
68764dff 503__EXPORT void lttvwindow_unregister_timespan_notify(Tab *tab,
1e3594a3
YB
504 LttvHook hook, gpointer hook_data)
505{
506 LttvAttributeValue value;
507 LttvHooks * tmp;
508 gboolean retval;
509
510 retval= lttv_iattribute_find_by_path(tab->attributes,
511 "hooks/updatetimespan", LTTV_POINTER, &value);
512 g_assert(retval);
501e4e70 513 tmp = (LttvHooks*)*(value.v_pointer);
514 if(tmp == NULL) return;
515 lttv_hooks_remove_data(tmp, hook, hook_data);
516}
517
518/**
519 * Function to register a hook function for a viewer to set/update its
520 * traceset.
521 * @param tab viewer's tab
522 * @param hook hook function of the viewer.
523 * @param hook_data hook data associated with the hook function.
524 */
525
f9240312 526__EXPORT void lttvwindow_register_traceset_notify(Tab *tab,
501e4e70 527 LttvHook hook, gpointer hook_data)
528{
529 LttvAttributeValue value;
530 LttvHooks * tmp;
8f318283
BP
531 gboolean retval;
532
533 retval= lttv_iattribute_find_by_path(tab->attributes,
534 "hooks/updatetraceset", LTTV_POINTER, &value);
535 g_assert(retval);
501e4e70 536 tmp = (LttvHooks*)*(value.v_pointer);
537 if(tmp == NULL){
538 tmp = lttv_hooks_new();
539 *(value.v_pointer) = tmp;
540 }
541 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
542}
543
544
545/**
546 * Function to unregister a viewer's hook function which is used to
547 * set/update the traceset of the viewer.
548 * @param tab viewer's tab
549 * @param hook hook function of the viewer.
550 * @param hook_data hook data associated with the hook function.
551 */
552
f9240312 553__EXPORT void lttvwindow_unregister_traceset_notify(Tab *tab,
501e4e70 554 LttvHook hook, gpointer hook_data)
555{
556 LttvAttributeValue value;
557 LttvHooks * tmp;
8f318283
BP
558 gboolean retval;
559
560 retval= lttv_iattribute_find_by_path(tab->attributes,
561 "hooks/updatetraceset", LTTV_POINTER, &value);
562 g_assert(retval);
501e4e70 563 tmp = (LttvHooks*)*(value.v_pointer);
564 if(tmp == NULL) return;
565 lttv_hooks_remove_data(tmp, hook, hook_data);
566}
567
9878c8a4 568/**
569 * Function to register a hook function for a viewer be completely redrawn.
570 *
571 * @param tab viewer's tab
572 * @param hook hook function of the viewer.
573 * @param hook_data hook data associated with the hook function.
574 */
575
f9240312 576__EXPORT void lttvwindow_register_redraw_notify(Tab *tab,
9878c8a4 577 LttvHook hook, gpointer hook_data)
578{
579 LttvAttributeValue value;
580 LttvHooks * tmp;
8f318283
BP
581 gboolean retval;
582
583 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/redraw",
584 LTTV_POINTER, &value);
585 g_assert(retval);
9878c8a4 586 tmp = (LttvHooks*)*(value.v_pointer);
587 if(tmp == NULL){
588 tmp = lttv_hooks_new();
589 *(value.v_pointer) = tmp;
590 }
591 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
592}
593
594
595/**
596 * Function to unregister a hook function for a viewer be completely redrawn.
597 *
598 * @param tab viewer's tab
599 * @param hook hook function of the viewer.
600 * @param hook_data hook data associated with the hook function.
601 */
602
f9240312 603__EXPORT void lttvwindow_unregister_redraw_notify(Tab *tab,
9878c8a4 604 LttvHook hook, gpointer hook_data)
605{
606 LttvAttributeValue value;
607 LttvHooks * tmp;
8f318283
BP
608 gboolean retval;
609
610 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/redraw",
611 LTTV_POINTER, &value);
612 g_assert(retval);
9878c8a4 613 tmp = (LttvHooks*)*(value.v_pointer);
614 if(tmp == NULL) return;
615 lttv_hooks_remove_data(tmp, hook, hook_data);
616}
617
618/**
619 * Function to register a hook function for a viewer to re-do the events
620 * requests for the needed interval.
621 *
622 * This action is typically done after a "stop".
623 *
624 * The typical hook will remove all current requests for the viewer
625 * and make requests for missing information.
626 *
627 * @param tab viewer's tab
628 * @param hook hook function of the viewer.
629 * @param hook_data hook data associated with the hook function.
630 */
631
f9240312 632__EXPORT void lttvwindow_register_continue_notify(Tab *tab,
9878c8a4 633 LttvHook hook, gpointer hook_data)
634{
635 LttvAttributeValue value;
636 LttvHooks * tmp;
8f318283
BP
637 gboolean retval;
638
639 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/continue",
640 LTTV_POINTER, &value);
641 g_assert(retval);
9878c8a4 642 tmp = (LttvHooks*)*(value.v_pointer);
643 if(tmp == NULL){
644 tmp = lttv_hooks_new();
645 *(value.v_pointer) = tmp;
646 }
647 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
648}
649
650
651/**
652 * Function to unregister a hook function for a viewer to re-do the events
653 * requests for the needed interval.
654 *
655 * @param tab viewer's tab
656 * @param hook hook function of the viewer.
657 * @param hook_data hook data associated with the hook function.
658 */
659
f9240312 660__EXPORT void lttvwindow_unregister_continue_notify(Tab *tab,
9878c8a4 661 LttvHook hook, gpointer hook_data)
662{
663 LttvAttributeValue value;
664 LttvHooks * tmp;
8f318283
BP
665 gboolean retval;
666
667 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/continue",
668 LTTV_POINTER, &value);
669 g_assert(retval);
9878c8a4 670 tmp = (LttvHooks*)*(value.v_pointer);
671 if(tmp == NULL) return;
672 lttv_hooks_remove_data(tmp, hook, hook_data);
673}
674
675
501e4e70 676/**
677 * Function to register a hook function for a viewer to set/update its
678 * filter.
679 * @param tab viewer's tab
680 * @param hook hook function of the viewer.
681 * @param hook_data hook data associated with the hook function.
682 */
683
f9240312 684__EXPORT void lttvwindow_register_filter_notify(Tab *tab,
501e4e70 685 LttvHook hook, gpointer hook_data)
686{
687 LttvAttributeValue value;
688 LttvHooks * tmp;
8f318283
BP
689 gboolean retval;
690
691 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/updatefilter",
692 LTTV_POINTER, &value);
693 g_assert(retval);
501e4e70 694 tmp = (LttvHooks*)*(value.v_pointer);
695 if(tmp == NULL){
696 tmp = lttv_hooks_new();
697 *(value.v_pointer) = tmp;
698 }
699 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
700}
701
702
703/**
704 * Function to unregister a viewer's hook function which is used to
705 * set/update the filter of the viewer.
706 * @param tab viewer's tab
707 * @param hook hook function of the viewer.
708 * @param hook_data hook data associated with the hook function.
709 */
710
f9240312 711__EXPORT void lttvwindow_unregister_filter_notify(Tab *tab,
501e4e70 712 LttvHook hook,
713 gpointer hook_data)
714{
715 LttvAttributeValue value;
716 LttvHooks * tmp;
8f318283
BP
717 gboolean retval;
718
719 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/updatefilter",
720 LTTV_POINTER, &value);
721 g_assert(retval);
501e4e70 722 tmp = (LttvHooks*)*(value.v_pointer);
723 if(tmp == NULL) return;
724 lttv_hooks_remove_data(tmp, hook, hook_data);
725}
726
727/**
5290ec02 728 * function to register a hook function for a viewer to set/update its
501e4e70 729 * current time.
730 * @param tab viewer's tab
731 * @param hook hook function of the viewer.
732 * @param hook_data hook data associated with the hook function.
733 */
734
f9240312 735__EXPORT void lttvwindow_register_current_time_notify(Tab *tab,
501e4e70 736 LttvHook hook, gpointer hook_data)
737{
738 LttvAttributeValue value;
739 LttvHooks * tmp;
8f318283
BP
740 gboolean retval;
741
742 retval= lttv_iattribute_find_by_path(tab->attributes,
743 "hooks/updatecurrenttime", LTTV_POINTER, &value);
744 g_assert(retval);
501e4e70 745 tmp = (LttvHooks*)*(value.v_pointer);
746 if(tmp == NULL){
747 tmp = lttv_hooks_new();
748 *(value.v_pointer) = tmp;
749 }
750 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
751}
752
753
754/**
5290ec02 755 * function to unregister a viewer's hook function which is used to
501e4e70 756 * set/update the current time of the viewer.
757 * @param tab viewer's tab
758 * @param hook hook function of the viewer.
759 * @param hook_data hook data associated with the hook function.
760 */
761
f9240312 762__EXPORT void lttvwindow_unregister_current_time_notify(Tab *tab,
501e4e70 763 LttvHook hook, gpointer hook_data)
764{
765 LttvAttributeValue value;
766 LttvHooks * tmp;
8f318283
BP
767 gboolean retval;
768
769 retval= lttv_iattribute_find_by_path(tab->attributes,
770 "hooks/updatecurrenttime", LTTV_POINTER, &value);
771 g_assert(retval);
501e4e70 772 tmp = (LttvHooks*)*(value.v_pointer);
773 if(tmp == NULL) return;
774 lttv_hooks_remove_data(tmp, hook, hook_data);
775}
776
5290ec02 777/**
778 * function to register a hook function for a viewer to set/update its
779 * current position.
780 * @param tab viewer's tab
781 * @param hook hook function of the viewer.
782 * @param hook_data hook data associated with the hook function.
783 */
784
f9240312 785__EXPORT void lttvwindow_register_current_position_notify(Tab *tab,
5290ec02 786 LttvHook hook, gpointer hook_data)
787{
788 LttvAttributeValue value;
789 LttvHooks * tmp;
8f318283
BP
790 gboolean retval;
791
792 retval= lttv_iattribute_find_by_path(tab->attributes,
793 "hooks/updatecurrentposition", LTTV_POINTER, &value);
794 g_assert(retval);
5290ec02 795 tmp = (LttvHooks*)*(value.v_pointer);
796 if(tmp == NULL){
797 tmp = lttv_hooks_new();
798 *(value.v_pointer) = tmp;
799 }
800 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
801}
802
803
804/**
805 * function to unregister a viewer's hook function which is used to
806 * set/update the current position of the viewer.
807 * @param tab viewer's tab
808 * @param hook hook function of the viewer.
809 * @param hook_data hook data associated with the hook function.
810 */
811
f9240312 812__EXPORT void lttvwindow_unregister_current_position_notify(Tab *tab,
5290ec02 813 LttvHook hook, gpointer hook_data)
814{
815 LttvAttributeValue value;
816 LttvHooks * tmp;
8f318283
BP
817 gboolean retval;
818
819 retval= lttv_iattribute_find_by_path(tab->attributes,
820 "hooks/updatecurrentposition", LTTV_POINTER, &value);
821 g_assert(retval);
5290ec02 822 tmp = (LttvHooks*)*(value.v_pointer);
823 if(tmp == NULL) return;
824 lttv_hooks_remove_data(tmp, hook, hook_data);
825}
826
501e4e70 827
828/**
829 * Function to register a hook function for a viewer to show
830 * the content of the viewer.
831 * @param tab viewer's tab
832 * @param hook hook function of the viewer.
833 * @param hook_data hook data associated with the hook function.
834 */
835
836void lttvwindow_register_show_notify(Tab *tab,
837 LttvHook hook, gpointer hook_data)
838{
839 LttvAttributeValue value;
840 LttvHooks * tmp;
8f318283
BP
841 gboolean retval;
842
843 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/showviewer",
844 LTTV_POINTER, &value);
845 g_assert(retval);
501e4e70 846 tmp = (LttvHooks*)*(value.v_pointer);
847 if(tmp == NULL){
848 tmp = lttv_hooks_new();
849 *(value.v_pointer) = tmp;
850 }
851 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
852}
853
854
855/**
856 * Function to unregister a viewer's hook function which is used to
857 * show the content of the viewer..
858 * @param tab viewer's tab
859 * @param hook hook function of the viewer.
860 * @param hook_data hook data associated with the hook function.
861 */
862
863void lttvwindow_unregister_show_notify(Tab *tab,
864 LttvHook hook, gpointer hook_data)
865{
866 LttvAttributeValue value;
867 LttvHooks * tmp;
8f318283
BP
868 gboolean retval;
869
870 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/showviewer",
871 LTTV_POINTER, &value);
872 g_assert(retval);
501e4e70 873 tmp = (LttvHooks*)*(value.v_pointer);
874 if(tmp == NULL) return;
875 lttv_hooks_remove_data(tmp, hook, hook_data);
876}
877
878/**
879 * Function to register a hook function for a viewer to set/update the
880 * dividor of the hpane.
881 * @param tab viewer's tab
882 * @param hook hook function of the viewer.
883 * @param hook_data hook data associated with the hook function.
884 */
885
886void lttvwindow_register_dividor(Tab *tab,
887 LttvHook hook, gpointer hook_data)
888{
889 LttvAttributeValue value;
890 LttvHooks * tmp;
8f318283
BP
891 gboolean retval;
892
893 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/hpanedividor",
894 LTTV_POINTER, &value);
895 g_assert(retval);
501e4e70 896 tmp = (LttvHooks*)*(value.v_pointer);
897 if(tmp == NULL){
898 tmp = lttv_hooks_new();
899 *(value.v_pointer) = tmp;
900 }
901 lttv_hooks_add(tmp, hook, hook_data, LTTV_PRIO_DEFAULT);
902}
903
904
905/**
906 * Function to unregister a viewer's hook function which is used to
907 * set/update hpane's dividor of the viewer.
908 * It will be called by the destructor of the viewer.
909 * @param tab viewer's tab
910 * @param hook hook function of the viewer.
911 * @param hook_data hook data associated with the hook function.
912 */
913
914void lttvwindow_unregister_dividor(Tab *tab,
915 LttvHook hook, gpointer hook_data)
916{
917 LttvAttributeValue value;
918 LttvHooks * tmp;
8f318283
BP
919 gboolean retval;
920
921 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/hpanedividor",
922 LTTV_POINTER, &value);
923 g_assert(retval);
501e4e70 924 tmp = (LttvHooks*)*(value.v_pointer);
925 if(tmp == NULL) return;
926 lttv_hooks_remove_data(tmp, hook, hook_data);
927}
928
929
501e4e70 930/**
931 * Function to set the time interval of the current tab.
932 * It will be called by a viewer's signal handle associated with
933 * the move_slider signal
934 * @param tab viewer's tab
935 * @param time_interval a pointer where time interval is stored.
936 */
937
f9240312 938__EXPORT void lttvwindow_report_time_window(Tab *tab,
939 TimeWindow time_window)
501e4e70 940{
b052368a 941 //set_time_window(tab, time_window);
942 //set_time_window_adjustment(tab, time_window);
943
e800cf84 944 time_change_manager(tab, time_window);
945
946
947#if 0
b052368a 948 /* Set scrollbar */
949 LttvTracesetContext *tsc =
950 LTTV_TRACESET_CONTEXT(tab->traceset_info->traceset_context);
951 TimeInterval time_span = tsc->time_span;
952 GtkAdjustment *adjustment = gtk_range_get_adjustment(GTK_RANGE(tab->scrollbar));
b052368a 953 g_object_set(G_OBJECT(adjustment),
954 "lower",
0c5dbe3b 955 0.0, /* lower */
b052368a 956 "upper",
b9a010a2 957 ltt_time_to_double(
958 ltt_time_sub(time_span.end_time, time_span.start_time))
c74e0cf9 959 , /* upper */
b052368a 960 "step_increment",
961 ltt_time_to_double(time_window->time_width)
962 / SCROLL_STEP_PER_PAGE
c74e0cf9 963 , /* step increment */
b052368a 964 "page_increment",
965 ltt_time_to_double(time_window->time_width)
c74e0cf9 966 , /* page increment */
b052368a 967 "page_size",
968 ltt_time_to_double(time_window->time_width)
c74e0cf9 969 , /* page size */
b052368a 970 NULL);
971 gtk_adjustment_changed(adjustment);
972
973 //g_object_set(G_OBJECT(adjustment),
974 // "value",
975 // ltt_time_to_double(time_window->start_time)
c74e0cf9 976 // , /* value */
b052368a 977 // NULL);
978 /* Note : the set value will call set_time_window if scrollbar value changed
979 */
980 gtk_adjustment_set_value(adjustment,
b9a010a2 981 ltt_time_to_double(
982 ltt_time_sub(time_window->start_time,
983 time_span.start_time))
c74e0cf9 984 );
e800cf84 985#endif //0
501e4e70 986}
987
988
989/**
5290ec02 990 * Function to set the current time of the current tab.
501e4e70 991 * It will be called by a viewer's signal handle associated with
992 * the button-release-event signal
993 * @param tab viewer's tab
994 * @param time a pointer where time is stored.
995 */
996
f9240312 997__EXPORT void lttvwindow_report_current_time(Tab *tab,
e800cf84 998 LttTime time)
501e4e70 999{
e800cf84 1000 current_time_change_manager(tab, time);
501e4e70 1001}
1002
5290ec02 1003/**
1004 * Function to set the current event of the current tab.
1005 * It will be called by a viewer's signal handle associated with
1006 * the button-release-event signal
1007 * @param tab viewer's tab
1008 * @param time a pointer where time is stored.
1009 */
1010
f9240312 1011__EXPORT void lttvwindow_report_current_position(Tab *tab,
451aaf27 1012 LttvTracesetPosition *pos)
5290ec02 1013{
5290ec02 1014 current_position_change_manager(tab, pos);
1015}
1016
1017
501e4e70 1018/**
1019 * Function to set the position of the hpane's dividor (viewer).
1020 * It will be called by a viewer's signal handle associated with
1021 * the motion_notify_event event/signal
1022 * @param tab viewer's tab
1023 * @param position position of the hpane's dividor.
1024 */
1025
1026void lttvwindow_report_dividor(Tab *tab, gint position)
1027{
1028 LttvAttributeValue value;
1029 LttvHooks * tmp;
8f318283
BP
1030 gboolean retval;
1031
1032 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/hpanedividor",
1033 LTTV_POINTER, &value);
1034 g_assert(retval);
501e4e70 1035 tmp = (LttvHooks*)*(value.v_pointer);
1036 if(tmp == NULL) return;
1037 lttv_hooks_call(tmp, &position);
1038}
1039
501e4e70 1040/**
1041 * Function to request data in a specific time interval to the main window. The
1042 * event request servicing is differed until the glib idle functions are
1043 * called.
1044 *
1045 * The viewer has to provide hooks that should be associated with the event
1046 * request.
1047 *
1048 * Either start time or start position must be defined in a EventRequest
1049 * structure for it to be valid.
1050 *
1051 * end_time, end_position and num_events can all be defined. The first one
1052 * to occur will be used as end criterion.
1053 *
1054 * @param tab viewer's tab
1055 * @param events_requested the structure of request from.
1056 */
1057
f9240312 1058__EXPORT void lttvwindow_events_request(Tab *tab,
1059 EventsRequest *events_request)
501e4e70 1060{
20fde85f 1061 tab->events_requests = g_slist_append(tab->events_requests, events_request);
501e4e70 1062
1063 if(!tab->events_request_pending)
1064 {
553d1e7b 1065 /* Redraw has +20 priority. We want to let the redraw be done while we do
e140c5b3 1066 * our job. Mathieu : test with high prio higher than events for better
1067 * scrolling. */
c55068ce 1068 /* Mathieu, 2008 : ok, finally, the control flow view needs the cell updates
1069 * to come soon enough so we can have one active cell to get the pixmap
1070 * buffer height from. Therefore, let the gdk events run before the events
1071 * requests.
1072 */
1073 g_idle_add_full((G_PRIORITY_HIGH_IDLE + 21),
1074 //g_idle_add_full((G_PRIORITY_DEFAULT + 2),
501e4e70 1075 (GSourceFunc)execute_events_requests,
1076 tab,
1077 NULL);
1078 tab->events_request_pending = TRUE;
1079 }
1080}
1081
1082
1083/**
1084 * Function to remove data requests related to a viewer.
1085 *
1086 * The existing requests's viewer gpointer is compared to the pointer
1087 * given in argument to establish which data request should be removed.
1088 *
1089 * @param tab the tab the viewer belongs to.
1090 * @param viewer a pointer to the viewer data structure
1091 */
1092
1093gint find_viewer (const EventsRequest *a, gconstpointer b)
1094{
2d262115 1095 return (a->owner != b);
501e4e70 1096}
1097
1098
f9240312 1099__EXPORT void lttvwindow_events_request_remove_all(Tab *tab,
501e4e70 1100 gconstpointer viewer)
1101{
6843100a 1102 GSList *element = tab->events_requests;
501e4e70 1103
1104 while((element =
6843100a 1105 g_slist_find_custom(element, viewer,
501e4e70 1106 (GCompareFunc)find_viewer))
1107 != NULL) {
2d262115 1108 EventsRequest *events_request = (EventsRequest *)element->data;
3bafb436 1109 // Modified so a viewer being destroyed won't have its after_request
1110 // called. Not so important anyway. Note that a viewer that call this
1111 // remove_all function will not get its after_request called.
1112 //if(events_request->servicing == TRUE) {
1113 // lttv_hooks_call(events_request->after_request, NULL);
1114 //}
c5b5eee1 1115 events_request_free(events_request);
1116 //g_free(events_request);
501e4e70 1117 tab->events_requests = g_slist_remove_link(tab->events_requests, element);
6843100a 1118 element = g_slist_next(element);
1119 if(element == NULL) break; /* end of list */
501e4e70 1120 }
b052368a 1121 if(g_slist_length(tab->events_requests) == 0) {
1122 tab->events_request_pending = FALSE;
1123 g_idle_remove_by_data(tab);
1124 }
1125
501e4e70 1126}
1127
efcd775d 1128
1129/**
1130 * Function to see if there are events request pending.
1131 *
1132 * It tells if events requests are pending. Useful for checks in some events,
1133 * i.e. detailed event list scrolling.
1134 *
1135 * @param tab the tab the viewer belongs to.
1136 * @param viewer a pointer to the viewer data structure
1137 * @return : TRUE is events requests are pending, else FALSE.
1138 */
1139
f9240312 1140__EXPORT gboolean lttvwindow_events_request_pending(Tab *tab)
efcd775d 1141{
1142 GSList *element = tab->events_requests;
1143
c73ce169
FD
1144 if(element == NULL){
1145 return FALSE;
1146 }
1147 else {
1148 return TRUE;
1149 }
efcd775d 1150}
1151
1152
50106726 1153/**
1154 * Function to get the current time interval shown on the current tab.
1155 * It will be called by a viewer's hook function to update the
1156 * shown time interval of the viewer and also be called by the constructor
1157 * of the viewer.
1158 * @param tab viewer's tab
1159 * @return time window.
1160 */
1161
f9240312 1162__EXPORT TimeWindow lttvwindow_get_time_window(Tab *tab)
50106726 1163{
1164 return tab->time_window;
1165}
1166
501e4e70 1167
501e4e70 1168/**
1169 * Function to get the current time/event of the current tab.
1170 * It will be called by a viewer's hook function to update the
1171 * current time/event of the viewer.
1172 * @param tab viewer's tab
6ea08962 1173 * @return time
501e4e70 1174 */
1175
f9240312 1176__EXPORT LttTime lttvwindow_get_current_time(Tab *tab)
501e4e70 1177{
6ea08962 1178 return tab->current_time;
501e4e70 1179}
1180
1181
1182/**
1183 * Function to get the filter of the current tab.
501e4e70 1184 * @param filter, a pointer to a filter.
c790dfd9 1185 *
1186 * returns the current filter
501e4e70 1187 */
f9240312 1188__EXPORT LttvFilter *lttvwindow_get_filter(Tab *tab)
501e4e70 1189{
e433e6d6 1190 return g_object_get_data(G_OBJECT(tab->vbox), "filter");
501e4e70 1191}
1192
dc5e5266 1193/**
1194 * Function to set the filter of the current tab.
1195 * It should be called by the filter GUI to tell the
1196 * main window to update the filter tab's lttv_filter.
1197 *
1198 * This function does change the current filter, removing the
1199 * old one when necessary, and call the updatefilter hooks
1200 * of the registered viewers.
1201 *
1202 * @param main_win, the main window the viewer belongs to.
1203 * @param filter, a pointer to a filter.
1204 */
dc5e5266 1205void lttvwindow_report_filter(Tab *tab, LttvFilter *filter)
1206{
1207 LttvAttributeValue value;
1208 LttvHooks * tmp;
8f318283 1209 gboolean retval;
dc5e5266 1210
e433e6d6 1211 //lttv_filter_destroy(tab->filter);
1212 //tab->filter = filter;
dc5e5266 1213
8f318283
BP
1214 retval= lttv_iattribute_find_by_path(tab->attributes, "hooks/updatefilter",
1215 LTTV_POINTER, &value);
1216 g_assert(retval);
dc5e5266 1217 tmp = (LttvHooks*)*(value.v_pointer);
1218 if(tmp == NULL) return;
962e2228 1219 lttv_hooks_call(tmp, filter);
dc5e5266 1220}
1221
451aaf27 1222#ifdef BABEL_CLEANUP
501e4e70 1223
1224/**
1225 * Function to get the stats of the traceset
1226 * @param tab viewer's tab
1227 */
1228
f9240312 1229__EXPORT LttvTracesetStats* lttvwindow_get_traceset_stats(Tab *tab)
501e4e70 1230{
1231 return tab->traceset_info->traceset_context;
1232}
451aaf27 1233#endif /*BABEL_CLEANUP*/
c5b5eee1 1234
9a366873
FD
1235__EXPORT LttvTraceset *lttvwindow_get_traceset(Tab *tab)
1236{
1237 return tab->traceset_info->traceset;
1238}
1239
c5b5eee1 1240void events_request_free(EventsRequest *events_request)
1241{
88bf15f0 1242
c5b5eee1 1243 if(events_request == NULL) return;
1244
1245 if(events_request->start_position != NULL)
88bf15f0 1246 lttv_traceset_destroy_position(events_request->start_position);
c5b5eee1 1247 if(events_request->end_position != NULL)
88bf15f0
FD
1248 lttv_traceset_destroy_position(events_request->end_position);
1249#ifdef BABEL_CLEANUP
1250 if(events_request->hooks != NULL) {
c5b5eee1 1251 GArray *hooks = events_request->hooks;
88bf15f0 1252
04348950 1253 lttv_trace_hook_remove_all(&hooks);
88bf15f0 1254
c5b5eee1 1255 g_array_free(events_request->hooks, TRUE);
88bf15f0 1256
c5b5eee1 1257 }
88bf15f0 1258
c5b5eee1 1259 if(events_request->before_chunk_traceset != NULL)
1260 lttv_hooks_destroy(events_request->before_chunk_traceset);
1261 if(events_request->before_chunk_trace != NULL)
1262 lttv_hooks_destroy(events_request->before_chunk_trace);
1263 if(events_request->before_chunk_tracefile != NULL)
1264 lttv_hooks_destroy(events_request->before_chunk_tracefile);
1265 if(events_request->event != NULL)
1266 lttv_hooks_destroy(events_request->event);
c5b5eee1 1267 if(events_request->after_chunk_tracefile != NULL)
1268 lttv_hooks_destroy(events_request->after_chunk_tracefile);
1269 if(events_request->after_chunk_trace != NULL)
1270 lttv_hooks_destroy(events_request->after_chunk_trace);
1271 if(events_request->after_chunk_traceset != NULL)
1272 lttv_hooks_destroy(events_request->after_chunk_traceset);
1273 if(events_request->before_request != NULL)
1274 lttv_hooks_destroy(events_request->before_request);
1275 if(events_request->after_request != NULL)
1276 lttv_hooks_destroy(events_request->after_request);
9a366873 1277#endif /*BABEL_CLEANUP*/
88bf15f0
FD
1278 g_free(events_request);
1279
1280
c5b5eee1 1281}
1282
1283
f9240312 1284__EXPORT GtkWidget *main_window_get_widget(Tab *tab)
6a4f1205 1285{
93ac601b 1286 return tab->mw->mwindow;
6a4f1205 1287}
1288
This page took 0.127149 seconds and 4 git commands to generate.