0
0
Fork 0
mirror of https://github.com/boltgolt/howdy.git synced 2024-09-19 09:51:19 +02:00

First working implementation of auth ui in gtk

This commit is contained in:
boltgolt 2020-12-03 00:36:22 +01:00
parent 3c9537a35f
commit d154c56566
No known key found for this signature in database
GPG key ID: BECEC9937E1AAE26
3 changed files with 174 additions and 9 deletions

125
howdy-gtk/authsticky.py Normal file
View file

@ -0,0 +1,125 @@
# Shows a floating window when authenticating
import cairo
import gi
import signal
import sys
import os
# Make sure we have the libs we need
gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0")
# Import them
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
from gi.repository import GObject as gobject
# Set window size constants
windowWidth = 400
windowHeight = 100
message = "Starting up... "
subtext = ""
class StickyWindow(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.set_title("Howdy Authentication UI")
# Set a bunch of options to make the window stick and be on top of everything
self.stick()
self.set_gravity(gdk.Gravity.STATIC)
self.set_resizable(False)
self.set_keep_above(True)
self.set_app_paintable(True)
self.set_skip_pager_hint(True)
self.set_skip_taskbar_hint(True)
self.set_can_focus(False)
self.set_can_default(False)
self.set_focus(None)
self.set_type_hint(gdk.WindowTypeHint.NOTIFICATION)
self.set_decorated(False)
# Draw
self.connect("draw", self.draw)
self.connect("destroy", self.exit)
self.connect("button-press-event", self.exit)
darea = gtk.DrawingArea()
darea.set_size_request(windowWidth, windowHeight)
self.add(darea)
screen = self.get_screen()
visual = screen.get_rgba_visual()
if visual and screen.is_composited():
self.set_visual(visual)
# TODO: handle more than 1 screen
self.move((screen.get_width() / 2) - (windowWidth / 2), 0)
self.show_all()
self.resize(windowWidth, windowHeight)
gobject.timeout_add(100, self.test)
gtk.main()
def draw(self, widget, ctx):
# Change cursor to the kill icon
self.get_window().set_cursor(gdk.Cursor(gdk.CursorType.PIRATE))
ctx.set_source_rgba(0, 0, 0, .9)
ctx.set_operator(cairo.OPERATOR_SOURCE)
ctx.paint()
ctx.set_operator(cairo.OPERATOR_OVER)
dir = os.path.dirname(os.path.abspath(__file__))
image_surface = cairo.ImageSurface.create_from_png(dir + "/logo.png")
ratio = float(windowHeight - 20) / float(image_surface.get_height())
ctx.translate(15, 10)
ctx.scale(ratio, ratio)
ctx.set_source_surface(image_surface)
ctx.paint()
ctx.set_source_rgba(255, 255, 255, .9)
ctx.set_font_size(80)
if subtext:
ctx.move_to(380, 145)
else:
ctx.move_to(380, 170)
ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
ctx.show_text(message)
ctx.set_source_rgba(230, 230, 230, .8)
ctx.set_font_size(40)
ctx.move_to(380, 210)
ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
ctx.show_text(subtext)
def exit(self, widget, context):
gtk.main_quit()
def test(self):
global message, subtext
comm = sys.stdin.readline()[:-1]
if comm:
if comm[0] == "M":
message = comm[2:]
if comm[0] == "S":
subtext = comm[2:]
self.queue_draw()
gobject.timeout_add(100, self.test)
signal.signal(signal.SIGINT, signal.SIG_DFL)
window = StickyWindow()

BIN
howdy-gtk/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -17,12 +17,21 @@ import configparser
import dlib
import cv2
import datetime
import subprocess
import snapshot
import numpy as np
import _thread as thread
from recorders.video_capture import VideoCapture
def exit(code):
"""Exit while closeing howdy-gtk properly"""
global gtk_proc
gtk_proc.terminate()
sys.exit(code)
def init_detector(lock):
"""Start face detector, encoder and predictor in a new thread"""
global face_detector, pose_predictor, face_encoder
@ -33,7 +42,7 @@ def init_detector(lock):
print("\n\tcd " + PATH + "/dlib-data")
print("\tsudo ./install.sh\n")
lock.release()
sys.exit(1)
exit(1)
# Use the CNN detector if enabled
if use_cnn:
@ -62,9 +71,24 @@ def make_snapshot(type):
])
def send_to_ui(type, message):
"""Send message to the auth ui"""
global gtk_proc
# Format message so the ui can parse it
message = type + "=" + message + " \n"
# Try to send the message to the auth ui, but it's okay if that fails
try:
gtk_proc.stdin.write(bytearray(message.encode("ascii")))
gtk_proc.stdin.flush()
except IOError as err:
pass
# Make sure we were given an username to tast against
if len(sys.argv) < 2:
sys.exit(12)
exit(12)
# Get the absolute path to the current directory
PATH = os.path.abspath(__file__ + "/..")
@ -90,6 +114,11 @@ face_detector = None
pose_predictor = None
face_encoder = None
# Start the auth ui
gtk_proc = subprocess.Popen(["python3", "-u", "../howdy-gtk/authsticky.py"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# Write to the stdin to redraw ui
send_to_ui("M", "Starting up...")
# Try to load the face model from the models folder
try:
models = json.load(open(PATH + "/models/" + user + ".dat"))
@ -97,11 +126,11 @@ try:
for model in models:
encodings += model["data"]
except FileNotFoundError:
sys.exit(10)
exit(10)
# Check if the file contains a model
if len(models) < 1:
sys.exit(10)
exit(10)
# Read config from disk
config = configparser.ConfigParser()
@ -156,18 +185,29 @@ timeout = config.getint("video", "timeout")
dark_threshold = config.getfloat("video", "dark_threshold")
end_report = config.getboolean("debug", "end_report")
# Initiate histogram equalization
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
# Let the ui know that we're ready
send_to_ui("M", "Identifying you...")
# Start the read loop
frames = 0
valid_frames = 0
timings["fr"] = time.time()
dark_running_total = 0
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
while True:
# Increment the frame count every loop
frames += 1
# Form a string to let the user know we're real busy
ui_subtext = "Scanned " + str(valid_frames) + " frames"
if (dark_tries > 1):
ui_subtext += " (skipped " + str(dark_tries) + " dark frames)"
# Show it in the ui as subtext
send_to_ui("S", ui_subtext)
# Stop if we've exceded the time limit
if time.time() - timings["fr"] > timeout:
# Create a timeout snapshot if enabled
@ -177,9 +217,9 @@ while True:
if dark_tries == valid_frames:
print("All frames were too dark, please check dark_threshold in config")
print("Average darkness: " + str(dark_running_total / max(1, valid_frames)) + ", Threshold: " + str(dark_threshold))
sys.exit(13)
exit(13)
else:
sys.exit(11)
exit(11)
# Grab a single frame of video
frame, gsframe = video_capture.read_frame()
@ -283,7 +323,7 @@ while True:
make_snapshot("SUCCESSFUL")
# End peacefully
sys.exit(0)
exit(0)
if exposure != -1:
# For a strange reason on some cameras (e.g. Lenoxo X1E)