diff --git a/debian/control b/debian/control index fbcfe50..4683d09 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,8 @@ Package: kano-desktop Architecture: all Depends: ${misc:Depends}, openbox (>=3.5.2-4~kano.1), kdesk (>=1.1-02), chromium, kano-themes, lxmenu-data (>=0.1.2-3~kano), - kano-video-files, kano-init-flow (>=1.2.2-1), kano-profile (>=1.2-3), libkdesk-dev + kano-video-files, kano-init-flow (>=1.2.2-1), kano-profile (>=1.2-3), + libkdesk-dev, gir1.2-lightdm-1 Replaces: kano-settings (<< 1.1-1.20140512build2), kano-feedback (<< 1.1-3) Breaks: kano-settings (<< 1.1-1.20140512build2), kano-feedback (<< 1.1-3) Description: The desktop experience of Kanux diff --git a/debian/install b/debian/install index c2311cc..e94bcdd 100644 --- a/debian/install +++ b/debian/install @@ -1,10 +1,14 @@ wallpapers usr/share/kano-desktop icons usr/share/kano-desktop images usr/share/kano-desktop -lightdm usr/share/kano-desktop kdesk usr/share/kano-desktop +kdesk/.kdeskrc var/lib/lightdm Legal usr/share/kano-desktop +kano-greeter/kano-greeter.py usr/share/kano-desktop/kano-greeter +kano-greeter/kano-greeter.css usr/share/kano-desktop/kano-greeter +kano-greeter/kano-greeter.desktop usr/share/xgreeters + config/autostart usr/share/kano-desktop/config config/chromium usr/share/kano-desktop/config config/keyboard/kanokeyboardrc usr/share/kano-desktop/config/keyboard diff --git a/debian/postinst b/debian/postinst index 2bcc183..567ac49 100644 --- a/debian/postinst +++ b/debian/postinst @@ -6,14 +6,12 @@ # License: http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 # -lightdm_greeter_config=/etc/lightdm/lightdm-gtk-greeter.conf -custom_lightdm_greeter_config=/usr/share/kano-desktop/lightdm/lightdm-gtk-greeter.conf - openbox_rc=/etc/xdg/openbox/rc.xml lxde_openbox_rc=/etc/xdg/openbox/LXDE/rc.xml custom_openbox_rc=/usr/share/kano-desktop/openbox/rc.xml lightdm_config=/etc/lightdm/lightdm.conf +lightdm_kdeskrc=/var/lib/lightdm/.kdeskrc chromium_master_prefs=/etc/chromium/master_preferences custom_chromium_master_prefs=/usr/share/kano-desktop/config/chromium/master_preferences @@ -73,37 +71,20 @@ case "$1" in cp $lxde_openbox_rc $lxde_openbox_rc-old cat $custom_openbox_rc > $lxde_openbox_rc - # Configure lightdm - cp $lightdm_greeter_config $lightdm_greeter_config-old - cat $custom_lightdm_greeter_config > $lightdm_greeter_config - - # Display a list of user names when logging in - sed -i 's/#\?\s*\(greeter-hide-users\=\).*/\1false/' "$lightdm_config" - sed -i 's/^\s*\(user-session\=\).*/# \1default/' "$lightdm_config" - - # Remove all but our default Ligtdhm Xsession from the Greeter login dialog - # these are displayed under the password field, in a drop down list - dir_xsession=/usr/share/xsessions - dir_xsession_disabled=/usr/share/xsessions/disabled - if [ ! -d $dir_xsession_disabled ]; then - mkdir -p $dir_xsession_disabled - fi + ### Configure lightdm ### - if [ -f $dir_xsession/LXDE.desktop ]; then - mv $dir_xsession/LXDE.desktop $dir_xsession_disabled - fi + # Switch to use the Kano Greeter + sed -i 's/^\s*\(greeter-session\=\).*/\1kano-greeter/' "$lightdm_config" - if [ -f $dir_xsession/openbox-gnome.desktop ]; then - mv $dir_xsession/openbox-gnome.desktop $dir_xsession_disabled - fi + # Create bin link to the Kano Greeter + ln -s /usr/share/kano-desktop/kano-greeter/kano-greeter.py /usr/bin/kano-greeter - if [ -f $dir_xsession/openbox-kde.desktop ]; then - mv $dir_xsession/openbox-kde.desktop $dir_xsession_disabled - fi + # Change the Kano Greeter backgrounds + # For now these are identical to every other user's default but will be different in the future + # sed -i 's|^\(\s*Background.File-medium:\s\).*|\1/usr/share/kano-desktop/wallpapers/kanux-background-1024.png|' "$lightdm_kdeskrc" + # sed -i 's|^\(\s*Background.File-4-3:\s\).*|\1/usr/share/kano-desktop/wallpapers/kanux-background-4-3.png|' "$lightdm_kdeskrc" + # sed -i 's|^\(\s*Background.File-16-9:\s\).*|\1/usr/share/kano-desktop/wallpapers/kanux-background-16-9.png|' "$lightdm_kdeskrc" - if [ -f $dir_xsession/openbox.desktop ]; then - mv $dir_xsession/openbox.desktop $dir_xsession_disabled - fi # Configure chromium cp $chromium_master_prefs $chromium_master_prefs-old diff --git a/debian/postrm b/debian/postrm index cad8fa4..ced3cb7 100644 --- a/debian/postrm +++ b/debian/postrm @@ -9,7 +9,6 @@ openbox_rc=/etc/xdg/openbox/rc.xml lxde_openbox_rc=/etc/xdg/openbox/LXDE/rc.xml -lightdm_greeter_config=/etc/lightdm/lightdm_gtk_greeter.conf lightdm_config=/etc/lightdm/lightdm.conf chromium_master_prefs=/etc/chromium/master_preferences @@ -34,14 +33,8 @@ case "$1" in mv $lxde_openbox_rc-old $lxde_openbox_rc fi - # Revert old lightdm greeter config - if [ -e "$lightdm_greeter_config-old" ]; then - mv $lightdm_greeter_config-old $lightdm_greeter_config - fi - - # Don't isplay a list of user names when logging in - sed -i 's/#\?\s*\(greeter-hide-users\=\).*/\1true/' "$lightdm_config" - sed -i 's/#\?\s*\(user-session\=\).*/\1default/' "$lightdm_config" + # Revert to the default greeter + sed -i 's/^\s*\(greeter-session\=\).*/\1lightdm-greeter/' "$lightdm_config" # Removing links rm -f /etc/skel/.config/pcmanfm @@ -50,6 +43,7 @@ case "$1" in rm -f /etc/skel/.config/lxterminal rm -f /etc/skel/.config/lxsession rm -rf /etc/skel/Legal + rm -f /usr/bin/kano-greeter # Revert chromium config if [ -e "$chromium_bookmarks-old" ]; then diff --git a/kano-greeter/kano-greeter.css b/kano-greeter/kano-greeter.css new file mode 100644 index 0000000..6d286c1 --- /dev/null +++ b/kano-greeter/kano-greeter.css @@ -0,0 +1,21 @@ +GtkLabel { + font: Bariol 18; + font-weight: bold; +} + +GtkEventBox.user { + background: @kano_orange; + border-width: 3px; + border-radius:3px; + padding: 12px; +} + +GtkEventBox.user GtkLabel { + color: #ffffff; +} + +GtkEventBox.user.hover { + background: @kano_orange_lighter; + border-color: @active_border; + border-style: solid; +} diff --git a/kano-greeter/kano-greeter.desktop b/kano-greeter/kano-greeter.desktop new file mode 100644 index 0000000..766ff61 --- /dev/null +++ b/kano-greeter/kano-greeter.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=Kano Greeter +Comment=Kano greeter +Exec=kano-greeter +Type=Application diff --git a/kano-greeter/kano-greeter.py b/kano-greeter/kano-greeter.py new file mode 100755 index 0000000..1dc68f1 --- /dev/null +++ b/kano-greeter/kano-greeter.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python + +# kano-greeter.py +# +# Copyright (C) 2014 Kano Computing Ltd. +# License: http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 +# +# + +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import LightDM +import os + +from kano.logging import logger +from kano.gtk3.apply_styles import apply_common_to_screen, \ + apply_styling_to_screen +from kano.gtk3.top_bar import TopBar +from kano.gtk3.buttons import KanoButton +from kano.gtk3.heading import Heading +from kano.gtk3.application_window import ApplicationWindow +from kano.gtk3.kano_dialog import KanoDialog +from kano.gtk3.buttons import OrangeButton + + +class GreeterWindow(ApplicationWindow): + WIDTH = 400 + HEIGHT = -1 + + def __init__(self): + apply_common_to_screen() + + ApplicationWindow.__init__(self, 'Login', self.WIDTH, self.HEIGHT) + self.connect("delete-event", Gtk.main_quit) + + self.grid = Gtk.Grid() + self.set_main_widget(self.grid) + + self.grid.set_column_spacing(30) + self.grid.set_row_spacing(30) + + self.top_bar = TopBar('Login') + self._remove_top_bar_buttons() + self.top_bar.set_size_request(self.WIDTH, -1) + self.grid.attach(self.top_bar, 0, 0, 3, 1) + + self.shutdown_btn = OrangeButton('Shutdown') + self.shutdown_btn.connect('clicked', self.shutdown) + align = Gtk.Alignment(xalign=1.0, + xscale=0.0) + align.add(self.shutdown_btn) + self.grid.attach(align, 1, 2, 1, 1) + + self.grid.attach(Gtk.Label(), 0, 3, 3, 1) + + self.top_bar.set_prev_callback(self._back_cb) + + self.user_list = UserList() + + self.go_to_users() + + cursor = Gdk.Cursor.new(Gdk.CursorType.ARROW) + self.get_root_window().set_cursor(cursor) + + def _remove_top_bar_buttons(self): + self.top_bar.box.remove(self.top_bar.close_button) + self.top_bar.box.remove(self.top_bar.next_button) + + def set_main(self, wdg): + child = self.grid.get_child_at(1, 1) + if child: + self.grid.remove(child) + + self.grid.attach(wdg, 1, 1, 1, 1) + self.show_all() + + def go_to_users(self): + self.set_main(self.user_list) + self.top_bar.disable_prev() + + def go_to_password(self, user): + password_view = PasswordView(user) + self.set_main(password_view) + self.top_bar.enable_prev() + + def _back_cb(self, event, button): + self.go_to_users() + + def shutdown(self, *_): + confirm = KanoDialog(title_text='Are you sure you want to shut down?', + button_dict={ + 'OK': {'return_value': True}, + 'CANCEL': {'return_value': False} + }) + confirm.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS) + if confirm.run(): + LightDM.shutdown() + + +class UserList(Gtk.ScrolledWindow): + HEIGHT = 250 + WIDTH = 250 + + def __init__(self): + Gtk.ScrolledWindow.__init__(self) + + self.set_size_request(self.WIDTH, self.HEIGHT) + + self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.box.set_spacing(10) + self.add(self.box) + + title = Heading('Select Account', 'Log in to which account?') + self.box.pack_start(title.container, False, False, 0) + + self._populate() + + def _populate(self): + # Populate list + user_list = LightDM.UserList() + for user in user_list.get_users(): + logger.debug('adding user {}'.format(user.get_name())) + self.add_item(user.get_name()) + + def add_item(self, username): + user = User(username) + self.box.pack_start(user, False, False, 0) + + +class User(Gtk.EventBox): + HEIGHT = 50 + + def __init__(self, username): + Gtk.EventBox.__init__(self) + self.set_size_request(-1, self.HEIGHT) + + self.username = username + + self.get_style_context().add_class('user') + + label = Gtk.Label(username.title()) + self.add(label) + + self.connect('button-release-event', self._user_select_cb) + self.connect('enter-notify-event', self._hover_cb) + self.connect('leave-notify-event', self._unhover_cb) + + def _user_select_cb(self, button, event): + logger.debug('user {} selected'.format(self.username)) + + win = self.get_toplevel() + win.go_to_password(self.username) + + def _hover_cb(self, widget, event): + self.get_style_context().add_class('hover') + + def _unhover_cb(self, widget, event): + self.get_style_context().remove_class('hover') + + +class PasswordView(Gtk.Grid): + greeter = LightDM.Greeter() + + def __init__(self, user): + Gtk.Grid.__init__(self) + + self.get_style_context().add_class('password') + self.set_row_spacing(10) + + self._reset_greeter() + + self.user = user + title = Heading('Enter your password', + 'If you haven\'t changed your password,\n' + 'use "kano"') + self.attach(title.container, 0, 0, 1, 1) + self.password = Gtk.Entry() + self.password.set_visibility(False) + self.password.set_alignment(0.5) + self.password.connect('activate', self._login_cb) + self.attach(self.password, 0, 1, 1, 1) + + self.login_btn = KanoButton('LOGIN') + self.login_btn.connect('button-release-event', self._login_cb) + self.attach(self.login_btn, 0, 2, 1, 1) + + def _reset_greeter(self): + PasswordView.greeter = PasswordView.greeter.new() + PasswordView.greeter.connect_sync() + + # connect signal handlers to LightDM + PasswordView.greeter.connect('show-prompt', self._send_password_cb) + PasswordView.greeter.connect('authentication-complete', + self._authentication_complete_cb) + PasswordView.greeter.connect('show-message', self._auth_error_cb) + + def _login_cb(self, event=None, button=None): + logger.debug('Sending username to LightDM') + + self.login_btn.start_spinner() + PasswordView.greeter.authenticate(self.user) + + if PasswordView.greeter.get_is_authenticated(): + logger.debug('User is already authenticated, starting session') + start_session() + + def _send_password_cb(self, _greeter, text, prompt_type): + logger.debug('Need to show prompt: {}'.format(text)) + if _greeter.get_in_authentication(): + logger.debug('Sending password to LightDM') + _greeter.respond(self.password.get_text()) + + def _authentication_complete_cb(self, _greeter): + logger.debug('Authentication process is complete') + + if not _greeter.get_is_authenticated(): + logger.warn('Could not authenticate user {}'.format(self.user)) + self._auth_error_cb('Incorrect password (The default is "kano")') + + return + + logger.info( + 'The user {} is authenticated. Starting LightDM X Session' + .format(self.user)) + + if not _greeter.start_session_sync('lightdm-xsession'): + logger.error('Failed to start session') + else: + logger.info('Login failed') + + def _auth_error_cb(self, text, message_type=None): + logger.info('There was an error logging in: {}'.format(text)) + + win = self.get_toplevel() + win.go_to_users() + + error = KanoDialog(title_text='Error Logging In', + description_text=text, + parent_window=self.get_toplevel()) + error.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS) + error.run() + + +if __name__ == '__main__': + try: + # Refresh the wallpaper + os.system('kdesk -w') + + apply_styling_to_screen( + '/usr/share/kano-desktop/kano-greeter/kano-greeter.css') + + WIN = GreeterWindow() + WIN.show_all() + + Gtk.main() + except Exception as e: + logger.error(e) diff --git a/lightdm/lightdm-gtk-greeter.conf b/lightdm/lightdm-gtk-greeter.conf deleted file mode 100644 index d3d1fb3..0000000 --- a/lightdm/lightdm-gtk-greeter.conf +++ /dev/null @@ -1,21 +0,0 @@ -# -# background = Background file to use, either an image path or a color (e.g. #772953) -# show-language-selector (true or false) -# theme-name = GTK+ theme to use -# font-name = Font to use -# xft-antialias = Whether to antialias Xft fonts (true or false) -# xft-dpi = Resolution for Xft in dots per inch (e.g. 96) -# xft-hintstyle = What degree of hinting to use (hintnone, hintslight, hintmedium, or hintfull) -# xft-rgba = Type of subpixel antialiasing (none, rgb, bgr, vrgb or vbgr) -# - -[greeter] -background=/usr/share/kano-desktop/wallpapers/login-background.png -#show-language-selector=false -theme-name=Kano -font-name=Bariol -xft-antialias=true -#xft-dpi= -xft-hintstyle=hintfull -xft-rgba=rgb -