def trigger_led_speaker(): global LEDS_LAST_TRIGGER now = time.time() if now - LEDS_LAST_TRIGGER > 3: run_bg('sudo kano-speakerleds initflow 2 4') LEDS_LAST_TRIGGER = now
def error(self, message): self.print_usage() coloured_error, _, _ = run_cmd('colour_echo "{{8 x }} {{7 error: }}"') print "\n " + coloured_error.strip('\n') + message + '\n' run_bg('echo " `colour_echo "' + _('Press {{1 ENTER }} to try again.') + '"`"') raw_input() self.exit(2)
def configure_cpu_monitor_animation(self, checkbox=None): is_ticked = self.cpu_monitor_checkbox.get_active() was_enabled = get_setting('LED-Speaker-anim') if is_ticked and not was_enabled: set_setting('LED-Speaker-anim', is_ticked) run_bg('kano-speakerleds cpu-monitor start', unsudo=True) elif was_enabled and not is_ticked: set_setting('LED-Speaker-anim', is_ticked) run_bg('kano-speakerleds cpu-monitor stop', unsudo=True)
def stop_videos(_button=None): """ Kills all videos that are currently playing # TODO: Stop only videos which are managed by this module """ if omxplayer_present: run_bg("killall omxplayer.bin") else: run_bg("killall vlc")
def stop_videos(_button=None): """ Kills all videos that are currently playing # TODO: Stop only videos which are managed by this module """ if omxplayer_present: run_bg('killall omxplayer.bin') else: run_bg('killall vlc')
def launch_project(app, filename, data_dir, background=False): logger.info('launch_project: {} {} {}'.format(app, filename, data_dir)) app_profiles = read_json(app_profiles_file) fullpath = os.path.join(data_dir, filename) cmd = app_profiles[app]['cmd'].format(fullpath=fullpath, filename=filename) if background: run_bg(cmd) else: _, _, rc = run_print_output_error(cmd) return rc
def save_app_state_with_dialog(app_name, data): logger.debug("save_app_state_with_dialog {}".format(app_name)) old_level, _, old_xp = calculate_kano_level() old_badges = calculate_badges() save_app_state(app_name, data) new_level, _, new_xp = calculate_kano_level() new_badges = calculate_badges() # TODO: This function needs a bit of refactoring in the future # The notifications no longer need to be concatenated to a string # new level new_level_str = '' if old_level != new_level: new_level_str = 'level:{}'.format(new_level) # new items new_items_str = '' badge_changes = compare_badges_dict(old_badges, new_badges) if badge_changes: for category, subcats in badge_changes.iteritems(): for subcat, items in subcats.iteritems(): for item, rules in items.iteritems(): new_items_str += ' {}:{}:{}'.format(category, subcat, item) # Check if XP has changed, if so play sound in the backgrond if old_xp != new_xp: sound_cmd = 'aplay /usr/share/kano-media/sounds/kano_xp.wav > /dev/null 2>&1 &' run_bg(sound_cmd) if not new_level_str and not new_items_str: return if is_gui(): # Open the fifo in append mode, as if it is not # present, notifications are queued in a flat file notifications = (new_level_str + ' ' + new_items_str).split(' ') # Write to both the dashboard and the desktop widget f1 = os.path.join(os.path.expanduser('~'), '.kano-notifications.fifo') f2 = os.path.join(os.path.expanduser('~'), '.kano-notifications-desktop.fifo') write_notifications(f1, notifications) write_notifications(f2, notifications) cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd)
def launch_project(app, filename, data_dir, background=False): # This is necessary to support the new official names # TODO: once the apps have been renamed this will not be necessary name_translation = { 'make-art': 'kano-draw', 'terminal-quest': 'linux-story' } app_tr = name_translation.get(app, app) logger.info("launch_project: {} {} {}".format(app_tr, filename, data_dir)) app_profiles = read_json(app_profiles_file) # XML file with complete pathname fullpath = os.path.join(data_dir, filename) # Prepare the command line to open the app with the new project try: cmd = (app_profiles[app_tr]['cmd'].format(fullpath=fullpath, filename=filename)) except KeyError as exc: logger.warn("Can't find app '{}' in the app profiles - [{}]".format( app_tr, exc)) raise ValueError(_("App '{}' not available").format(app_tr)) # Try to load the project if the app is already running, via a signal. _, _, rc = run_cmd('/usr/bin/kano-signal launch-share {}'.format(fullpath)) if rc: # Likely the app is not running and the signal could not be sent, so start it now logger.warn( "Error sending launch signal, starting the app now, rc={}".format( rc)) if background: # TODO: After migrating to launching apps via systemd, shares for make-snake # stopped launching from KW. Created a special case here to avoid # fixing the make-snake cmd through systemd temporarily. FIX THIS. if app == 'make-snake': run_bg(cmd) else: run_cmd('systemd-run --user {cmd}'.format(cmd=cmd)) else: _, _, rc = run_print_output_error(cmd) return rc else: logger.info("Sent signal to app: {} to open : {}".format( app_tr, fullpath)) return 0
def launch_project(app, filename, data_dir, background=False): # This is necessary to support the new official names # TODO: once the apps have been renamed this will not be necessary name_translation = { 'make-art': 'kano-draw', 'terminal-quest': 'linux-story' } app_tr = name_translation.get(app, app) logger.info("launch_project: {} {} {}".format(app_tr, filename, data_dir)) app_profiles = read_json(app_profiles_file) # XML file with complete pathname fullpath = os.path.join(data_dir, filename) # Prepare the command line to open the app with the new project try: cmd = (app_profiles[app_tr]['cmd'] .format(fullpath=fullpath, filename=filename)) except KeyError as exc: logger.warn( "Can't find app '{}' in the app profiles - [{}]" .format(app_tr, exc) ) raise ValueError(_("App '{}' not available").format(app_tr)) # Try to load the project if the app is already running, via a signal. _, _, rc = run_cmd('/usr/bin/kano-signal launch-share {}'.format(fullpath)) if rc: # Likely the app is not running and the signal could not be sent, so start it now logger.warn("Error sending launch signal, starting the app now, rc={}".format(rc)) if background: # TODO: After migrating to launching apps via systemd, shares for make-snake # stopped launching from KW. Created a special case here to avoid # fixing the make-snake cmd through systemd temporarily. FIX THIS. if app == 'make-snake': run_bg(cmd) else: run_cmd('systemd-run --user {cmd}'.format(cmd=cmd)) else: _, _, rc = run_print_output_error(cmd) return rc else: logger.info("Sent signal to app: {} to open : {}".format(app_tr, fullpath)) return 0
def block_and_sync(): """ Sync the local profile data with kano_world and block until finished """ logger.info('block and sync profile') cmd = '{bin_dir}/kano-sync --sync -s --skip-kdesk'.format(bin_dir=bin_dir) pr = run_bg(cmd) pr.wait()
def block_and_sync(): """ Sync the local profile data with kano_world and block until finished """ logger.info("block and sync profile") cmd = '{bin_dir}/kano-sync --sync -s --skip-kdesk'.format(bin_dir=bin_dir) pr = run_bg(cmd) pr.wait()
def log_in_success(self): '''If the login process is successful, sync with kano world and return success dialog text. ''' logger.info('login successful') # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # restore on first successful login/restore try: first_sync_done = profile['first_sync_done'] except Exception: first_sync_done = False if not first_sync_done: logger.info( "running kano-sync --sync --restore after first time login" ) # When both --sync and --restore are given as options, sync occurs # before the restore cmd = '{bin_dir}/kano-sync --sync -s --restore'.format(bin_dir=bin_dir) run_bg(cmd) save_profile_variable( 'first_sync_done', True, skip_kdesk_refresh=True ) else: logger.info("running kano-sync --sync after non-first login") # sync on each successful login cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) title = _("Success!") description = _("You're in - online features now enabled.") return_value = 'SUCCESS' return (title, description, return_value)
def show_kano_dialog(title, description, buttons, blocking=True): retval = None cmd = 'kano-dialog title="{}" description="{}" buttons="{}" no-taskbar'.format( title, description, buttons) if blocking: _, _, retval = run_cmd(cmd) else: retval = run_bg('exec ' + cmd) return retval
def recreate_char(block=True): """ Recreate the assets for the character from the saved values :param block: (Optional) Set to True to block until the operation has finished :type block: Boolean """ logger.info("recreating character from profile") cmd = '{bin_dir}/kano-character-cli -g'.format(bin_dir=bin_dir) pr = run_bg(cmd) if block: pr.wait()
def save_profile(data): ''' Write profile data to file :param data: JSON serialisable data about the profile ''' logger.debug('save_profile') data.pop('cpu_id', None) data.pop('mac_addr', None) data['save_date'] = get_date_now() ensure_dir(profile_dir) write_json(profile_file, data) if 'SUDO_USER' in os.environ: chown_path(kanoprofile_dir) chown_path(profile_dir) chown_path(profile_file) if os.path.exists('/usr/bin/kdesk') and not is_running('kano-sync'): logger.info('refreshing kdesk from save_profile') run_bg('kdesk -a profile')
def recreate_char(block=True): """ Recreate the assets for the character from the saved values :param block: (Optional) Set to True to block until the operation has finished :type block: Boolean """ logger.info('recreating character from profile') cmd = '{bin_dir}/kano-character-cli -g'.format(bin_dir=bin_dir) pr = run_bg(cmd) if block: pr.wait()
def log_in_success(self): '''If the login process is successful, sync with kano world and return success dialog text. ''' logger.info('login successful') # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # restore on first successful login/restore try: first_sync_done = profile['first_sync_done'] except Exception: first_sync_done = False if not first_sync_done: logger.info('running kano-sync --sync && --sync && --restore after first time login') # doing first sync and restore cmd1 = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) cmd2 = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) cmd3 = '{bin_dir}/kano-sync --restore -s'.format(bin_dir=bin_dir) cmd = "{} && {} && {}".format(cmd1, cmd2, cmd3) run_bg(cmd) save_profile_variable('first_sync_done', True) else: logger.info('running kano-sync --sync after non-first login') # sync on each successful login cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) title = _("Success!") description = _("You're in - online features now enabled.") return_value = "SUCCESS" return (title, description, return_value)
def save_profile(data, skip_kdesk_refresh=False): ''' Write profile data to file :param data: JSON serialisable data about the profile ''' logger.debug('save_profile') data.pop('cpu_id', None) data.pop('mac_addr', None) data['save_date'] = get_date_now() ensure_dir(profile_dir) write_json(profile_file, data) if 'SUDO_USER' in os.environ: chown_path(kanoprofile_dir) chown_path(profile_dir) chown_path(profile_file) if (not skip_kdesk_refresh and os.path.exists('/usr/bin/kdesk') and not is_running('kano-sync')): logger.info("refreshing kdesk from save_profile") run_bg('kdesk -a profile')
def log_in_success(self): '''If the login process is successful, sync with kano world and return success dialog text. ''' logger.info('login successful') # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # restore on first successful login/restore try: first_sync_done = profile['first_sync_done'] except Exception: first_sync_done = False if not first_sync_done: logger.info( "running kano-sync --sync --restore after first time login") # When both --sync and --restore are given as options, sync occurs # before the restore cmd = '{bin_dir}/kano-sync --sync -s --restore'.format( bin_dir=bin_dir) run_bg(cmd) else: logger.info("running kano-sync --sync after non-first login") # sync on each successful login cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) title = _("Success!") description = _("You're in - online features now enabled.") return_value = 'SUCCESS' return (title, description, return_value)
def _launch_shutdown_menu(): """ Launch the shutdown menu when the power button is pressed. """ if not is_enabled.value: return # FIXME: The problem: The poppa menu eventually pops up on a naked PI # with no pihat board connected, right in the middle of Dashboard loading up, # grabbing user input and consequently blocking the user completely. # Solution: prevent the poppa menu from appearing if the Dashboard # has not been running for long enough. if time.time() - startup_timestamp < 20: return # TODO: The env vars bellow are a workaround the fact that Qt5 apps are # stacking on top of each other creating multiple mice, events propagating # below, etc. This hack still leaves a frozen mouse on the screen. self.power_button_pressed() run_bg('systemd-run' ' --setenv=QT_QPA_EGLFS_NO_LIBINPUT=1' ' --setenv=QT_QPA_EVDEV_MOUSE_PARAMETERS=grab=1' ' /usr/bin/shutdown-menu')
def save_app_state_with_dialog(app_name, data): logger.debug('save_app_state_with_dialog {}'.format(app_name)) old_level, _, old_xp = calculate_kano_level() old_badges = calculate_badges() save_app_state(app_name, data) new_level, _, new_xp = calculate_kano_level() new_badges = calculate_badges() # TODO: This function needs a bit of refactoring in the future # The notifications no longer need to be concatenated to a string # new level new_level_str = '' if old_level != new_level: new_level_str = 'level:{}'.format(new_level) # A new level has been reached, update the desktop profile icon if os.path.exists('/usr/bin/kdesk') and not is_running('kano-sync'): logger.info('refreshing kdesk due to new experience level') run_bg('kdesk -a profile') # new items new_items_str = '' badge_changes = compare_badges_dict(old_badges, new_badges) if badge_changes: for category, subcats in badge_changes.iteritems(): for subcat, items in subcats.iteritems(): for item, rules in items.iteritems(): new_items_str += ' {}:{}:{}'.format(category, subcat, item) # Check if XP has changed, if so play sound in the backgrond if old_xp != new_xp: sound_cmd = 'aplay /usr/share/kano-media/sounds/kano_xp.wav > /dev/null 2>&1 &' run_bg(sound_cmd) if not new_level_str and not new_items_str: return if is_gui(): fifo = open( os.path.join(os.path.expanduser('~'), '.kano-notifications.fifo'), 'w' ) with fifo: for notification in (new_level_str + ' ' + new_items_str).split(' '): if len(notification) > 0: logger.debug( "Showing the {} notification".format(notification) ) fifo.write('{}\n'.format(notification)) cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd)
def launch_chromium(*args): user_name = get_user_unsudoed() arguments = ''.join(*args) run_bg('su - ' + user_name + ' -c "chromium {}"'.format(arguments))
def refresh_resolvconf(): run_bg('resolvconf -u')
def register_user_with_gui(self): self.data_screen.cache_emails() self.data_screen.cache_marketing_choice() self.page_control.disable_buttons() self.data_screen.disable_all() self.get_email_data() # Make cursor into a spinner watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH) self.win.get_window().set_cursor(watch_cursor) # This means no threads are needed. while Gtk.events_pending(): Gtk.main_iteration() # Try and register the account on the server email = self.win.data["email"] secondary_email = self.win.data["secondary_email"] username = self.win.data["username"] password = self.win.data["password"] date_year = self.win.data["year"] date_month = self.win.data["month"] date_day = self.win.data["day"] marketing_enabled = self.win.data["marketing_enabled"] logger.info('trying to register user with data {} {} {} {} {} {} {} {}' .format( email, secondary_email, username, password, date_year, date_month, date_day, marketing_enabled ) ) success, text = register_(email, username, password, date_year, date_month, date_day, secondary_email=secondary_email, marketing_enabled=marketing_enabled) # This should no longer be needed, since this is checked in the first screen. # However there is a small chance someone could take the username # while the user is in the process of registering if not success: if text.strip() == "Cannot register, problem: Username already registered": logger.info('username invalid - getting second username') self.collect_new_username() return else: logger.info('problem with registration: {}'.format(text)) return_value = "FAIL" self.create_dialog( title=_("Houston, we have a problem"), description=str(text) ) track_data('world-registration-failed', {'reason': text}) else: logger.info('registration successful') bday_date = str(datetime.date(date_year, date_month, date_day)) save_profile_variable('birthdate', bday_date) # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info('running kano-sync after successful registration') cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = "SUCCEED" self.create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.") ) self.page_control.enable_buttons() self.data_screen.enable_all() self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == "SUCCEED": Gtk.main_quit()
def launch_midori(*args): user_name = get_user_unsudoed() arguments=''.join(*args) run_bg('su - ' + user_name + ' -c "midori {}"'.format(arguments))
def launch_chromium(*args): user_name = get_user_unsudoed() arguments=''.join(*args) run_bg('su - ' + user_name + ' -c "chromium {}"'.format(arguments))
def sync_profile(): """ Sync the local profile data with kano_world, without blocking """ logger.info('sync_profile') cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd)
def refresh_resolvconf(): run_bg("resolvconf -u")
def _on_register_button(self, widget=None): # TODO: refactor this """ """ if not is_internet(): self._show_not_internet_dialog() return # Get the username, password and birthday data = self.data_screen.get_widget_data() email = data['email'] username = data['username'] # Validate that the email address format is correct email_error = validate_email(email) if email_error: self._show_error_dialog(_("Incorrect Email address"), email_error) return if not self._is_username_available(username): self._show_username_taken_dialog(username) return # We can save the username to kano-profile # Don't save password as this is private self.data_screen.save_username_and_birthday() # TODO: rename this self.data_screen.cache_emails() data = self.data_screen.get_widget_data() # This means no threads are needed. while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() # Try and register the account on the server password = data['password'] success, text = register_(email, username, password, marketing_enabled=True) # This should no longer be needed, since this is checked in the first # screen. However there is a small chance someone could take the # username while the user is in the process of registering if not success: if text.strip() == _("Cannot register, problem: " "Username already registered"): self._show_username_taken_dialog(username) else: logger.info("problem with registration: {}".format(text)) return_value = 'FAIL' self._create_dialog(title=_("Houston, we have a problem"), description=str(text)) track_data('world-registration-failed', {'reason': text}) else: logger.info("registration successful") # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info("running kano-sync after successful registration") cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = 'SUCCEED' self._create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.")) self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == 'SUCCEED': Gtk.main_quit()
def launch_chromium(*args): user_name = get_user_unsudoed() run_bg('su - ' + user_name + ' -c chromium')
def _on_register_button(self, widget=None): # TODO: refactor this """ """ if not is_internet(): self._show_not_internet_dialog() return # Get the username, password and birthday data = self.data_screen.get_widget_data() email = data['email'] username = data['username'] # Validate that the email address format is correct email_error = validate_email(email) if email_error: self._show_error_dialog(_("Incorrect Email address"), email_error) return if not self._is_username_available(username): self._show_username_taken_dialog(username) return # We can save the username to kano-profile # Don't save password as this is private self.data_screen.save_username_and_birthday() # TODO: rename this self.data_screen.cache_emails() data = self.data_screen.get_widget_data() # This means no threads are needed. while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() # Try and register the account on the server password = data['password'] success, text = register_(email, username, password, marketing_enabled=True) # This should no longer be needed, since this is checked in the first # screen. However there is a small chance someone could take the # username while the user is in the process of registering if not success: if text.strip() == _("Cannot register, problem: " "Username already registered"): self._show_username_taken_dialog(username) else: logger.info("problem with registration: {}".format(text)) return_value = 'FAIL' self._create_dialog( title=_("Houston, we have a problem"), description=str(text) ) track_data('world-registration-failed', {'reason': text}) else: logger.info("registration successful") # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info("running kano-sync after successful registration") cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = 'SUCCEED' self._create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.") ) self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == 'SUCCEED': Gtk.main_quit()
def launch_midori(*args): user_name = get_user_unsudoed() arguments = ''.join(*args) run_bg('su - ' + user_name + ' -c "midori {}"'.format(arguments))
def sync_profile(): """ Sync the local profile data with kano_world, without blocking """ logger.info("sync_profile") cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd)