~feng-kylin/unity/unityshell-rotated-kylin

« back to all changes in this revision

Viewing changes to launcher/SwitcherModel.cpp

  • Committer: handsome_feng
  • Date: 2015-12-23 01:13:33 UTC
  • mfrom: (3999.2.68 unity)
  • Revision ID: 445865575@qq.com-20151223011333-gm1y3os6xzdzfstb
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2011-2012 Canonical Ltd
 
2
 * Copyright (C) 2011-2015 Canonical Ltd
3
3
 *
4
4
 * This program is free software: you can redistribute it and/or modify
5
5
 * it under the terms of the GNU General Public License version 3 as
14
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
15
 *
16
16
 * Authored by: Jason Smith <jason.smith@canonical.com>
 
17
 *              Marco Trevisan <marco.trevisan@canonical.com>
17
18
 */
18
19
 
19
20
#include <math.h>
28
29
 
29
30
namespace switcher
30
31
{
31
 
 
32
 
 
33
 
SwitcherModel::SwitcherModel(std::vector<AbstractLauncherIcon::Ptr> const& icons)
 
32
namespace
 
33
{
 
34
/**
 
35
 * Helper comparison functor for sorting application icons.
 
36
 */
 
37
bool CompareSwitcherItemsPriority(AbstractLauncherIcon::Ptr const& first,
 
38
                                  AbstractLauncherIcon::Ptr const& second)
 
39
{
 
40
  if (first->GetIconType() == second->GetIconType())
 
41
    return first->SwitcherPriority() > second->SwitcherPriority();
 
42
 
 
43
  if (first->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP)
 
44
    return true;
 
45
 
 
46
  if (second->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP)
 
47
    return false;
 
48
 
 
49
  return first->GetIconType() < second->GetIconType();
 
50
}
 
51
}
 
52
 
 
53
 
 
54
SwitcherModel::SwitcherModel(Applications const& icons, bool sort_by_priority)
34
55
  : detail_selection(false)
35
56
  , detail_selection_index(0)
36
 
  , only_detail_on_viewport(false)
 
57
  , only_apps_on_viewport(true)
37
58
  , applications_(icons)
 
59
  , sort_by_priority_(sort_by_priority)
38
60
  , index_(0)
39
61
  , last_index_(0)
40
62
  , row_index_(0)
41
63
{
42
 
  // When using Webapps, there are more than one active icon, so let's just pick
43
 
  // up the first one found which is the web browser.
44
 
  bool found = false;
45
 
  int order = 0;
46
 
 
 
64
  for (auto it = applications_.begin(); it != applications_.end();)
 
65
  {
 
66
    ConnectToIconSignals(*it);
 
67
 
 
68
    if (!(*it)->ShowInSwitcher(only_apps_on_viewport))
 
69
    {
 
70
      hidden_applications_.push_back(*it);
 
71
      it = applications_.erase(it);
 
72
      continue;
 
73
    }
 
74
 
 
75
    ++it;
 
76
  }
 
77
 
 
78
  if (sort_by_priority_)
 
79
    std::sort(std::begin(applications_), std::end(applications_), CompareSwitcherItemsPriority);
 
80
 
 
81
  UpdateLastActiveApplication();
 
82
 
 
83
  only_apps_on_viewport.changed.connect([this] (bool) {
 
84
    VerifyApplications();
 
85
  });
 
86
 
 
87
  detail_selection.changed.connect([this] (bool) {
 
88
    UpdateDetailXids();
 
89
  });
 
90
}
 
91
 
 
92
void SwitcherModel::UpdateLastActiveApplication()
 
93
{
47
94
  for (auto const& application : applications_)
48
95
  {
49
 
    application->SetOrder(++order);
50
 
 
51
 
    AddChild(application.GetPointer());
52
 
    if (application->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE) && !found)
 
96
    if (application->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE))
53
97
    {
54
98
      last_active_application_ = application;
55
 
      found = true;
56
 
    }
57
 
  }
58
 
}
59
 
 
60
 
