~azzar1/unity/fix-trash-li-blocking

« back to all changes in this revision

Viewing changes to plugins/unityshell/src/HudView.cpp

  • Committer: Daniel van Vugt
  • Date: 2012-03-14 06:24:18 UTC
  • mfrom: (2108 unity)
  • mto: This revision was merged to the branch mainline in revision 2146.
  • Revision ID: daniel.van.vugt@canonical.com-20120314062418-nprucpbr0m7qky5e
MergedĀ latestĀ lp:unity

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 Canonical Ltd
 
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 3 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, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Gord Allott <gord.allott@canonical.com>
 
17
 */
 
18
 
 
19
#include "HudView.h"
 
20
 
 
21
#include <math.h>
 
22
 
 
23
#include <gio/gdesktopappinfo.h>
 
24
#include <glib/gi18n-lib.h>
 
25
#include <gtk/gtk.h>
 
26
#include <Nux/Button.h>
 
27
#include <iostream>
 
28
#include <sstream>
 
29
 
 
30
#include <NuxCore/Logger.h>
 
31
#include <UnityCore/GLibWrapper.h>
 
32
#include <UnityCore/RadioOptionFilter.h>
 
33
#include <UnityCore/Variant.h>
 
34
#include <Nux/HLayout.h>
 
35
#include <Nux/LayeredLayout.h>
 
36
 
 
37
#include <NuxCore/Logger.h>
 
38
#include "HudButton.h"
 
39
#include "UBusMessages.h"
 
40
#include "DashStyle.h"
 
41
 
 
42
namespace unity
 
