Initial Import
[profile/ivi/clutter-toys.git] / attic / mallums-magic-browser / web-browser.c
1 #include <clutter/clutter.h>
2 #include <webkit/webkit.h>
3 #include <tidy/tidy.h>
4
5 #include "web-browser.h"
6 #include "scroll-frame.h"
7 #include "popup-factory.h"
8
9 static void
10 tabs_cb (ClutterActor *button,
11          ClutterEvent *event,
12          MmBrowser    *browser);
13
14 G_DEFINE_TYPE (MmBrowser, mm_browser, CLUTTER_TYPE_GROUP)
15 #define BROWSER_PRIVATE(o) \
16   (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_BROWSER, MmBrowserPrivate))
17
18 typedef struct _MmBrowserPage
19 {
20   MmBrowser *browser;
21   ClutterActor *webkit;
22   ClutterActor *overlay;
23   ClutterActor *scroll;
24   ClutterActor *popup_menu;
25
26   PopupFactory *factory;
27
28   WebKitWebView *view;
29   WebkitAdjustment *hadj, *vadj;
30
31   char *address;
32
33   gboolean over_link;
34
35   int start_x;
36   int start_y;
37 } MmBrowserPage;
38
39 struct _MmBrowserPrivate
40 {
41   ClutterTimeline *fade_timeline;
42   ClutterTimeline *scale_timeline;
43   ClutterTimeline *scroll_timeline;
44   ClutterTimeline *move_timeline;
45
46   ClutterEffectTemplate *fade_template;
47   ClutterEffectTemplate *scale_template;
48   ClutterEffectTemplate *scroll_template;
49
50   ClutterActor *toolbar, *toolbar_bg;
51   ClutterActor *tab_control;
52   ClutterActor *new_tab;
53   ClutterActor *prev_tab;
54   ClutterActor *next_tab;
55
56   ClutterActor *next_prev_group;
57
58   ClutterActor *back;
59   ClutterActor *forward;
60   ClutterActor *entry;
61   ClutterActor *tabs;
62   ClutterActor *progress;
63
64   ClutterActor *page_group;
65
66   GList *pages;
67   GList *current_page;
68
69   gboolean showing_tabs;
70   gboolean maybe_scroll;
71
72   int popup_x;
73   int popup_y;
74 };
75
76 #define WEBKIT_WIDTH 800
77 #define WEBKIT_HEIGHT 480
78
79 #define JITTER 5
80
81 static void
82 mm_browser_finalize (GObject *object)
83 {
84   G_OBJECT_CLASS (mm_browser_parent_class)->finalize (object);
85 }
86
87 static void
88 mm_browser_dispose (GObject *object)
89 {
90   G_OBJECT_CLASS (mm_browser_parent_class)->dispose (object);
91 }
92
93 static void
94 mm_browser_class_init (MmBrowserClass *klass)
95 {
96   GObjectClass *o_class = (GObjectClass *) klass;
97   ClutterActorClass *a_class = (ClutterActorClass *) klass;
98
99   g_type_class_add_private (klass, sizeof (MmBrowserPrivate));
100
101   o_class->finalize = mm_browser_finalize;
102   o_class->dispose = mm_browser_dispose;
103 }
104
105 static void
106 set_back_and_forward (MmBrowser *browser)
107 {
108   MmBrowserPrivate *priv = browser->priv;
109   MmBrowserPage *page;
110
111   /* Get top page */
112   page = priv->current_page->data;
113
114   if (webkit_web_view_can_go_back (page->view)) {
115     clutter_effect_fade (priv->fade_template, priv->back, 0xff, NULL, NULL);
116   } else {
117     clutter_effect_fade (priv->fade_template, priv->back, 0x55, NULL, NULL);
118   }
119
120   if (webkit_web_view_can_go_forward (page->view)) {
121     clutter_effect_fade (priv->fade_template, priv->forward, 0xff, NULL, NULL);
122   } else {
123     clutter_effect_fade (priv->fade_template, priv->forward, 0x55, NULL, NULL);
124   }
125 }
126
127 static void
128 load_started_cb (WebKitWebView  *web_view,
129                  WebKitWebFrame *frame,
130                  MmBrowser      *browser)
131 {
132   MmBrowserPrivate *priv = browser->priv;
133   ClutterTimeline *tl;
134
135   clutter_effect_fade (priv->fade_template, priv->progress, 0xff, NULL, NULL);
136   clutter_timeline_start (priv->move_timeline);
137 }
138
139 static void
140 load_finished_cb (WebKitWebView  *web_view,
141                   WebKitWebFrame *frame,
142                   MmBrowser      *browser)
143 {
144   MmBrowserPrivate *priv = browser->priv;
145   MmBrowserPage *page;
146   ClutterTimeline *tl;
147
148   clutter_effect_fade (priv->fade_template, priv->progress, 0x00, NULL, NULL);
149   clutter_timeline_stop (priv->move_timeline);
150   clutter_timeline_rewind (priv->move_timeline);
151
152   clutter_entry_set_text (CLUTTER_ENTRY (priv->entry),
153                           webkit_web_frame_get_uri (frame));
154   page = priv->current_page->data;
155
156   g_free (page->address);
157   page->address = g_strdup (webkit_web_frame_get_uri (frame));
158
159   set_back_and_forward (browser);
160 }
161
162 static gboolean
163 webkit_event_capture_cb (ClutterActor  *actor,
164                          ClutterEvent  *event,
165                          MmBrowserPage *page)
166 {
167   MmBrowser *browser = page->browser;
168   MmBrowserPrivate *priv = browser->priv;
169
170   switch (event->type) {
171   case CLUTTER_BUTTON_PRESS:
172     if (priv->showing_tabs == TRUE)
173       {
174         tabs_cb (NULL, NULL, browser);
175         return TRUE;
176       }
177
178     return FALSE;
179
180   case CLUTTER_BUTTON_RELEASE:
181     return FALSE;
182
183   case CLUTTER_MOTION:
184 #if 0
185     if (priv->maybe_scroll == TRUE) {
186       ClutterMotionEvent *mev = (ClutterMotionEvent *) event;
187       int dx = mev->x - page->start_x;
188       int dy = mev->y - page->start_y;
189
190       gtk_adjustment_set_value (page->hscroll,
191                                 MIN (page->hscroll->value - dx,
192                                      page->hscroll->upper - WEBKIT_WIDTH));
193       gtk_adjustment_set_value (page->vscroll,
194                                 MIN (page->vscroll->value - dy,
195                                      page->vscroll->upper - WEBKIT_HEIGHT));
196
197       page->start_x = mev->x;
198       page->start_y = mev->y;
199     } else {
200       return FALSE;
201     }
202 #endif
203     return FALSE;
204
205   case CLUTTER_ENTER:
206   case CLUTTER_LEAVE:
207   default:
208     /* Let the actor handle all the other events */
209     return FALSE;
210   }
211
212   return TRUE;
213 }
214
215 static void
216 hovering_over_link_cb (WebKitWebView *view,
217                        const char    *string1, /* What is this string? */
218                        const char    *url,
219                        MmBrowserPage *page)
220 {
221   if (string1 == NULL && url == NULL) {
222     page->over_link = FALSE;
223   } else {
224     page->over_link = TRUE;
225   }
226 }
227
228 static void
229 show_popup_menu (WebKitPopupFactory *factory,
230                  MmBrowser          *browser)
231 {
232   MmBrowserPrivate *priv = browser->priv;
233   MmBrowserPage *page;
234
235   page = priv->current_page->data;
236   clutter_actor_raise_top (page->popup_menu);
237   clutter_actor_show_all (page->popup_menu);
238 }
239
240 static void
241 hide_popup_menu (WebKitPopupFactory *factory,
242                  MmBrowser          *browser)
243 {
244   MmBrowserPrivate *priv = browser->priv;
245   MmBrowserPage *page;
246
247   page = priv->current_page->data;
248   clutter_actor_hide (page->popup_menu);
249 }
250
251 static gboolean
252 popup_button_release_cb (ClutterActor       *actor,
253                          ClutterButtonEvent *event,
254                          MmBrowser          *browser)
255 {
256   MmBrowserPrivate *priv = browser->priv;
257   MmBrowserPage *page;
258
259   page = priv->current_page->data;
260
261   if ((ABS (event->x - priv->popup_x) < JITTER) &&
262       (ABS (event->y - priv->popup_y) < JITTER)) {
263     int row;
264
265     row = tidy_list_view_get_row_at_pos (TIDY_LIST_VIEW (page->factory),
266                                          event->x, event->y);
267     if (row == -1) {
268       return FALSE;
269     }
270
271     webkit_popup_factory_activate (WEBKIT_POPUP_FACTORY (page->factory), row);
272     webkit_popup_factory_close (WEBKIT_POPUP_FACTORY (page->factory));
273     return TRUE;
274   }
275
276   return FALSE;
277 }
278
279 static gboolean
280 popup_button_press_cb (ClutterActor       *actor,
281                        ClutterButtonEvent *event,
282                        MmBrowser          *browser)
283 {
284   MmBrowserPrivate *priv = browser->priv;
285
286   if (event->button != 1) {
287     return FALSE;
288   }
289
290   priv->popup_x = event->x;
291   priv->popup_y = event->y;
292
293   return TRUE;
294 }
295
296 static void
297 create_popup_factory (MmBrowser     *browser,
298                       MmBrowserPage *page)
299 {
300   MmBrowserPrivate *priv = browser->priv;
301   ClutterActor *bground, *scroll;
302   ClutterColor black = {0xbb, 0xbb, 0xbb, 0xdd};
303
304   page->popup_menu = clutter_group_new ();
305
306   bground = clutter_rectangle_new_with_color (&black);
307   clutter_container_add_actor (CLUTTER_CONTAINER (page->popup_menu), bground);
308   clutter_actor_set_size (bground, WEBKIT_WIDTH, 125);
309   clutter_actor_show (bground);
310
311   page->factory = g_object_new (POPUP_TYPE_FACTORY,
312                                 "rules-hint", FALSE,
313                                 "show-headers", FALSE,
314                                 NULL);
315   tidy_stylable_set_style (TIDY_STYLABLE (page->factory), tidy_style_new ());
316   tidy_stylable_set (TIDY_STYLABLE (page->factory),
317                      "font-name", "Impact 20", NULL);
318
319   g_signal_connect (page->factory, "show-menu",
320                     G_CALLBACK (show_popup_menu), browser);
321   g_signal_connect (page->factory, "hide-menu",
322                     G_CALLBACK (hide_popup_menu), browser);
323   g_signal_connect (page->factory, "button-press-event",
324                     G_CALLBACK (popup_button_press_cb), browser);
325   g_signal_connect (page->factory, "button-release-event",
326                     G_CALLBACK (popup_button_release_cb), browser);
327   webkit_web_view_set_popup_factory (page->view, WEBKIT_POPUP_FACTORY (page->factory));
328   clutter_actor_set_size (CLUTTER_ACTOR (page->factory), WEBKIT_WIDTH, 125);
329   clutter_actor_show (CLUTTER_ACTOR (page->factory));
330
331   scroll = tidy_finger_scroll_new (TIDY_FINGER_SCROLL_MODE_KINETIC);
332   clutter_container_add_actor (CLUTTER_CONTAINER (page->popup_menu), scroll);
333   clutter_container_add_actor (CLUTTER_CONTAINER (scroll),
334                                CLUTTER_ACTOR (page->factory));
335   clutter_actor_set_size (scroll, WEBKIT_WIDTH, 125);
336
337   clutter_actor_set_position (page->popup_menu, 0, WEBKIT_HEIGHT - 125);
338   clutter_container_add_actor (CLUTTER_CONTAINER (clutter_stage_get_default ()),
339                                page->popup_menu);
340
341   clutter_actor_show_all (scroll);
342 }
343
344 static void
345 page_start_editing_cb (WebkitActor *actor,
346                        MmBrowser   *browser)
347 {
348   MmBrowserPrivate *priv = browser->priv;
349   MmBrowserPage *page;
350
351   /* Get top page */
352   page = priv->current_page->data;
353
354   webkit_web_view_zoom_to_selected_node (page->view);
355 }
356
357 static void
358 page_stop_editing_cb (WebkitActor *actor,
359                       MmBrowser   *browser)
360 {
361   MmBrowserPrivate *priv = browser->priv;
362   MmBrowserPage *page;
363
364   /* Get top page */
365   page = priv->current_page->data;
366
367   webkit_web_view_zoom_to_default (page->view);
368 }
369
370 static void
371 add_new_page (MmBrowser *browser)
372 {
373   MmBrowserPrivate *priv = browser->priv;
374   MmBrowserPage *page;
375   ClutterActor *frame;
376
377   page = g_new (MmBrowserPage, 1);
378   page->address = NULL;
379   page->browser = browser;
380
381   page->hadj = webkit_adjustment_new (0,0,0,0,0,0);
382   page->vadj = webkit_adjustment_new (0,0,0,0,0,0);
383
384   page->webkit = webkit_web_view_new (WEBKIT_WIDTH, WEBKIT_HEIGHT);
385   webkit_web_view_set_scroll_adjustments (WEBKIT_WEB_VIEW (page->webkit),
386                                           page->hadj, page->vadj);
387
388   clutter_actor_set_reactive (page->webkit, TRUE);
389   clutter_actor_set_size (page->webkit, WEBKIT_WIDTH, WEBKIT_HEIGHT);
390   g_signal_connect (page->webkit, "captured-event",
391                     G_CALLBACK (webkit_event_capture_cb), page);
392   page->view = WEBKIT_WEB_VIEW (page->webkit);
393   clutter_actor_show (page->webkit);
394
395   frame = g_object_new (SCROLL_TYPE_FRAME, NULL);
396   /* clutter_actor_set_size (frame, WEBKIT_WIDTH, WEBKIT_HEIGHT); */
397   clutter_actor_show (frame);
398
399   scroll_frame_add_webkit (SCROLL_FRAME (frame), page->view);
400
401   page->scroll = tidy_finger_scroll_new (TIDY_FINGER_SCROLL_MODE_KINETIC);
402   tidy_stylable_set_style (TIDY_STYLABLE (page->scroll), tidy_style_new ());
403   tidy_stylable_set (TIDY_STYLABLE (page->scroll),
404                      "xthickness", 5, "ythickness", 5, NULL);
405   clutter_actor_set_size (page->scroll, WEBKIT_WIDTH, WEBKIT_HEIGHT);
406   clutter_container_add_actor (CLUTTER_CONTAINER (page->scroll), frame);
407
408   webkit_web_view_open (page->view, "about:blank");
409   g_signal_connect (page->view, "load-started",
410                     G_CALLBACK (load_started_cb), browser);
411   g_signal_connect (page->view, "load-finished",
412                     G_CALLBACK (load_finished_cb), browser);
413   g_signal_connect (page->view, "hovering-over-link",
414                     G_CALLBACK (hovering_over_link_cb), page);
415   g_signal_connect (page->view, "start-editing",
416                     G_CALLBACK (page_start_editing_cb), browser);
417   g_signal_connect (page->view, "stop-editing",
418                     G_CALLBACK (page_stop_editing_cb), browser);
419
420   clutter_actor_set_anchor_point_from_gravity (page->scroll,
421                                                CLUTTER_GRAVITY_CENTER);
422   clutter_actor_set_position (page->scroll, WEBKIT_WIDTH / 2,
423                               WEBKIT_HEIGHT / 2);
424
425   clutter_container_add_actor (CLUTTER_CONTAINER (priv->page_group),
426                                page->scroll);
427   priv->pages = g_list_append (priv->pages, page);
428
429   create_popup_factory (browser, page);
430
431   /* Fixme...obviously */
432   priv->current_page = g_list_last (priv->pages);
433 }
434
435 static ClutterActor *
436 make_button (const char *image)
437 {
438   return clutter_texture_new_from_file (image, NULL);
439 }
440
441 #if 0
442 static void
443 key_release_cb (ClutterEntry *entry,
444                 ClutterEvent *event,
445                 MmBrowser    *browser)
446 {
447   if (event->type == CLUTTER_KEY_RELEASE) {
448     ClutterKeyEvent *kev = (ClutterKeyEvent *) event;
449
450     clutter_entry_handle_key_event (CLUTTER_ENTRY (browser->priv->entry), kev);
451   }
452 }
453 #endif
454 static void
455 entry_activated_cb (ClutterEntry *entry,
456                     MmBrowser    *browser)
457 {
458   ClutterActor *stage = clutter_stage_get_default ();
459   MmBrowserPrivate *priv = browser->priv;
460   char *address = g_strdup (clutter_entry_get_text (entry));
461   MmBrowserPage *page;
462
463   mm_browser_open (browser, address);
464
465   page = priv->current_page->data;
466   clutter_stage_set_key_focus (CLUTTER_STAGE (stage), page->webkit);
467   g_free (address);
468 }
469
470 static void
471 entry_clicked_cb (ClutterActor       *actor,
472                   ClutterButtonEvent *event,
473                   MmBrowser          *browser)
474 {
475   ClutterActor *stage = clutter_stage_get_default ();
476   MmBrowserPrivate *priv = browser->priv;
477
478   clutter_stage_set_key_focus (CLUTTER_STAGE (stage), priv->entry);
479 }
480
481 static void
482 back_cb (ClutterActor *button,
483          ClutterEvent *event,
484          MmBrowser    *browser)
485 {
486   MmBrowserPrivate *priv = browser->priv;
487   MmBrowserPage *page;
488
489   if (priv->showing_tabs == TRUE)
490     return;
491
492   /* Get top page */
493   page = priv->current_page->data;
494   webkit_web_view_go_back (page->view);
495   set_back_and_forward (browser);
496 }
497
498 static void
499 forward_cb (ClutterActor *button,
500             ClutterEvent *event,
501             MmBrowser    *browser)
502 {
503   MmBrowserPrivate *priv = browser->priv;
504   MmBrowserPage *page;
505
506   if (priv->showing_tabs == TRUE)
507     return;
508
509   /* Get top page */
510   page = priv->current_page->data;
511   webkit_web_view_go_forward (page->view);
512   set_back_and_forward (browser);
513 }
514
515 static void
516 hide_on_effect_complete (ClutterActor *actor,
517                          gpointer      userdata)
518 {
519   clutter_actor_hide (actor);
520 }
521
522 static void
523 tabs_cb (ClutterActor *button,
524          ClutterEvent *event,
525          MmBrowser    *browser)
526 {
527   MmBrowserPrivate *priv = browser->priv;
528   MmBrowserPage *page, *prev = NULL, *next = NULL;
529
530   if (priv->showing_tabs == FALSE) {
531     page = priv->current_page->data;
532
533     /* Layout previous page */
534     if (priv->current_page->prev) {
535       prev = priv->current_page->prev->data;
536
537       clutter_actor_set_scale (prev->scroll, 0.4, 0.4);
538       clutter_actor_set_position (prev->scroll, 0, 240);
539       clutter_actor_set_opacity (prev->scroll, 0x00);
540
541       clutter_actor_show (prev->scroll);
542     } else {
543       g_print ("No prev\n");
544     }
545
546     /* Layout next page */
547     if (priv->current_page->next) {
548       next = priv->current_page->next->data;
549
550       clutter_actor_set_scale (next->scroll, 0.4, 0.4);
551       clutter_actor_set_position (next->scroll, 800, 240);
552       clutter_actor_set_opacity (next->scroll, 0x00);
553
554       clutter_actor_show (next->scroll);
555     }
556
557     clutter_effect_scale (priv->scale_template, page->scroll, 
558                           0.4, 0.4, NULL, NULL);
559     clutter_actor_show (priv->tab_control);
560     clutter_effect_fade (priv->fade_template, priv->tab_control, 
561                          0xff, NULL, NULL);
562     if (prev != NULL) {
563       clutter_actor_show (prev->scroll);
564       clutter_effect_fade (priv->fade_template, prev->scroll, 0xff, NULL, NULL);
565     }
566
567     if (next != NULL) {
568       clutter_actor_show (next->scroll);
569       clutter_effect_fade (priv->fade_template, next->scroll, 0xff, NULL, NULL);
570     }
571
572     priv->showing_tabs = TRUE;
573   } else {
574     page = priv->current_page->data;
575
576     if (priv->current_page->prev) {
577       prev = priv->current_page->prev->data;
578
579       clutter_effect_fade (priv->fade_template, prev->scroll, 0x00, hide_on_effect_complete, NULL);
580     }
581
582     if (priv->current_page->next) {
583       next = priv->current_page->next->data;
584
585       clutter_effect_fade (priv->fade_template, next->scroll, 0x00, hide_on_effect_complete, NULL);
586     }
587
588     clutter_effect_scale (priv->scale_template, page->scroll,
589                           1.0, 1.0, NULL, NULL);
590     clutter_effect_fade (priv->fade_template, priv->tab_control,
591                          0x00, hide_on_effect_complete, NULL);
592     priv->showing_tabs = FALSE;
593   }
594 }
595
596 static void
597 select_previous_tab (ClutterActor *button,
598                      ClutterEvent *event,
599                      MmBrowser    *browser)
600 {
601   ClutterActor *stage = clutter_stage_get_default ();
602   MmBrowserPrivate *priv = browser->priv;
603   MmBrowserPage *pages[4], *current;
604   int i;
605
606   pages[2] = priv->current_page->data;
607
608   if (priv->current_page->next) {
609     pages[3] = priv->current_page->next->data;
610   } else {
611     pages[3] = NULL;
612   }
613
614   if (priv->current_page->prev) {
615     pages[1] = priv->current_page->prev->data;
616
617     if (priv->current_page->prev->prev) {
618       pages[0] = priv->current_page->prev->prev->data;
619     } else {
620       pages[0] = NULL;
621     }
622   } else {
623     /* Current page was the first page, so we can't screll */
624     return;
625   }
626
627   /* Scroll all four pages */
628   for (i = 0; i < 4; i++) {
629     int x, y;
630
631     if (pages[i] == NULL) {
632       continue;
633     }
634
635     clutter_actor_get_position (pages[i]->scroll, &x, &y);
636     clutter_effect_move (priv->scroll_template, pages[i]->scroll, 
637                          x + 400, y, NULL, NULL);
638   }
639
640   priv->current_page = priv->current_page->prev;
641   current = priv->current_page->data;
642   clutter_stage_set_key_focus (CLUTTER_STAGE (stage), current->scroll);
643   clutter_entry_set_text (CLUTTER_ENTRY (priv->entry), 
644                           current->address ? current->address : "");
645 }
646
647 static void
648 select_next_tab (ClutterActor *button,
649                  ClutterEvent *event,
650                  MmBrowser    *browser)
651 {
652   ClutterActor *stage = clutter_stage_get_default ();
653   MmBrowserPrivate *priv = browser->priv;
654   MmBrowserPage *pages[4], *current;
655   int i;
656
657   pages[1] = priv->current_page->data;
658
659   if (priv->current_page->prev) {
660     pages[0] = priv->current_page->prev->data;
661   } else {
662     pages[0] = NULL;
663   }
664
665   if (priv->current_page->next) {
666     pages[2] = priv->current_page->next->data;
667
668     if (priv->current_page->next->next) {
669       pages[3] = priv->current_page->next->next->data;
670     } else {
671       pages[3] = NULL;
672     }
673   } else {
674     /* Current page was last page, so we can't scroll */
675     return;
676   }
677
678   /* Scroll all four pages */
679   for (i = 0; i < 4; i++) {
680     int x, y;
681
682     if (pages[i] == NULL) {
683       continue;
684     }
685
686     clutter_actor_get_position (pages[i]->scroll, &x, &y);
687     clutter_effect_move (priv->scroll_template, pages[i]->scroll, 
688                          x - 400, y, NULL, NULL);
689   }
690
691   priv->current_page = priv->current_page->next;
692   current = priv->current_page->data;
693   clutter_stage_set_key_focus (CLUTTER_STAGE (stage), current->webkit);
694   clutter_entry_set_text (CLUTTER_ENTRY (priv->entry), 
695                           current->address ? current->address : "");
696 }
697
698 static void
699 create_new_tab (ClutterActor *button,
700                 ClutterEvent *event,
701                 MmBrowser    *browser)
702 {
703   g_print ("New tab\n");
704 }
705
706 static void
707 mm_browser_init (MmBrowser *self)
708 {
709   MmBrowserPrivate *priv;
710   ClutterColor white = {0x33, 0x33, 0x33, 0xff};
711   ClutterColor progress_color = {0x00, 0x55, 0xdd, 0xff};
712   ClutterActor *stage = clutter_stage_get_default ();
713   ClutterAlpha *alpha;
714   ClutterBehaviour *behave;
715   ClutterKnot progress_knots[] = {{265, 11}, {515, 11}};
716   MmBrowserPage *page;
717
718   priv = self->priv = BROWSER_PRIVATE (self);
719
720   priv->fade_timeline = clutter_timeline_new_for_duration (500);
721   priv->fade_template = clutter_effect_template_new (priv->fade_timeline,
722                                                      CLUTTER_ALPHA_RAMP_INC);
723
724   priv->scale_timeline = clutter_timeline_new_for_duration (100);
725   priv->scale_template = clutter_effect_template_new (priv->scale_timeline,
726                                                       CLUTTER_ALPHA_RAMP_INC);
727
728   priv->scroll_timeline = clutter_timeline_new_for_duration (250);
729   priv->scroll_template = clutter_effect_template_new (priv->scroll_timeline,
730                                                        CLUTTER_ALPHA_RAMP_INC);
731
732   priv->move_timeline = clutter_timeline_new_for_duration (2000);
733   clutter_timeline_set_loop (priv->move_timeline, TRUE);
734
735   alpha = clutter_alpha_new_full (priv->move_timeline, CLUTTER_ALPHA_RAMP, 
736                                   NULL, NULL);
737   behave = clutter_behaviour_path_new (alpha, progress_knots, 2);
738
739   priv->pages = NULL;
740   priv->showing_tabs = FALSE;
741
742   priv->page_group = clutter_group_new ();
743   clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->page_group);
744   clutter_actor_set_position (priv->page_group, 0, 0);
745   clutter_actor_set_size (priv->page_group, WEBKIT_WIDTH, WEBKIT_HEIGHT);
746   clutter_actor_set_reactive (priv->page_group, TRUE);
747
748   add_new_page (self);
749   add_new_page (self);
750   add_new_page (self);
751
752   priv->current_page = priv->current_page->prev;
753   clutter_actor_show (((MmBrowserPage *) priv->current_page->data)->scroll);
754   clutter_actor_raise_top (((MmBrowserPage *) priv->current_page->data)->scroll);
755
756   priv->tab_control = clutter_group_new ();
757   clutter_container_add_actor (CLUTTER_CONTAINER (priv->page_group), priv->tab_control);
758   clutter_actor_set_position (priv->tab_control, 0, 350);
759   clutter_actor_set_size (priv->tab_control, 800, 34);
760   
761   priv->prev_tab = make_button ("assets/go-previous.png");
762   clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
763                                priv->prev_tab);
764   clutter_actor_set_reactive (priv->prev_tab, TRUE);
765   clutter_actor_set_position (priv->prev_tab, 20, 2);
766   g_signal_connect (priv->prev_tab, "button-release-event",
767                     G_CALLBACK (select_previous_tab), self);
768
769   priv->next_tab = make_button ("assets/go-next.png");
770   clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
771                                priv->next_tab);
772   clutter_actor_set_reactive (priv->next_tab, TRUE);
773   clutter_actor_set_position (priv->next_tab, 748, 2);
774   g_signal_connect (priv->next_tab, "button-release-event",
775                     G_CALLBACK (select_next_tab), self);
776
777 #if 0  
778   priv->new_tab = make_button ("assets/document-new.png");
779   clutter_container_add_actor (CLUTTER_CONTAINER (priv->tab_control),
780                                priv->new_tab);
781   clutter_actor_set_reactive (priv->new_tab, TRUE);
782   clutter_actor_set_position (priv->new_tab, 384, 2);
783   g_signal_connect (priv->new_tab, "button-release-event",
784                     G_CALLBACK (create_new_tab), self);
785 #endif
786   clutter_actor_set_opacity (priv->tab_control, 0x00);
787   clutter_actor_show_all (priv->tab_control);
788
789   clutter_actor_show (priv->page_group);
790
791   priv->toolbar = clutter_group_new ();
792   clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->toolbar);
793   clutter_actor_set_position (priv->toolbar, 0, 430);
794
795   priv->toolbar_bg = clutter_texture_new_from_file ("assets/toolbar-bg.png", NULL);
796   clutter_group_add (CLUTTER_GROUP (priv->toolbar), priv->toolbar_bg);
797
798   priv->progress = clutter_rectangle_new_with_color (&progress_color);
799   clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), 
800                                priv->progress);
801   clutter_actor_set_size (priv->progress, 30, 28);
802   clutter_actor_set_position (priv->progress, 265, 11);
803   clutter_actor_set_opacity (priv->progress, 0x00);
804   clutter_behaviour_apply (behave, priv->progress);
805
806
807   priv->back = make_button ("assets/back.png");
808   clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->back);
809   clutter_actor_set_reactive (CLUTTER_ACTOR (priv->back), TRUE);
810   clutter_actor_set_position (priv->back, 140, 2);
811   g_signal_connect (priv->back, "button-release-event",
812                     G_CALLBACK (back_cb), self);
813
814   priv->forward = make_button ("assets/forward.png");
815   clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->forward);
816   clutter_actor_set_reactive (CLUTTER_ACTOR (priv->forward), TRUE);
817   clutter_actor_set_position (priv->forward, 200, 2);
818   g_signal_connect (priv->forward, "button-release-event",
819                     G_CALLBACK (forward_cb), self);
820
821   priv->tabs = make_button ("assets/tabs.png");
822   clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->tabs);
823   clutter_actor_set_reactive (CLUTTER_ACTOR (priv->tabs), TRUE);
824   clutter_actor_set_position (priv->tabs, 8, 2);
825   g_signal_connect (priv->tabs, "button-release-event",
826                     G_CALLBACK (tabs_cb), self);
827
828
829   priv->entry = clutter_entry_new_full ("Sans 28px", "", &white);
830   clutter_container_add_actor (CLUTTER_CONTAINER (priv->toolbar), priv->entry);
831   clutter_actor_set_reactive (priv->entry, TRUE);
832   clutter_actor_set_position (priv->entry, 265, 11);
833   clutter_actor_set_size (priv->entry, 515, 50);
834 #if 0
835   g_signal_connect (priv->entry, "key-release-event",
836                     G_CALLBACK (key_release_cb), self);
837 #endif
838   g_signal_connect (priv->entry, "activate",
839                     G_CALLBACK (entry_activated_cb), self);
840   g_signal_connect (priv->entry, "button-release-event",
841                     G_CALLBACK (entry_clicked_cb), self);
842
843   set_back_and_forward (self);
844
845   page = priv->current_page->data;
846   clutter_stage_set_key_focus (CLUTTER_STAGE (stage), page->webkit);
847
848   clutter_actor_show_all (priv->toolbar);
849
850   /* clutter_actor_raise_top (priv->page_group); */
851 }
852
853 MmBrowser *
854 mm_browser_new (void)
855 {
856   return g_object_new (MM_TYPE_BROWSER, NULL);
857 }
858
859 void
860 mm_browser_open (MmBrowser  *browser,
861                  const char *address)
862 {
863   MmBrowserPrivate *priv = browser->priv;
864   MmBrowserPage *page;
865
866   /* Get top page */
867   page = priv->current_page->data;
868   webkit_web_view_open (page->view, address);
869 }
870
871 /***************************************************************************/
872
873 int
874 main (int    argc,
875       char **argv)
876 {
877         ClutterActor *stage;
878         ClutterActor *background;
879         MmBrowser *browser;
880         ClutterColor col = {0x24, 0x29, 0x29, 0xff};
881
882         clutter_init (&argc, &argv);
883
884         stage = clutter_stage_get_default ();
885         clutter_actor_set_size (stage, 800, 480);
886         clutter_stage_set_color (CLUTTER_STAGE(stage), &col);
887
888         browser = mm_browser_new ();
889         clutter_actor_set_position (CLUTTER_ACTOR (browser), 0, 0);
890         clutter_group_add (CLUTTER_GROUP (stage), CLUTTER_ACTOR (browser));
891         clutter_actor_show_all (stage);
892
893         if (argc < 2) {
894           mm_browser_open (browser, "http://www.openedhand.com");
895         } else {
896           mm_browser_open (browser, argv[1]);
897         }
898
899         clutter_main ();
900         return 0;
901 }