SwitcherModel::~SwitcherModel()
61
 
{
62
 
  for (auto const& application : applications_)
63
 
  {
64
 
    RemoveChild(application.GetPointer());
65
 
  }
 
99
      break;
 
100
    }
 
101
  }
 
102
}
 
103
 
 
104
void SwitcherModel::VerifyApplications()
 
105
{
 
106
  bool anything_changed = false;
 
107
 
 
108
  for (auto it = applications_.begin(); it != applications_.end();)
 
109
  {
 
110
    if (!(*it)->ShowInSwitcher(only_apps_on_viewport))
 
111
    {
 
112
      unsigned icon_index = it - applications_.begin();
 
113
      hidden_applications_.push_back(*it);
 
114
      it = applications_.erase(it);
 
115
      anything_changed = true;
 
116
      bool was_in_detail = (detail_selection && icon_index == index_);
 
117
 
 
118
      if (icon_index < index_ || index_ == applications_.size())
 
119
        PrevIndex();
 
120
 
 
121
      if (was_in_detail)
 
122
        UnsetDetailSelection();
 
123
 
 
124
      continue;
 
125
    }
 
126
 
 
127
    ++it;
 
128
  }
 
129
 
 
130
  for (auto it = hidden_applications_.begin(); it != hidden_applications_.end();)
 
131
  {
 
132
    if ((*it)->ShowInSwitcher(only_apps_on_viewport))
 
133
    {
 
134
      InsertIcon(*it);
 
135
      it = hidden_applications_.erase(it);
 
136
      anything_changed = true;
 
137
      continue;
 
138
    }
 
139
 
 
140
    ++it;
 
141
  }
 
142
 
 
143
  if (anything_changed)
 
144
  {
 
145
    if (!last_active_application_ || !last_active_application_->ShowInSwitcher(only_apps_on_viewport))
 
146
      UpdateLastActiveApplication();
 
147
 
 
148
    updated.emit();
 
149
  }
 
150
}
 
151
 
 
152
void SwitcherModel::InsertIcon(AbstractLauncherIcon::Ptr const& application)
 
153
{
 
154
  if (sort_by_priority_)
 
155
  {
 
156
    auto pos = std::upper_bound(applications_.begin(), applications_.end(), application, CompareSwitcherItemsPriority);
 
157
    unsigned icon_index = pos - applications_.begin();
 
158
    applications_.insert(pos, application);
 
159
 
 
160
    if (icon_index <= index_)
 
161
      NextIndex();
 
162
  }
 
163
  else
 
164
  {
 
165
    applications_.push_back(application);
 
166
  }
 
167
}
 
168
 
 
169
void SwitcherModel::ConnectToIconSignals(launcher::AbstractLauncherIcon::Ptr const& icon)
 
170
{
 
171
  icon->quirks_changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &SwitcherModel::OnIconQuirksChanged))));
 
172
  icon->windows_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &SwitcherModel::OnIconWindowsUpdated), icon.GetPointer())));
 
173
}
 
174
 
 
175
void SwitcherModel::AddIcon(AbstractLauncherIcon::Ptr const& icon)
 
176
{
 
177
  if (!icon || icon->GetIconType() != AbstractLauncherIcon::IconType::APPLICATION)
 
178
    return;
 
179
 
 
180
  if (icon->ShowInSwitcher(only_apps_on_viewport))
 
181
  {
 
182
    if (icon->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE))
 
183
      last_active_application_ = icon;
 
184
 
 
185
    if (std::find(applications_.begin(), applications_.end(), icon) == applications_.end())
 
186
    {
 
187
      InsertIcon(icon);
 
188
      ConnectToIconSignals(icon);
 
189
      updated.emit();
 
190
    }
 
191
  }
 
192
  else if (std::find(hidden_applications_.begin(), hidden_applications_.end(), icon) == hidden_applications_.end())
 
193
  {
 
194
    hidden_applications_.push_back(icon);
 
195
    ConnectToIconSignals(icon);
 
196
  }
 
197
}
 
