Revert Back button
[platform/framework/web/wrt.git] / src / wrt-client / window_data.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file        window_data.cpp
18  * @author      Jaroslaw Osmanski (j.osmanski@samsung.com)
19  * @version     1.0
20  * @brief       Window data class implementation
21  */
22 #include "window_data.h"
23
24 #include <ui-gadget.h>
25 #include <dpl/log/log.h>
26
27 namespace {
28 char const* const PLATFORM_EDJ_PATH = "/usr/share/edje/wrt/Platform.edj";
29 char const* const DAEMON_EDJ_PATH = "/usr/share/edje/wrt/Daemon.edj";
30 char const* const THEME_EDJ_PATH = "/usr/share/edje/wrt/wrt_theme.edj";
31 char const* const ELM_STATE_SHOW_CONTENT = "elm,state,show,content";
32 char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content";
33 char const* const ELM_SWALLOW_BACKWARD = "elm.swallow.backward";
34 char const* const ELM_SWALLOW_TOOLBAR = "elm.swallow.toolbar";
35 char const* const ELM_RECT_HIDDENOPTION = "elm.rect.hiddenOption";
36
37 const char *EDJE_SHOW_TOOLBAR_SIGNAL = "show,toolbar,signal";
38 const char *EDJE_HIDE_TOOLBAR_SIGNAL = "hide,toolbar,signal";
39 const char *EDJE_SHOW_HIDDENOPTION_SIGNAL = "show,hiddenOption,signal";
40 const char *EDJE_HIDE_HIDDENOPTION_SIGNAL = "hide,hiddenOption,signal";
41
42 char const* const ELM = "elm";
43 char const* const LAYOUT = "layout";
44 char const* const APPLICATION = "application";
45 char const* const INDICATOR = "indicator";
46 char const* const NOINDICATOR = "noindicator";
47 char const* const INTERNAL_LAYOUT = "internal_layout";
48 char const* const FLOATBACKWARD_BUTTON_STYLE = "wrt/backward";
49 } // anonymous namespace
50
51 WindowData::WindowData(unsigned long pid, bool manualInit) :
52     m_win(NULL), m_naviBackButton(NULL),
53     m_toolbarTimer(NULL),
54     m_debugMode(false)
55 {
56     m_win = createWindow(pid);
57
58     if (!manualInit)
59     {
60         init();
61     }
62 }
63
64 WindowData::~WindowData()
65 {
66     LogDebug("");
67     evas_object_del(m_win);
68 }
69
70 void WindowData::init()
71 {
72     Assert(m_win != NULL && "m_win is null");
73
74     // import button theme
75     elm_theme_overlay_add(NULL, THEME_EDJ_PATH);
76
77     m_platform_layout = createPlatformLayout(m_win);
78     evas_object_show(m_platform_layout);
79     m_navigation = createNavigationBar(m_platform_layout);
80     evas_object_show(m_navigation);
81     m_user_layout = createUserLayout(m_navigation);
82     evas_object_show(m_user_layout);
83     m_conformant = createConformant(m_user_layout);
84     evas_object_show(m_conformant);
85 }
86
87 void WindowData::setEvasObjectForLayout(Evas_Object* evas_object)
88 {
89     elm_object_content_set(m_conformant, evas_object);
90 }
91
92 void WindowData::unsetEvasObjectForLayout()
93 {
94     elm_object_content_unset(m_conformant);
95 }
96
97 void WindowData::toggleIndicator(bool fullscreen)
98 {
99     LogDebug("fullscreen=" << (fullscreen?"true":"false"));
100
101     if (!fullscreen) {
102         elm_win_indicator_mode_set(m_win, ELM_WIN_INDICATOR_SHOW);
103         elm_layout_theme_set(m_platform_layout,
104                 LAYOUT,
105                 APPLICATION,
106                 INDICATOR);
107     } else {
108         elm_win_indicator_mode_set(m_win, ELM_WIN_INDICATOR_HIDE);
109         elm_layout_theme_set(m_platform_layout,
110                 LAYOUT,
111                 APPLICATION,
112                 NOINDICATOR);
113     }
114 }
115
116 void WindowData::setViewMode(
117         const char *title,
118         bool fullscreen,
119         bool backbutton,
120         CtxMenuItems ctxMenuItems)
121 {
122     LogDebug("setViewMode " <<m_debugMode);
123     LogDebug("fullscreen: " << fullscreen);
124     LogDebug("backbutton: " << backbutton);
125
126     m_fullscreen = fullscreen;
127
128     toggleIndicator(m_fullscreen);
129
130     if (backbutton) {
131         createFloatBackButton();
132     }
133
134     m_title = title;
135     m_ctxMenuItems = ctxMenuItems;
136
137     if(m_debugMode) {
138         if(fullscreen)
139             showHiddenOption(m_user_layout);
140         else
141             createTitle(m_title.c_str(), m_ctxMenuItems);
142
143         createToolbar(m_ctxMenuItems);
144     }
145     else
146         if(!fullscreen)
147             createTitle(m_title.c_str(), m_ctxMenuItems);
148 }
149
150 void WindowData::createTitle(const char *data, CtxMenuItems ctxMenuItems)
151 {
152     LogDebug("createTitle");
153     showTitle(data);
154     if(m_debugMode) {
155         createMoreButton();
156         createTitleToolbar(ctxMenuItems);
157     }
158 }
159
160 void WindowData::showTitle(const char *data)
161 {
162     LogInfo("showTitle");
163
164     Elm_Object_Item* naviIt = elm_naviframe_top_item_get(m_navigation);
165     elm_naviframe_item_title_visible_set(naviIt, EINA_TRUE);
166     elm_object_item_text_set(naviIt, data);
167 }
168
169 void WindowData::hideTitle()
170 {
171     LogInfo("hideTitle");
172
173     Elm_Object_Item* naviIt = elm_naviframe_top_item_get(m_navigation);
174     elm_object_item_signal_emit(naviIt, "elm,state,optionheader,instant_close", "");
175     optionheaderClose = FALSE;
176
177     elm_naviframe_item_title_visible_set(naviIt, EINA_FALSE);
178 }
179
180 void WindowData::createMoreButton()
181 {
182     Evas_Object *btn = elm_button_add(m_navigation);
183     if (!btn)
184         return;
185     Elm_Object_Item* naviIt = elm_naviframe_top_item_get(m_navigation);
186     elm_object_style_set(btn, "naviframe/more/default");
187     evas_object_smart_callback_add(btn, "clicked", moreButtonCallback, this);
188     elm_object_item_part_content_set(naviIt, "title_more_btn", btn);
189     evas_object_show(btn);
190
191 }
192
193 void WindowData::createTitleToolbar(CtxMenuItems ctxMenuItems)
194 {
195     Elm_Object_Item *toolbarIt;
196     Evas_Object *toolbarButton;
197     Elm_Object_Item *naviIt = elm_naviframe_top_item_get(m_navigation);
198
199     Evas_Object *toolbar = elm_toolbar_add(m_navigation);
200     if (!toolbar)
201         return;
202     elm_toolbar_shrink_mode_set(toolbar, ELM_TOOLBAR_SHRINK_EXPAND);
203
204     elm_object_style_set(toolbar, "naviframe");
205
206     toolbarButton = elm_button_add(m_navigation);
207     if (!toolbarButton)
208         return;
209
210     std::list<CtxMenuItem>::iterator itor;
211     for (itor = ctxMenuItems.begin(); itor != ctxMenuItems.end(); ++itor) {
212         toolbarButton = elm_button_add(toolbar);
213         elm_object_style_set(toolbarButton, "naviframe_contrl/default");
214         evas_object_size_hint_align_set(toolbarButton,
215                 EVAS_HINT_FILL,
216                 EVAS_HINT_FILL);
217         elm_object_text_set(toolbarButton, ((*itor).label).c_str());
218         evas_object_smart_callback_add(toolbarButton,
219                 "clicked",
220                 (*itor).callback,
221                 (*itor).data);
222         toolbarIt = elm_toolbar_item_append(toolbar, NULL, NULL, NULL, NULL);
223         elm_object_item_part_content_set(toolbarIt, "object", toolbarButton);
224     }
225
226     toolbarButton = elm_button_add(toolbar);
227     elm_object_style_set(toolbarButton, "naviframe_contrl/default");
228     evas_object_size_hint_align_set(toolbarButton,
229             EVAS_HINT_FILL,
230             EVAS_HINT_FILL);
231     elm_object_text_set(toolbarButton, WRT_OPTION_LABEL_FULLVIEW);
232     evas_object_smart_callback_add(toolbarButton,
233             "clicked",
234             changeViewModeCallback,
235             this);
236     toolbarIt = elm_toolbar_item_append(toolbar, NULL, NULL, NULL, NULL);
237     elm_object_item_part_content_set(toolbarIt, "object", toolbarButton);
238
239     elm_object_item_part_content_set(naviIt, "optionheader", toolbar);
240     elm_object_item_signal_emit(naviIt,
241             "elm,state,optionheader,instant_close",
242             "");
243     optionheaderClose = TRUE;
244 }
245
246 void WindowData::createToolbar(CtxMenuItems ctxMenuItems)
247 {
248     Elm_Object_Item *toolbarIt;
249     Evas_Object *toolbarButton;
250     Evas_Object *toolbar;
251     char buf[100];
252
253     toolbar = elm_toolbar_add(m_user_layout);
254     if (!toolbar)
255         return;
256
257     elm_object_style_set(toolbar, "naviframe");
258     elm_object_part_content_set(m_user_layout,
259             ELM_SWALLOW_TOOLBAR,
260             toolbar);
261
262     std::list<CtxMenuItem>::iterator itor;
263     for (itor = ctxMenuItems.begin(); itor != ctxMenuItems.end(); ++itor) {
264         toolbarButton = elm_button_add(toolbar);
265         if (!toolbarButton)
266             return;
267
268         evas_object_size_hint_align_set(toolbarButton,
269                 EVAS_HINT_FILL,
270                 EVAS_HINT_FILL);
271         evas_object_size_hint_weight_set(toolbarButton,
272                 EVAS_HINT_EXPAND,
273                 EVAS_HINT_EXPAND);
274
275         Evas_Object *ic = elm_icon_add(toolbar);
276          snprintf(buf, sizeof(buf), (*itor).icon.c_str());
277          elm_icon_file_set(ic, buf, NULL);
278         evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
279         elm_icon_resizable_set(ic, EINA_TRUE, EINA_TRUE);
280         elm_object_part_content_set(toolbarButton, "icon", ic);
281
282         evas_object_smart_callback_add(toolbarButton,
283                 "clicked",
284                 (*itor).callback,
285                 (*itor).data);
286         toolbarIt = elm_toolbar_item_append(toolbar, NULL, NULL, NULL, NULL);
287         elm_object_item_part_content_set(toolbarIt, "object", toolbarButton);
288
289         //for margin button between buttons
290         toolbarButton = elm_button_add(toolbar);
291         if (!toolbarButton)
292             return;
293         evas_object_color_set(
294                 toolbarButton,
295                 255,
296                 255,
297                 255,
298                 0);
299         toolbarIt = elm_toolbar_item_append(toolbar, NULL, NULL, NULL, NULL);
300         elm_object_item_part_content_set(toolbarIt, "object", toolbarButton);
301     }
302
303     toolbarButton = elm_button_add(toolbar);
304     if (!toolbarButton)
305         return;
306
307     Evas_Object *ic = elm_icon_add(toolbar);
308     snprintf(buf, sizeof(buf), WRT_OPTION_ICON_WINDOWVIEW);
309     elm_icon_file_set(ic, buf, NULL);
310     evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
311     elm_icon_resizable_set(ic, EINA_TRUE, EINA_TRUE);
312     elm_object_part_content_set(toolbarButton, "icon", ic);
313
314     evas_object_size_hint_align_set(toolbarButton,
315             EVAS_HINT_FILL,
316             EVAS_HINT_FILL);
317     evas_object_size_hint_weight_set(toolbarButton,
318             EVAS_HINT_EXPAND,
319             EVAS_HINT_EXPAND);
320     evas_object_smart_callback_add(toolbarButton,
321             "clicked",
322             changeViewModeCallback,
323             this);
324     toolbarIt = elm_toolbar_item_append(toolbar, NULL, NULL, NULL, NULL);
325     elm_object_item_part_content_set(toolbarIt, "object", toolbarButton);
326
327     optionheaderClose = TRUE;
328
329     elm_object_part_content_set(m_user_layout,
330             ELM_SWALLOW_TOOLBAR,
331             toolbar);
332 }
333
334 void WindowData::showToolbar()
335 {
336     emitSignalForUserLayout(EDJE_SHOW_TOOLBAR_SIGNAL, "");
337     m_toolbarTimer = ecore_timer_add(10.0, hideToolbarCallback, this);
338 }
339
340 void WindowData::hideToolbar()
341 {
342     emitSignalForUserLayout(EDJE_HIDE_TOOLBAR_SIGNAL, "");
343     if(m_toolbarTimer) {
344         ecore_timer_del(m_toolbarTimer);
345         m_toolbarTimer = NULL;
346     }
347 }
348
349 void WindowData::createTitleButton()
350 {
351     // Add left button for back action
352     m_naviBackButton = elm_button_add(m_navigation);
353     elm_object_style_set(m_naviBackButton, "navigationbar_backbutton/default");
354
355     Elm_Object_Item* naviIt = elm_naviframe_top_item_get(m_navigation);
356     elm_object_item_part_content_set(naviIt, "prev_btn", m_naviBackButton);
357 }
358
359 void WindowData::createFloatBackButton()
360 {
361     // Add float backbutton on the left coner
362     m_floatBackButton = elm_button_add(m_user_layout);
363     elm_object_style_set(m_floatBackButton, FLOATBACKWARD_BUTTON_STYLE);
364     elm_object_part_content_set(m_user_layout,
365                                 ELM_SWALLOW_BACKWARD,
366                                 m_floatBackButton);
367     evas_object_show(m_floatBackButton);
368 }
369
370 void WindowData::updateTitleButton(const bool display)
371 {
372     if (display) {
373         evas_object_show(m_naviBackButton);
374     } else {
375         evas_object_hide(m_naviBackButton);
376     }
377 }
378
379 Evas_Object* WindowData::createWindow(unsigned long pid)
380 {
381     Evas_Object* window = elm_win_add(NULL, "wrt-widget", ELM_WIN_BASIC);
382     ecore_x_window_prop_property_set(
383         elm_win_xwindow_get(window),
384         ECORE_X_ATOM_NET_WM_PID,
385         ECORE_X_ATOM_CARDINAL, 32, &pid, 1);
386     elm_win_title_set(window, "wrt-widget");
387     elm_win_borderless_set(window, EINA_TRUE);
388     elm_win_conformant_set(window, EINA_TRUE);
389     int w, h;
390     ecore_x_window_size_get(ecore_x_window_root_first_get(), &w, &h);
391     evas_object_resize(window, w, h);
392     return window;
393 }
394
395 Evas_Object* WindowData::createPlatformLayout(Evas_Object* parent)
396 {
397     Evas_Object*  platform_layout = elm_layout_add(parent);
398
399     if (!elm_layout_file_set(platform_layout, PLATFORM_EDJ_PATH, "platformlayout"))
400         elm_layout_theme_set(platform_layout, LAYOUT, APPLICATION, NOINDICATOR);
401
402     evas_object_size_hint_expand_set(platform_layout,
403                                      EVAS_HINT_EXPAND,
404                                      EVAS_HINT_EXPAND);
405
406     elm_win_resize_object_add(parent, platform_layout);
407
408     edje_object_signal_emit(
409             elm_layout_edje_get(platform_layout), ELM_STATE_SHOW_CONTENT, ELM);
410     return platform_layout;
411 }
412
413 Evas_Object* WindowData::createUserLayout(Evas_Object* parent)
414 {
415     Assert(parent != NULL && "Parent for User Layout is null");
416     Evas_Object* layout = elm_layout_add(parent);
417     elm_layout_file_set(layout, DAEMON_EDJ_PATH, "client");
418     evas_object_size_hint_weight_set(
419             layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
420     evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
421     elm_win_resize_object_add(parent, layout);
422
423     Elm_Object_Item* naviIt = elm_naviframe_item_push(
424         /* Evas_Object *obj */
425         parent,
426         /* const char *title_label  */
427         "",
428         /* Evas_Object *prev_btn */
429         NULL,
430         /* Evas_Object *next_btn */
431         NULL,
432         /* Evas_Object *content */
433         layout,
434         /* const char *item_style */
435         NULL);
436
437     elm_naviframe_item_title_visible_set(naviIt, EINA_FALSE);
438
439     return layout;
440 }
441
442 Evas_Object* WindowData::createConformant(Evas_Object* parent)
443 {
444     Assert(parent != NULL && "Parent is null");
445     Evas_Object* conformant = elm_conformant_add(parent);
446     elm_object_style_set(conformant, INTERNAL_LAYOUT);
447     evas_object_size_hint_weight_set(
448             conformant, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
449     evas_object_size_hint_align_set(conformant, EVAS_HINT_FILL, EVAS_HINT_FILL);
450     elm_object_part_content_set(parent, ELM_SWALLOW_CONTENT, conformant);
451     evas_object_show(conformant);
452     return conformant;
453 }
454
455 Evas_Object* WindowData::createNavigationBar(Evas_Object* parent)
456 {
457     Assert(parent != NULL && "Parent for naviframe is null");
458     Evas_Object* navigation = elm_naviframe_add(parent);
459     elm_object_part_content_set(parent, ELM_SWALLOW_CONTENT, navigation);
460     return navigation;
461 }
462
463 void WindowData::showHiddenOption(Evas_Object* parent)
464 {
465     Assert(parent != NULL && "Parent for Hiden Option");
466
467     emitSignalForUserLayout(EDJE_SHOW_HIDDENOPTION_SIGNAL, "");
468
469     edje_object_signal_callback_add(elm_layout_edje_get(parent),
470             "mouse,clicked,1",
471             "elm.rect.hiddenOption",
472             controlHiddenOptionCallback,
473             this);
474 }
475
476 void WindowData::hideHiddenOption(Evas_Object* parent)
477 {
478     Assert(parent != NULL && "Parent for Hiden Option");
479
480     emitSignalForUserLayout(EDJE_HIDE_HIDDENOPTION_SIGNAL, "");
481
482     edje_object_signal_callback_del(elm_layout_edje_get(parent),
483             "mouse,clicked,1",
484             "elm.rect.hiddenOption",
485             controlHiddenOptionCallback);
486 }
487
488 void WindowData::initFullViewMode ()
489 {
490     hideToolbar();
491     showHiddenOption(m_user_layout);
492 }
493
494 void WindowData::addNaviBackButtonCallback(
495         const char* event,
496         CallbackType callback,
497         const void* data)
498 {
499     Assert(m_naviBackButton != NULL && "m_naviBackButton is null");
500     evas_object_smart_callback_add(m_naviBackButton, event, callback, data);
501 }
502
503 void* WindowData::delNaviBackButtonCallback(
504         const char* event,
505         CallbackType callBack)
506 {
507     Assert(m_naviBackButton != NULL && "m_naviBackButton is null");
508     return evas_object_smart_callback_del(m_naviBackButton, event, callBack);
509 }
510
511 void WindowData::addFloatBackButtonCallback(
512         const char* event,
513         CallbackType callback,
514         const void* data)
515 {
516     Assert(m_floatBackButton != NULL && "m_floatBackButton is null");
517     evas_object_smart_callback_add(m_floatBackButton, event, callback, data);
518 }
519
520 void* WindowData::delFloatBackButtonCallback(
521         const char* event,
522         CallbackType callBack)
523 {
524     Assert(m_floatBackButton != NULL && "m_floatBackButton is null");
525     return evas_object_smart_callback_del(m_floatBackButton, event, callBack);
526 }
527
528 void WindowData::userlayoutCallbackAdd(
529         const Evas_Callback_Type event,
530         EvasCallbackType callback,
531         const void* data)
532 {
533     Assert(m_user_layout != NULL && "m_user_layout is null");
534     evas_object_event_callback_add(m_user_layout, event, callback, data);
535 }
536
537 void* WindowData::userlayoutCallbackDel(
538         const Evas_Callback_Type event,
539         EvasCallbackType callBack)
540 {
541     Assert(m_user_layout != NULL && "m_user_layout is null");
542     return evas_object_event_callback_del(m_user_layout, event, callBack);
543 }
544
545 void WindowData::emitSignalForUserLayout(
546         const char* emission, const char* source)
547 {
548     LogInfo("emitSignalForUserLayout called");
549     Assert(m_user_layout != NULL && "m_user_layout is null");
550     Assert(emission != NULL && "emission is null");
551     Assert(source != NULL && "source is null");
552
553     edje_object_signal_emit(
554             elm_layout_edje_get(m_user_layout), emission, source);
555 }
556
557 void WindowData::moreButtonCallback(void *data,
558         Evas_Object */*obj*/,
559         void */*event_info*/)
560 {
561     WindowData* This = static_cast<WindowData*>(data);
562     Elm_Object_Item *naviIt = elm_naviframe_top_item_get(This->m_navigation);
563
564     if (This->optionheaderClose)
565         elm_object_item_signal_emit(naviIt, "elm,state,optionheader,open", "");
566     else
567         elm_object_item_signal_emit(naviIt, "elm,state,optionheader,close", "");
568
569     This->optionheaderClose = !This->optionheaderClose;
570 }
571
572
573 void WindowData::changeViewModeCallback(void *data,
574         Evas_Object */*obj*/,
575         void */*event_info*/)
576 {
577     WindowData* This = static_cast<WindowData*>(data);
578     Elm_Object_Item *naviIt = elm_naviframe_top_item_get(This->m_navigation);
579
580     if(elm_naviframe_item_title_visible_get(naviIt)) {
581         This->hideTitle();
582         This->showHiddenOption(This->m_user_layout);
583
584     } else {
585         This->createTitle(This->m_title.c_str(), This->m_ctxMenuItems);
586         This ->hideToolbar();
587     }
588 }
589
590 void WindowData::controlHiddenOptionCallback(void *data,
591         Evas_Object */*obj*/,
592         const char */*emission*/,
593         const char */*source*/)
594 {
595     LogDebug("controlHiddenOptionCallback");
596     WindowData* This = static_cast<WindowData *>(data);
597     Elm_Object_Item *naviIt = elm_naviframe_top_item_get(This->m_navigation);
598
599     if(!elm_naviframe_item_title_visible_get(naviIt)) {
600         const char* state = edje_object_part_state_get(
601                 elm_layout_edje_get(This->m_user_layout),
602                 "elm.swallow.toolbar",
603                 NULL);
604
605         if (state && !strncmp(state, "default", strlen("default"))) {
606             This->showToolbar();
607             This->hideHiddenOption(This->m_user_layout);
608         }
609         else {
610             This->initFullViewMode();
611         }
612
613     }
614 }
615
616 Eina_Bool WindowData::hideToolbarCallback(void *data)
617 {
618     WindowData *This = static_cast<WindowData *>(data);
619
620     This->initFullViewMode();
621     return TRUE;
622 }
623
624 void WindowData::toggleFullscreen(bool fullscreen)
625 {
626     LogDebug(__PRETTY_FUNCTION__);
627
628     static bool alreadyFullscreen = false;
629
630     if (alreadyFullscreen == fullscreen) {
631         // window is in fullscreen mode and fullscreen mode is requested, or
632         // window is not in fullscreen and a request is made to exit fullscreen
633         // In these two situations we don't have to do anything here.
634         return;
635     }
636
637     if (!m_fullscreen) {
638         //If ViewMode is not fullscreen, toggle the title bar and indicator
639         fullscreen ? hideTitle() : showTitle(m_title.c_str());
640         toggleIndicator(fullscreen);
641     }
642     alreadyFullscreen = !alreadyFullscreen;
643 }