# Copyright 2020 Romain de Laage # # This file is part of tkGemini. # # tkGemini is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # any later version. # # tkGemini is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with tkGemini. If not, see . import tkinter as tk import tkinter.messagebox import tkinter.simpledialog import gemini import renderEngine import urllib.parse class Application(): def __init__(self): # Some global definitions self.root = tk.Tk() self.nav_bar = NavBar(self) self.content = Content(self) self.current_URL = "about:home" # Set window title self.root.title("tkGemini") # App main loop self.root.mainloop() def updateContent(self): # Get url asked url=self.nav_bar.getURL() # Is it a Gemini URL if not(verifyURL(url)): tkinter.messagebox.showerror("URL error", url+" is not a correct Gemini URL ! (HTTP/S is not supported, please use a web browser instead)") return self.current_URL = self.nav_bar.getURL() # New request r = gemini.Request(self.current_URL) status = r.makeRequest() # The server asked for user input if status[0] == "1": user_input = tkinter.simpledialog.askstring("User input", "The server asked for " + r.meta + ".") self.nav_bar.URL_var.set(self.current_URL + "?" + user_input) self.updateContent() # If server asked for redirection elif status[0] == "3": # Ask to user confirm = tkinter.messagebox.askyesno("Server redirection", "This server ask for redirection to " + r.meta + ". Follow ?") # If he accepted if confirm: self.nav_bar.URL_var.set(r.meta) self.updateContent() # The server asked for client certificate, unsupported elif status[0] == "6": tkinter.messagebox.showerror("Client certificate required", "Error " + status + " : " + r.meta) else: self.content.setContent(r.content) def linkClick(self, url): # Check if it is an absolute URL if "://" in url: # Check if it is a gemini URL if verifyURL(url): self.nav_bar.URL_var.set(url) self.updateContent() # Else show error else: tkinter.messagebox.showerror("URL error", url+" is not a correct Gemini URL ! (HTTP/S is not supported, please use a web browser instead)") # It is relative else: # Join current URL and relative path base = self.current_URL base = base.replace("gemini://","http://") url = urllib.parse.urljoin(base, url) url = url.replace("http://", "gemini://") # We can verify because sometime there is errors (mailto:) if verifyURL(url): self.nav_bar.URL_var.set(url) self.updateContent() else: tkinter.messagebox.showerror("URL error", url+" is not a correct Gemini URL ! (HTTP/S is not supported, please use a web browser instead)") def verifyURL(url): # Is it an absolute path ? if "://" in url: parsed_url = urllib.parse.urlparse(url) # Is this path supported ? if parsed_url.scheme == "gemini": return True else: return False class NavBar(): def __init__(self, parent): # Some global definitions self.parent = parent # All widgets are in a frame self.root = tk.Frame(self.parent.root) self.root.grid(column=0, row=0) # Define URL bar and variable self.URL_var = tk.StringVar() self.URL_bar = tk.Entry(self.root, textvariable=self.URL_var) self.URL_var.set("about:home") self.URL_bar.grid(column=0, row=0) # Define go button with action self.go_button = tk.Button(self.root, text='Go !', command=self.parent.updateContent) self.go_button.grid(column=1, row=0) def getURL(self): # Get URL from URL bar variable return self.URL_var.get() class Content(): def __init__(self, parent): self.parent = parent # Text container with home page self.root = renderEngine.Renderer(self.parent, "#Home page\nWelcome on tkGemini, a browser software for Gemini protocole\n=>gemini://rdelaage.ovh My gemini space") self.root.parse() self.root.content.grid(column=0, row=1) # Scrollbar beside to the text container self.scroll_bar = tk.Scrollbar(command=self.root.content.yview, orient='vertical') self.scroll_bar.grid(column=1, row=1) self.root.content['yscrollcommand'] = self.scroll_bar.set # When content is updated def setContent(self, new_content): self.root.text = new_content self.root.parse() app = Application()