1
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2
# Copyright 2012 Canonical
3
# Author: Thomi Richards
5
# This program is free software: you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License version 3, as published
7
# by the Free Software Foundation.
11
from time import sleep
13
from autopilot.keybindings import KeybindingsHelper
14
from autopilot.emulators.unity import UnityIntrospectionObject
15
from autopilot.emulators.unity.icons import BamfLauncherIcon, SimpleLauncherIcon
16
from autopilot.emulators.X11 import Mouse, ScreenGeometry
19
logger = logging.getLogger(__name__)
22
class LauncherController(UnityIntrospectionObject):
23
"""The LauncherController class."""
25
def get_launcher_for_monitor(self, monitor_num):
26
"""Return an instance of Launcher for the specified monitor, or None."""
27
launchers = self.get_children_by_type(Launcher, monitor=monitor_num)
28
return launchers[0] if launchers else None
32
"""Return the launcher model."""
33
models = LauncherModel.get_all_instances()
34
assert(len(models) == 1)
37
def key_nav_monitor(self):
38
return self.key_nav_launcher_monitor
41
class Launcher(UnityIntrospectionObject, KeybindingsHelper):
42
"""An individual launcher for a monitor."""
44
def __init__(self, *args, **kwargs):
45
super(Launcher, self).__init__(*args, **kwargs)
49
self.in_keynav_mode = False
50
self.in_switcher_mode = False
53
self._screen = ScreenGeometry()
55
def move_mouse_to_right_of_launcher(self):
56
"""Places the mouse to the right of this launcher."""
57
self._screen.move_mouse_to_monitor(self.monitor)
58
(x, y, w, h) = self.geometry
62
logger.debug("Moving mouse away from launcher.")
63
self._mouse.move(target_x, target_y, False)
64
sleep(self.show_timeout)
66
def move_mouse_over_launcher(self):
67
"""Move the mouse over this launcher."""
68
self._screen.move_mouse_to_monitor(self.monitor)
69
(x, y, w, h) = self.geometry
73
logger.debug("Moving mouse to center of launcher.")
74
self._mouse.move(target_x, target_y)
76
def reveal_launcher(self):
77
"""Reveal this launcher with the mouse."""
78
self._screen.move_mouse_to_monitor(self.monitor)
79
(x, y, w, h) = self.geometry
81
logger.debug("Revealing launcher on monitor %d with mouse.", self.monitor)
82
self._mouse.move(x - 920, y + h / 2, True, 5, .002)
83
sleep(self.show_timeout)
85
def keyboard_reveal_launcher(self):
86
"""Reveal this launcher using the keyboard."""
87
self._screen.move_mouse_to_monitor(self.monitor)
88
logger.debug("Revealing launcher with keyboard.")
89
self.keybinding_hold("launcher/reveal")
92
def keyboard_unreveal_launcher(self):
93
"""Un-reveal this launcher using the keyboard."""
94
self._screen.move_mouse_to_monitor(self.monitor)
95
logger.debug("Un-revealing launcher with keyboard.")
96
self.keybinding_release("launcher/reveal")
99
def key_nav_start(self):
100
"""Start keyboard navigation mode by pressing Alt+F1."""
101
self._screen.move_mouse_to_monitor(self.monitor)
102
logger.debug("Initiating launcher keyboard navigation with Alt+F1.")
103
self.keybinding("launcher/keynav")
104
self.in_keynav_mode = True
106
def key_nav_end(self, cancel):
107
"""End the key navigation.
109
If cancel is True, the currently selected icon will not be activated.
112
if not self.in_keynav_mode:
113
raise RuntimeError("Cannot end the key navigation when not in kaynav mode.")
115
logger.debug("Cancelling keyboard navigation mode.")
116
self.keybinding("launcher/keynav/exit")
118
logger.debug("Ending keyboard navigation mode, activating icon.")
119
self.keybinding("launcher/keynav/activate")
121
self.in_keynav_mode = False
123
def key_nav_next(self):
124
if not self.in_keynav_mode:
125
raise RuntimeError("Cannot use the key navigation commands when not in kaynav mode.")
126
logger.debug("Selecting next item in keyboard navigation mode.")
127
self.keybinding("launcher/keynav/next")
129
def key_nav_prev(self):
130
if not self.in_keynav_mode:
131
raise RuntimeError("Cannot use the key navigation commands when not in kaynav mode.")
132
logger.debug("Selecting previous item in keyboard navigation mode.")
133
self.keybinding("launcher/keynav/prev")
135
def key_nav_enter_quicklist(self):
136
if not self.in_keynav_mode:
137
raise RuntimeError("Cannot open switcher quicklist while not in keynav mode.")
138
logger.debug("Opening quicklist for currently selected icon.")
139
self.keybinding("launcher/keynav/open-quicklist")
141
def key_nav_exit_quicklist(self):
142
if not self.in_keynav_mode:
143
raise RuntimeError("Cannot close switcher quicklist while not in keynav mode.")
144
logger.debug("Closing quicklist for currently selected icon.")
145
self.keybinding("launcher/keynav/close-quicklist")
147
def switcher_start(self):
148
"""Start the super+Tab switcher on this launcher."""
149
self._screen.move_mouse_to_monitor(self.monitor)
150
logger.debug("Starting Super+Tab switcher.")
151
self.keybinding_hold("launcher/switcher")
152
self.keybinding_tap("launcher/switcher")
153
self.in_switcher_mode = True
155
def switcher_end(self, cancel):
156
"""End the super+tab swithcer.
158
If cancel is True, the currently selected icon will not be activated.
161
if not self.in_switcher_mode:
162
raise RuntimeError("Cannot end the launcher switcher when not in switcher mode.")
165
logger.debug("Cancelling keyboard navigation mode.")
166
self.keybinding("launcher/switcher/exit")
167
self.keybinding_release("launcher/switcher")
169
logger.debug("Ending keyboard navigation mode.")
170
self.keybinding_release("launcher/switcher")
172
self.in_switcher_mode = False
174
def switcher_next(self):
175
if not self.in_switcher_mode:
176
raise RuntimeError("Cannot use the launcher switcher commands when not in switcher mode.")
177
logger.debug("Selecting next item in keyboard navigation mode.")
178
self.keybinding("launcher/switcher/next")
180
def switcher_prev(self):
181
if not self.in_switcher_mode:
182
raise RuntimeError("Cannot use the launcher switcher commands when not in switcher mode.")
183
logger.debug("Selecting previous item in keyboard navigation mode.")
184
self.keybinding("launcher/switcher/prev")
186
def switcher_up(self):
187
if not self.in_switcher_mode:
188
raise RuntimeError("Cannot use the launcher switcher commands when not in switcher mode.")
189
logger.debug("Selecting next item in keyboard navigation mode.")
190
self.keybinding("launcher/switcher/up")
192
def switcher_down(self):
193
if not self.in_switcher_mode:
194
raise RuntimeError("Cannot use the launcher switcher commands when not in switcher mode.")
195
logger.debug("Selecting previous item in keyboard navigation mode.")
196
self.keybinding("launcher/switcher/down")
198
def click_launcher_icon(self, icon, button=1):
199
"""Move the mouse over the launcher icon, and click it.
201
`icon` must be an instance of SimpleLauncherIcon or it's descendants.
204
if not isinstance(icon, SimpleLauncherIcon):
205
raise TypeError("icon must be a LauncherIcon")
206
logger.debug("Clicking launcher icon %r on monitor %d with mouse button %d",
207
icon, self.monitor, button)
208
self.reveal_launcher()
209
target_x = icon.x + self.x
210
target_y = icon.y + (self.icon_size / 2)
211
self._mouse.move(target_x, target_y )
212
self._mouse.click(button)
213
self.move_mouse_to_right_of_launcher()
215
def lock_to_launcher(self, icon):
216
"""lock 'icon' to the launcher, if it's not already.
218
`icon` must be an instance of BamfLauncherIcon.
221
if not isinstance(icon, BamfLauncherIcon):
222
raise TypeError("Can only lock instances of BamfLauncherIcon")
227
logger.debug("Locking icon %r to launcher.", icon)
228
self.click_launcher_icon(icon, button=3)
229
quicklist = icon.get_quicklist()
230
pin_item = quicklist.get_quicklist_item_by_text('Lock to Launcher')
231
quicklist.click_item(pin_item)
233
def unlock_from_launcher(self, icon):
234
"""lock 'icon' to the launcher, if it's not already.
236
`icon` must be an instance of BamfLauncherIcon.
239
if not isinstance(icon, BamfLauncherIcon):
240
raise TypeError("Can only unlock instances of BamfLauncherIcon")
245
logger.debug("Unlocking icon %r from launcher.")
246
self.click_launcher_icon(icon, button=3)
247
quicklist = icon.get_quicklist()
248
pin_item = quicklist.get_quicklist_item_by_text('Unlock from Launcher')
249
quicklist.click_item(pin_item)
251
def is_quicklist_open(self):
252
return self.quicklist_open
254
def is_showing(self):
255
return not self.hidden
257
def are_shortcuts_showing(self):
258
return self.shortcuts_shown
262
"""Returns a tuple of (x,y,w,h) for the current launcher."""
263
return (self.x, self.y, self.width, self.height)
266
class LauncherModel(UnityIntrospectionObject):
267
"""THe launcher model. Contains all launcher icons as children."""
269
def get_launcher_icons(self, visible_only=True):
270
"""Get a list of launcher icons in this launcher."""
272
return self.get_children_by_type(SimpleLauncherIcon, quirk_visible=True)
274
return self.get_children_by_type(SimpleLauncherIcon)
276
def get_icon_by_tooltip_text(self, tooltip_text):
277
"""Get a launcher icon given it's tooltip text.
279
Returns None if there is no icon with the specified text.
281
for icon in self.get_launcher_icons():
282
if icon.tooltip_text == tooltip_text:
286
def get_icon_by_desktop_file(self, desktop_file):
287
"""Gets a launcher icon with the specified desktop file.
289
Returns None if there is no such launcher icon.
291
icons = self.get_children_by_type(SimpleLauncherIcon, desktop_file=desktop_file)
294
def num_launcher_icons(self):
295
"""Get the number of icons in the launcher model."""
296
return len(self.get_launcher_icons())