198
 
 
199
void SwitcherModel::RemoveIcon(launcher::AbstractLauncherIcon::Ptr const& icon)
 
200
{
 
201
  auto icon_it = std::find(applications_.begin(), applications_.end(), icon);
 
202
  if (icon_it != applications_.end())
 
203
  {
 
204
    unsigned icon_index = icon_it - applications_.begin();
 
205
    bool was_in_detail = (detail_selection && icon_index == index_);
 
206
    applications_.erase(icon_it);
 
207
 
 
208
    if (last_active_application_ == icon)
 
209
      UpdateLastActiveApplication();
 
210
 
 
211
    if (icon_index < index_ || index_ == applications_.size())
 
212
      PrevIndex();
 
213
 
 
214
    if (was_in_detail)
 
215
      UnsetDetailSelection();
 
216
 
 
217
    updated.emit();
 
218
  }
 
219
  else
 
220
  {
 
221
    hidden_applications_.erase(std::remove(hidden_applications_.begin(), hidden_applications_.end(), icon), hidden_applications_.end());
 
222
  }
 
223
}
 
224
 
 
225
void SwitcherModel::OnIconQuirksChanged()
 
226
{
 
227
  auto old_selection = Selection();
 
228
  VerifyApplications();
 
229
 
 
230
  if (old_selection == last_active_application_)
 
231
    UpdateLastActiveApplication();
 
232
 
 
233
  auto const& new_selection = Selection();
 
234
 
 
235
  if (old_selection != new_selection)
 
236
    selection_changed.emit(new_selection);
 
237
}
 
238
 
 
239
void SwitcherModel::OnIconWindowsUpdated(AbstractLauncherIcon* icon)
 
240
{
 
241
  if (detail_selection() && icon == Selection().GetPointer())
 
242
  {
 
243
    UpdateDetailXids();
 
244
 
 
245
    if (detail_selection_index() >= detail_xids_.size())
 
246
      detail_selection_index = detail_xids_.empty() ? 0 : detail_xids_.size() - 1;
 
247
  }
 
248
 
 
249
  updated.emit();
66
250
}
67
251
 
68
252
std::string SwitcherModel::GetName() const
74
258
{
75
259
  introspection
76
260
  .add("detail-selection", detail_selection)
77
 
  .add("detail-selection-index", (int)detail_selection_index)
78
 
  .add("detail-current-count", DetailXids().size())
79
 
  .add("detail-windows", glib::Variant::FromVector(DetailXids()))
80
 
  .add("only-detail-on-viewport", only_detail_on_viewport)
 
261
  .add("detail-selection-index", detail_selection_index())
 
262
  .add("detail-current-count", SelectionWindows().size())
 
263
  .add("detail-windows", glib::Variant::FromVector(SelectionWindows()))
 
264
  .add("only-apps-on-viewport", only_apps_on_viewport())
81
265
  .add("selection-index", SelectionIndex())
82
266
  .add("last-selection-index", LastSelectionIndex());
83
267
}
84
268
 
 
269
debug::Introspectable::IntrospectableList SwitcherModel::GetIntrospectableChildren()
 
270
{
 
271
  debug::Introspectable::IntrospectableList children;
 
272
  unsigned order = 0;
 
273
 
 
274
  for (auto const& icon : applications_)
 
275
  {
 
276
    if (!icon->ShowInSwitcher(only_apps_on_viewport))
 
277
    {
 
278
      icon->SetOrder(++order);
 
279
      children.push_back(icon.GetPointer());
 
280
    }
 
281
  }
 
282
 
 
283
  return children;
 
284
}
 
285
 
85
286
SwitcherModel::iterator SwitcherModel::begin()
86
287
{
87
288
  return applications_.begin();
104
305
 
105
306
AbstractLauncherIcon::Ptr SwitcherModel::at(unsigned int index) const
106
307
{
107
 
  if ((int) index >= Size ())
 
308
  if (index >= applications_.size())
108
309
    return AbstractLauncherIcon::Ptr();
 
310
 
109
311
  return applications_[index];
110
312
}
111
313
 
112
 
int SwitcherModel::Size() const
 
314
size_t SwitcherModel::Size() const
113
315
{
114
316
  return applications_.size();
115
317
}
139
341
  return last_index_;
140
342
}
141
343
 