43
{
 
44
namespace hud
 
45
{
 
46
 
 
47
namespace
 
48
{
 
49
nux::logging::Logger logger("unity.hud.view");
 
50
int icon_size = 42;
 
51
const std::string default_text = _("Type your command");
 
52
const int grow_anim_length = 90 * 1000;
 
53
const int pause_before_grow_length = 32 * 1000;
 
54
}
 
55
 
 
56
NUX_IMPLEMENT_OBJECT_TYPE(View);
 
57
 
 
58
View::View()
 
59
  : nux::View(NUX_TRACKER_LOCATION)
 
60
  , button_views_(NULL)
 
61
  , timeline_id_(0)
 
62
  , start_time_(0)
 
63
  , last_known_height_(0)
 
64
  , current_height_(0)
 
65
  , timeline_need_more_draw_(false)
 
66
  , selected_button_(0)
 
67
{
 
68
  renderer_.SetOwner(this);
 
69
  renderer_.need_redraw.connect([this] () { 
 
70
    QueueDraw();
 
71
  });
 
72
 
 
73
  nux::ROPConfig rop;
 
74
  rop.Blend = true;
 
75
  rop.SrcBlend = GL_ONE;
 
76
  rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
 
77
 
 
78
  SetupViews();
 
79
  search_bar_->key_down.connect (sigc::mem_fun (this, &View::OnKeyDown));
 
80
 
 
81
  search_bar_->activated.connect ([&]() 
 
82
  {
 
83
    search_activated.emit(search_bar_->search_string);
 
84
  });
 
85
 
 
86
  search_bar_->text_entry()->SetLoseKeyFocusOnKeyNavDirectionUp(false);
 
87
  search_bar_->text_entry()->SetLoseKeyFocusOnKeyNavDirectionDown(false);
 
88
 
 
89
  search_bar_->text_entry()->key_nav_focus_change.connect([&](nux::Area *area, bool receiving, nux::KeyNavDirection direction)
 
90
  {
 
91
    // We get here when the Hud closes.
 
92
    // The TextEntry should always have the keyboard focus as long as the hud is open.
 
93
 
 
94
    if (buttons_.empty())
 
95
      return;// early return on empty button list
 
96
 
 
97
    if (receiving)
 
98
    {
 
99
      if (!buttons_.empty())
 
100
      {
 
101
        // If the search_bar gets focus, fake focus the first button if it exists
 
102
        buttons_.back()->fake_focused = true;
 
103
      }
 
104
    }
 
105
    else
 
106
    {
 
107
      // The hud is closing and there are HudButtons visible. Remove the fake_focus.
 
108
      // There should be only one HudButton with the fake_focus set to true.
 
109
      std::list<HudButton::Ptr>::iterator it;
 
110
      for(it = buttons_.begin(); it != buttons_.end(); ++it)
 
111
      {
 
112
        if ((*it)->fake_focused)
 
113
        {
 
114
          (*it)->fake_focused = false;
 
115
        }
 
116
      }      
 
117
    }
 
118
  });
 
119
 
 
120
  mouse_down.connect(sigc::mem_fun(this, &View::OnMouseButtonDown));
 
121
  
 
122
  Relayout();
 
123
}
 
124
 
 
125
View::~View()
 
126
{
 
127
  RemoveChild(search_bar_.GetPointer());
 
128
  for (auto button = buttons_.begin(); button != buttons_.end(); button++)
 
129
  {
 
130
    RemoveChild((*button).GetPointer());
 
131
  }
 
132
}
 
133
 
 
134
void View::ProcessGrowShrink()
 
135
{
 
136
  float diff = g_get_monotonic_time() - start_time_;
 
137
  int target_height = content_layout_->GetGeometry().height;
 
138
  // only animate if we are after our defined pause time
 
139
  if (diff > pause_before_grow_length)
 
140
  {
 
141
   float progress = (diff - pause_before_grow_length) / grow_anim_length;
 
142
   int last_height = last_known_height_;
 
143
   int new_height = 0;
 
144
   
 
145
   if (last_height < target_height)
 
146
   {
 
147
     // grow
 
148
     new_height = last_height + ((target_height - last_height) * progress);
 
149
   }
 
150
   else 
 
151
   {
 
152
     //shrink
 
153
     new_height = last_height - ((last_height - target_height) * progress);
 
154
   }
 
155
   
 
156
   LOG_DEBUG(logger) << "resizing to " << target_height << " (" << new_height << ")"
 
157
                     << "View height: " << GetGeometry().height;
 
158
   current_height_ = new_height;
 
159
  }
 
160
  
 
161
  QueueDraw();  
 
162
  
 
163
  if (diff > grow_anim_length + pause_before_grow_length)
 
164
  {
 
165
    // ensure we are at our final location and update last known height
 
166
    current_height_ = target_height;
 
167
    last_known_height_ = target_height;
 
168
    timeline_need_more_draw_ = false;
 
169
  }
 
170
}
 
171
 
 
172
 
 
173
void View::ResetToDefault()
 
174
{
 
175
  search_bar_->search_string = "";
 
176
  search_bar_->search_hint = default_text;
 
177
}
 
178
 
 
179
void View::Relayout()
 
180
{
 
181
  nux::Geometry geo = GetGeometry();
 
182
  content_geo_ = GetBestFitGeometry(geo);
 
183
  LOG_DEBUG(logger) << "content_geo: " << content_geo_.width << "x" << content_geo_.height;
 
184
 
 
185
  layout_->SetMinimumWidth(content_geo_.width);
 
186
  layout_->SetMaximumWidth(content_geo_.width);
 
187
  layout_->SetMaximumHeight(content_geo_.height);
 
188
  //layout_->SetMinMaxSize(content_geo_.width, content_geo_.height);
 
189
 
 
190
  QueueDraw();
 
191
}
 
192
 
 
193
long View::PostLayoutManagement(long LayoutResult)
 
194
{
 
195
  Relayout();
 
196
  if (GetGeometry().height != last_known_height_)
 
197
  {
 
198
    // Start the timeline of drawing the dash resize
 
199
    if (timeline_need_more_draw_)
 
200
    {
 
201
      // already started, just reset the last known height
 
202
      last_known_height_ = current_height_;
 
203
    }
 
204
   
 
205
    timeline_need_more_draw_ = true;
 
206
    start_time_ = g_get_monotonic_time();
 
207
    QueueDraw();
 
208
  }
 
209
 
 
210
  return LayoutResult;
 
211
}
 
212
 
 
213
 
 
214
nux::View* View::default_focus() const
 
215
{
 
216
  return search_bar_->text_entry();
 
217
}
 
218
 
 
219
void View::SetQueries(Hud::Queries queries)
 
220
{
 
221
  // remove the previous children
 
222
  for (auto button : buttons_)
 
223
  {
 
224
    RemoveChild(button.GetPointer());
 
225
  }
 
226
 
 
227
  selected_button_ = 0;
 
228
  queries_ = queries_;
 
229
  buttons_.clear();
 
230
  button_views_->Clear();
 
231
  int found_items = 0;
 
232
  for (auto query = queries.begin(); query != queries.end(); query++)
 
233
  {
 
234
    if (found_items > 5)
 
235
      break;
 
236
 
 
237
    HudButton::Ptr button(new HudButton());
 
238
    buttons_.push_front(button);
 
239
    button->SetQuery(*query);
 
240
 
 
241
    button_views_->AddView(button.GetPointer(), 0, nux::MINOR_POSITION_LEFT);
 
242
 
 
243
    button->click.connect([&](nux::View* view) {
 
244
      query_activated.emit(dynamic_cast<HudButton*>(view)->GetQuery());
 
245
    });
 
246
 
 
247
    button->key_nav_focus_activate.connect([&](nux::Area *area) {
 
248
      query_activated.emit(dynamic_cast<HudButton*>(area)->GetQuery());
 
249
    });
 
250
 
 
251
    button->key_nav_focus_change.connect([&](nux::Area *area, bool recieving, KeyNavDirection direction){
 
252
      if (recieving)
 
253
        query_selected.emit(dynamic_cast<HudButton*>(area)->GetQuery());
 
254
    });
 
255
 
 
256
    // You should never decrement end().  We should fix this loop.
 
257
    button->is_rounded = (query == --(queries.end())) ? true : false;
 
258
    button->fake_focused = (query == (queries.begin())) ? true : false;
 
259
 
 
260
    button->SetMinimumWidth(941);
 
261
    found_items++;
 
262
  }
 
263
  if (found_items)
 
264
    selected_button_ = 1;
 
265
 
 
266
  QueueRelayout();
 
267
  QueueDraw();
 
268
}
 
269
 
 
270
void View::SetIcon(std::string icon_name)
 
271
{
 
272
  LOG_DEBUG(logger) << "Setting icon to " << icon_name;
 
273
  icon_->SetByIconName(icon_name.c_str(), icon_size);
 
274
  QueueDraw();
 
275
}
 
276
 
 
277
// Gives us the width and height of the contents that will give us the best "fit",
 
278
// which means that the icons/views will not have uneccessary padding, everything will
 
279
// look tight
 
280
nux::Geometry View::GetBestFitGeometry(nux::Geometry const& for_geo)
 
281
{
 
282
  //FIXME - remove magic values, replace with scalable text depending on DPI 
 
283
  // requires smarter font settings really...
 
284
  int width, height = 0;
 
285
  width = 1024;
 
286
  height = 276;
 
287
  
 
288
  LOG_DEBUG (logger) << "best fit is, " << width << ", " << height;
 
289
 
 
290
  return nux::Geometry(0, 0, width, height);
 
291
}
 
292
 
 
293
void View::AboutToShow()
 
294
{
 
295
  renderer_.AboutToShow();
 
296
}
 
297
 
 
298
void View::AboutToHide()
 
299
{
 
300
  renderer_.AboutToHide();
 
301
}
 
302
 
 
303
void View::SetWindowGeometry(nux::Geometry const& absolute_geo, nux::Geometry const& geo)
 
304
{
 
305
  window_geometry_ = geo;
 
306
  window_geometry_.x = 0;
 
307
  window_geometry_.y = 0;
 
308
  absolute_window_geometry_ = absolute_geo;
 
309
}
 
310
 
 
311
namespace
 
312
{
 
313
  const int top_spacing = 9;
 
314
  const int content_width = 941;
 
315
  const int icon_vertical_margin = 5;
 
316
  const int spacing_between_icon_and_content = 8;
 
317
  const int bottom_padding = 10;
 
318
}
 
319
 
 
320
void View::SetupViews()
 
321
{
 
322
  nux::VLayout* super_layout = new nux::VLayout(); 
 
323
  layout_ = new nux::HLayout();
 
324
  { 
 
325
    // fill icon layout with icon
 
326
    icon_ = new Icon("", icon_size, true);
 
327
    nux::Layout* icon_layout = new nux::VLayout();
 
328
    {
 
329
      icon_layout->SetVerticalExternalMargin(icon_vertical_margin);
 
330
      icon_layout->AddView(icon_.GetPointer(), 0, nux::MINOR_POSITION_LEFT, nux::MINOR_SIZE_FULL);
 
331
      layout_->AddLayout(icon_layout, 0, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_MATCHCONTENT);
 
332
    }
 
333
 
 
334
    // add padding to layout between icon and content
 
335
    layout_->AddLayout(new nux::SpaceLayout(spacing_between_icon_and_content,
 
336
                                            spacing_between_icon_and_content,
 
337
                                            spacing_between_icon_and_content,
 
338
                                            spacing_between_icon_and_content), 0);
 
339
    
 
340
    // fill the content layout
 
341
    content_layout_ = new nux::VLayout();
 
342
    {
 
343
      // add the top spacing 
 
344
      content_layout_->AddLayout(new nux::SpaceLayout(top_spacing,top_spacing,top_spacing,top_spacing), 0);
 
345
 
 
346
      // add the search bar to the composite
 
347
      search_bar_ = new unity::SearchBar(content_width, true);
 
348
      search_bar_->disable_glow = true;
 
349
      search_bar_->search_hint = default_text;
 
350
      search_bar_->search_changed.connect(sigc::mem_fun(this, &View::OnSearchChanged));
 
351
      AddChild(search_bar_.GetPointer());
 
352
      content_layout_->AddView(search_bar_.GetPointer(), 0, nux::MINOR_POSITION_LEFT);
 
353
     
 
354
      button_views_ = new nux::VLayout();
 
355
      button_views_->SetMaximumWidth(content_width);
 
356
 
 
357
      content_layout_->AddLayout(button_views_.GetPointer(), 1, nux::MINOR_POSITION_LEFT);
 
358
      content_layout_->AddLayout(new nux::SpaceLayout(bottom_padding,
 
359
                                                      bottom_padding,
 
360
                                                      bottom_padding,
 
361
                                                      bottom_padding), 0);
 
362
    }
 
363
 
 
364
    layout_->AddLayout(content_layout_.GetPointer(), 1, nux::MINOR_POSITION_TOP);
 
365
  }
 
366
  
 
367
  super_layout->AddLayout(layout_.GetPointer(), 0);
 
368
  SetLayout(super_layout);
 
369
}
 
370
 
 
371
void View::OnSearchChanged(std::string const& search_string)
 
372
{
 
373
  LOG_DEBUG(logger) << "got search change";
 
374
  search_changed.emit(search_string);
 
375
  if (search_string.empty())
 
376
  {
 
377
    search_bar_->search_hint = default_text;
 
378
  }
 
379
  else
 
380
  {
 
381
    search_bar_->search_hint = "";
 
382
  }
 
383
}
 
384
 
 
385
 
 
386
void View::OnKeyDown (unsigned long event_type, unsigned long keysym,
 
387
                      unsigned long event_state, const TCHAR* character,
 
388
                      unsigned short key_repeat_count)
 
389
{
 
390
  if (keysym == NUX_VK_ESCAPE)
 
391
  {
 
392
    LOG_DEBUG(logger) << "got escape key";
 
393
    ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
 
394
  }
 
395
}
 
396
 
 
397
void View::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key)
 
398
{
 
399
  if (!content_geo_.IsPointInside(x, y))
 
400
  {
 
401
    ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
 
402
  }
 
403
}
 
404
 
 
405
void View::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
 
406
{
 
407
  if (timeline_need_more_draw_)
 
408
  {
 
409
    ProcessGrowShrink();
 
410
  }
 
411
 
 
412
  nux::Geometry draw_content_geo(layout_->GetGeometry());
 
413
  draw_content_geo.height = current_height_;
 
414
  renderer_.DrawFull(gfx_context, draw_content_geo, absolute_window_geometry_, window_geometry_, true);
 
415
}
 
416
 
 
417
void View::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
 
418
{
 
419
  nux::Geometry draw_content_geo(layout_->GetGeometry());
 
420
  draw_content_geo.height = current_height_;
 
421
 
 
422
  renderer_.DrawInner(gfx_context, draw_content_geo, absolute_window_geometry_, window_geometry_);
 
423
 
 
424
  gfx_context.PushClippingRectangle(draw_content_geo);
 
425
  if (IsFullRedraw())
 
426
  {
 
427
    nux::GetPainter().PushBackgroundStack();
 
428
    GetLayout()->ProcessDraw(gfx_context, force_draw);
 
429
    nux::GetPainter().PopBackgroundStack();
 
430
  }
 
431
  else
 
432
  {
 
433
    GetLayout()->ProcessDraw(gfx_context, force_draw);
 
434
  }
 
435
  gfx_context.PopClippingRectangle();
 
436
 
 
437
  renderer_.DrawInnerCleanup(gfx_context, draw_content_geo, absolute_window_geometry_, window_geometry_);
 
438
 
 
439
  if (timeline_need_more_draw_ && !timeline_id_)
 
440
  {
 
441
    timeline_id_ = g_timeout_add(0, [] (gpointer data) -> gboolean 
 
442
    {
 
443
      View *self = static_cast<View*>(data);
 
444
      self->QueueDraw();
 
445
      self->timeline_id_ = 0;
 
446
      return FALSE;
 
447
    }, this);
 
448
  }
 
449
}
 
450
 
 
451
// Keyboard navigation
 
452
bool View::AcceptKeyNavFocus()
 
453
{
 
454
  return false;
 
455
}
 
456
 
 
457
// Introspectable
 
458
std::string View::GetName() const
 
459
{
 
460
  return "HudView";
 
461
}
 
462
 
 
463
void View::AddProperties(GVariantBuilder* builder)
 
464
{
 
465
  unsigned num_buttons = buttons_.size();
 
466
  variant::BuilderWrapper(builder)
 
467
    .add("selected_button", selected_button_)
 
468
    .add("num_buttons", num_buttons);
 
469
}
 
470
 
 
471
bool View::InspectKeyEvent(unsigned int eventType,
 
472
                           unsigned int key_sym,
 
473
                           const char* character)
 
474
{
 
475
  if ((eventType == nux::NUX_KEYDOWN) && (key_sym == NUX_VK_ESCAPE))
 
476
  {
 
477
    if (search_bar_->search_string == "")
 
478
    {
 
479
      ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
 
480
    }
 
481
    else
 
482
    {
 
483
      search_bar_->search_string = "";
 
484
      search_bar_->search_hint = default_text;
 
485
    }
 
486
    return true;
 
487
  }
 
488
  return false;
 
489
}
 
490
 
 
491
nux::Area* View::FindKeyFocusArea(unsigned int event_type,
 
492
      unsigned long x11_key_code,
 
493
      unsigned long special_keys_state)
 
494
{
 
495
  nux::KeyNavDirection direction = nux::KEY_NAV_NONE;
 
496
  switch (x11_key_code)
 
497
  {
 
498
  case NUX_VK_UP:
 
499
    direction = nux::KEY_NAV_UP;
 
500
    break;
 
501
  case NUX_VK_DOWN:
 
502
    direction = nux::KEY_NAV_DOWN;
 
503
    break;
 
504
  case NUX_VK_LEFT:
 
505
    direction = nux::KEY_NAV_LEFT;
 
506
    break;
 
507
  case NUX_VK_RIGHT:
 
508
    direction = nux::KEY_NAV_RIGHT;
 
509
    break;
 
510
  case NUX_VK_LEFT_TAB:
 
511
    direction = nux::KEY_NAV_TAB_PREVIOUS;
 
512
    break;
 
513
  case NUX_VK_TAB:
 
514
    direction = nux::KEY_NAV_TAB_NEXT;
 
515
    break;
 
516
  case NUX_VK_ENTER:
 
517
  case NUX_KP_ENTER:
 
518
    // Not sure if Enter should be a navigation key
 
519
    direction = nux::KEY_NAV_ENTER;
 
520
    break;
 
521
  default:
 
522
    direction = nux::KEY_NAV_NONE;
 
523
    break;
 
524
  }
 
525
 
 
526
 
 
527
  if ((event_type == nux::NUX_KEYDOWN) && (x11_key_code == NUX_VK_ESCAPE))
 
528
  {
 
529
    // Escape key! This is how it works:
 
530
    //    -If there is text, clear it and give the focus to the text entry view.
 
531
    //    -If there is no text text, then close the hud.
 
532
 
 
533
    if (search_bar_->search_string == "")
 
534
    {
 
535
      search_bar_->search_hint = default_text;
 
536
      ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
 
537
    }
 
538
    else
 
539
    {
 
540
      search_bar_->search_string = "";
 
541
      search_bar_->search_hint = default_text;
 
542
      return search_bar_->text_entry();
 
543
    }
 
544
    return NULL;
 
545
  }
 
546
 
 
547
  if (search_bar_->text_entry()->HasKeyFocus())
 
548
  {
 
549
    if (direction == nux::KEY_NAV_NONE ||
 
550
        direction == nux::KEY_NAV_UP ||
 
551
        direction == nux::KEY_NAV_DOWN ||
 
552
        direction == nux::KEY_NAV_LEFT ||
 
553
        direction == nux::KEY_NAV_RIGHT)
 
554
    {
 
555
      // We have received a key character or a keyboard arrow Up or Down (navigation keys).
 
556
      // Because we have called "SetLoseKeyFocusOnKeyNavDirectionUp(false);" and "SetLoseKeyFocusOnKeyNavDirectionDown(false);"
 
557
      // on the text entry, the text entry will not loose the keyboard focus.
 
558
      // All that we need to do here is set the fake_focused value on the HudButton.
 
559
 
 
560
      if (!buttons_.empty())
 
561
      {
 
562
        if (event_type == nux::NUX_KEYDOWN && direction == nux::KEY_NAV_UP)
 
563
        {
 
564
          std::list<HudButton::Ptr>::iterator it;
 
565
          for(it = buttons_.begin(); it != buttons_.end(); ++it)
 
566
          {
 
567
            if ((*it)->fake_focused)
 
568
            {
 
569
              std::list<HudButton::Ptr>::iterator next = it;
 
570
              ++next;
 
571
              if (next != buttons_.end())
 
572
              {
 
573
                // The button with the current fake_focus looses it.
 
574
                (*it)->fake_focused = false;
 
575
                // The next button gets the fake_focus
 
576
                (*next)->fake_focused = true;
 
577
                query_selected.emit((*next)->GetQuery());
 
578
                --selected_button_;
 
579
              }
 
580
              break;
 
581
            }
 
582
          }
 
583
        }
 
584
 
 
585
        if (event_type == nux::NUX_KEYDOWN && direction == nux::KEY_NAV_DOWN)
 
586
        {
 
587
          std::list<HudButton::Ptr>::reverse_iterator rit;
 
588
          for(rit = buttons_.rbegin(); rit != buttons_.rend(); ++rit)
 
589
          {
 
590
            if ((*rit)->fake_focused)
 
591
            {
 
592
              std::list<HudButton::Ptr>::reverse_iterator next = rit;
 
593
              ++next;
 
594
              if(next != buttons_.rend())
 
595
              {
 
596
                // The button with the current fake_focus looses it.
 
597
                (*rit)->fake_focused = false;
 
598
                // The next button bellow gets the fake_focus.
 
599
                (*next)->fake_focused = true;
 
600
                query_selected.emit((*next)->GetQuery());
 
601
                ++selected_button_;
 
602
              }
 
603
              break;
 
604
            }
 
605
          }
 
606
        }
 
607
      }
 
608
      return search_bar_->text_entry();
 
609
    }
 
610
 
 
611
    if (direction == nux::KEY_NAV_ENTER)
 
612
    {
 
613
      // The "Enter" key has been received and the text entry has the key focus.
 
614
      // If one of the button has the fake_focus, we get it to emit the query_activated signal.
 
615
      if (!buttons_.empty())
 
616
      {
 
617
        std::list<HudButton::Ptr>::iterator it;
 
618
        for(it = buttons_.begin(); it != buttons_.end(); ++it)
 
619
        {
 
620
          if ((*it)->fake_focused)
 
621
          {
 
622
            query_activated.emit((*it)->GetQuery());
 
623
          }
 
624
        }
 
625
      }
 
626
 
 
627
      // We still choose the text_entry as the receiver of the key focus.
 
628
      return search_bar_->text_entry();
 
629
    }
 
630
  }
 
631
  else if (direction == nux::KEY_NAV_NONE)
 
632
  {
 
633
    return search_bar_->text_entry();
 
634
  }
 
635
  else if (next_object_to_key_focus_area_)
 
636
  {
 
637
    return next_object_to_key_focus_area_->FindKeyFocusArea(event_type, x11_key_code, special_keys_state);
 
638
  }
 
639
  return NULL;
 
640
}
 
641
 
 
642
}
 
643
}