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