142
 
std::vector<Window> SwitcherModel::DetailXids() const
143
 
{
 
344
std::vector<Window> const& SwitcherModel::DetailXids() const
 
345
{
 
346
  return detail_xids_;
 
347
}
 
348
 
 
349
std::vector<Window> SwitcherModel::SelectionWindows() const
 
350
{
 
351
  if (!detail_xids_.empty())
 
352
    return detail_xids_;
 
353
 
144
354
  WindowManager& wm = WindowManager::Default();
145
355
  std::vector<Window> results;
146
356
 
148
358
  {
149
359
    Window xid = window->window_id();
150
360
 
151
 
    if (!only_detail_on_viewport || wm.IsWindowOnCurrentDesktop(xid))
 
361
    if (!only_apps_on_viewport || wm.IsWindowOnCurrentDesktop(xid))
152
362
      results.push_back(xid);
153
363
  }
154
364
 
155
 
  if (results.empty() && detail_selection)
156
 
  {
157
 
    request_detail_hide.emit();
 
365
  if (results.empty())
158
366
    return results;
159
 
  }
160
367
 
161
368
  std::sort(results.begin(), results.end(), [&wm](Window first, Window second) {
162
 
      return wm.GetWindowActiveNumber(first) > wm.GetWindowActiveNumber(second);
 
369
    return wm.GetWindowActiveNumber(first) > wm.GetWindowActiveNumber(second);
163
370
  });
164
371
 
165
 
  if (Selection() == last_active_application_ && results.size() > 1)
 
372
  if (Selection() == last_active_application_)
166
373
  {
167
374
    results.push_back(results.front());
168
375
    results.erase(results.begin());
171
378
  return results;
172
379
}
173
380
 
 
381
void SwitcherModel::UpdateDetailXids()
 
382
{
 
383
  detail_xids_.clear();
 
384
 
 
385
  if (detail_selection)
 
386
    detail_xids_ = SelectionWindows();
 
387
}
 
388
 
174
389
Window SwitcherModel::DetailSelectionWindow() const
175
390
{
176
 
  auto windows = DetailXids();
177
 
  if (!detail_selection || windows.empty())
178
 
    return 0;
179
 
 
180
 
  if (detail_selection_index > windows.size() - 1)
181
 
    return 0;
182
 
 
183
 
  return windows[detail_selection_index];
 
391
  if (!detail_selection || detail_xids_.empty())
 
392
    return 0;
 
393
 
 
394
  if (detail_selection_index > detail_xids_.size() - 1)
 
395
    return 0;
 
396
 
 
397
  return detail_xids_[detail_selection_index];
 
398
}
 
399
 
 
400
void SwitcherModel::UnsetDetailSelection()
 
401
{
 
402
  detail_selection = false;
 
403
  detail_selection_index = 0;
 
404
  row_index_ = 0;
 
405
}
 
406
 
 
407
void SwitcherModel::NextIndex()
 
408
{
 
409
  last_index_ = index_;
 
410
  ++index_ %= applications_.size();
184
411
}
185
412
 
186
413
void SwitcherModel::Next()
187
414
{
 
415
  NextIndex();
 
416
  UnsetDetailSelection();
 
417
  selection_changed.emit(Selection());
 
418
}
 
419
 
 
420
void SwitcherModel::PrevIndex()
 
421
{
188
422
  last_index_ = index_;
189
 
 
190
 
  index_++;
191
 
  if (index_ >= applications_.size())
192
 
    index_ = 0;
193
 
 
194
 
  detail_selection = false;
195
 
  detail_selection_index = 0;
196
 
  row_index_ = 0;
197
 
  selection_changed.emit(Selection());
 
423
  index_ = ((index_ > 0 && index_ < applications_.size()) ? index_ : applications_.size()) - 1;
198
424
}
199
425
 
200
426
void SwitcherModel::Prev()
201
427
{
202
 
  last_index_ = index_;
203
 
 
204
 
  if (index_ > 0)
205
 
    index_--;
206
 
  else
207
 
    index_ = applications_.size() - 1;
208
 
 
209
 
  detail_selection = false;
210
 
  detail_selection_index = 0;
211
 
  row_index_ = 0;
 
428
  PrevIndex();
 
429
  UnsetDetailSelection();
212
430
  selection_changed.emit(Selection());
213
431
}
214
432
 
217
435
  if (!detail_selection())
218
436
    return;
219
437
 
220
 
  if (detail_selection_index < DetailXids().size() - 1)
221
 
    detail_selection_index = detail_selection_index + 1;
222
 
  else
223
 
    detail_selection_index = 0;
224
 
 
 
438
  detail_selection_index = (detail_selection_index + 1) % detail_xids_.size();
225
439
  UpdateRowIndex();
226
440
}
227
441
 
230
444
  if (!detail_selection())
231
445
    return;
232
446
 
233
 
  if (detail_selection_index >= (unsigned int) 1)
234
 
    detail_selection_index = detail_selection_index - 1;
235
 
  else
236
 
    detail_selection_index = DetailXids().size() - 1;
237
 
 
 
447
  detail_selection_index = ((detail_selection_index() > 0) ? detail_selection_index : detail_xids_.size()) - 1;
238
448
  UpdateRowIndex();
239
449
}
240
450
 
253
463
      return;
254
464
    }
255
465
 
256
 
    current_row++;
 
466
    ++current_row;
257
467
  }
258
468
}
259
469
 
289
499
      increment = next_row;
290
500
 
291
501
    detail_selection_index = detail_selection_index + increment;
292
 
    row_index_++;
 
502
    ++row_index_;
293
503
  }
294
504
  else
295
505
  {
296
 
    detail_selection_index = detail_selection_index + 1;
 
506
    detail_selection_index = (detail_selection_index + 1) % detail_xids_.size();
297
507
  }
298
508
}
299
509
 
313
523
  }
314
524
  else
315
525
  {
316
 
    detail_selection_index = detail_selection_index - 1;
 
526
    detail_selection_index = ((detail_selection_index() > 0) ? detail_selection_index : detail_xids_.size()) - 1;
317
527
  }
318
528
}
319
529
 
320
530
bool SwitcherModel::HasNextDetailRow() const
321
531
{
322
 
  return (detail_selection_index < DetailXids().size() - 1);
 
532
  return (detail_selection_index() < detail_xids_.size() - 1);
323
533
}
324
534
 
325
535
bool SwitcherModel::HasPrevDetailRow() const
326
536
{
327
 
  return (detail_selection_index > (unsigned int) 0);
 
537
  return (detail_selection_index() > 0);
328
538
}
329
539
 
330
540
void SwitcherModel::SetRowSizes(std::vector<int> const& row_sizes)
334
544
 
335
545
void SwitcherModel::Select(AbstractLauncherIcon::Ptr const& selection)
336
546
{
337
 
  int i = 0;
 
547
  unsigned i = 0;
338
548
  for (iterator it = begin(), e = end(); it != e; ++it)
339
549
  {
340
550
    if (*it == selection)
341
551
    {
342
 
      if ((int) index_ != i)
 
552
      if (index_ != i)
343
553
      {
344
554
        last_index_ = index_;
345
555
        index_ = i;
346
556
 
347
 
        detail_selection = false;
348
 
        detail_selection_index = 0;
 
557
        UnsetDetailSelection();
349
558
        selection_changed.emit(Selection());
350
559
      }
351
560
      break;
363
572
    last_index_ = index_;
364
573
    index_ = target;
365
574
 
366
 
    detail_selection = false;
367
 
    detail_selection_index = 0;
 
575
    UnsetDetailSelection();
368
576
    selection_changed.emit(Selection());
369
577
  }
370
578
}