Index: src/mlx/gui/acars.py
===================================================================
--- src/mlx/gui/acars.py	(revision 747)
+++ src/mlx/gui/acars.py	(revision 919)
@@ -1,9 +1,9 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
 import mlx.const as const
 
-import cef
+from . import cef
 
 #------------------------------------------------------------------------------
Index: src/mlx/gui/bugreport.py
===================================================================
--- src/mlx/gui/bugreport.py	(revision 492)
+++ src/mlx/gui/bugreport.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -105,5 +105,5 @@
         response = super(BugReportDialog, self).run()
 
-        print "response", response, RESPONSETYPE_ACCEPT
+        print("response", response, RESPONSETYPE_ACCEPT)
         if response==RESPONSETYPE_ACCEPT:
             self._send()
@@ -126,9 +126,8 @@
                                      descriptionBuffer.get_end_iter(),
                                      False)
-        description = text2unicode(description)
         self.set_sensitive(False)
-        self._gui.sendBugReport(text2unicode(self._summary.get_text()),
+        self._gui.sendBugReport(self._summary.get_text(),
                                 description,
-                                text2unicode(self._email.get_text()),
+                                self._email.get_text(),
                                 self._bugReportSent)
 
Index: src/mlx/gui/callouts.py
===================================================================
--- src/mlx/gui/callouts.py	(revision 300)
+++ src/mlx/gui/callouts.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -208,5 +208,5 @@
             config = self._gui.config
             for (aircraftType, approachCallouts) in \
-                    self._approachCallouts.iteritems():
+                    self._approachCallouts.items():
                 config.setApproachCallouts(aircraftType, approachCallouts)
             config.save()
Index: src/mlx/gui/cef.py
===================================================================
--- src/mlx/gui/cef.py	(revision 915)
+++ src/mlx/gui/cef.py	(revision 945)
@@ -1,3 +1,3 @@
-from common import *
+from .common import *
 
 from mlx.util import secondaryInstallation
@@ -10,11 +10,12 @@
 import os
 import re
-import thread
+import _thread
 import threading
 import tempfile
 import traceback
-import urllib2
+import ctypes
+import urllib.request, urllib.error, urllib.parse
 from lxml import etree
-from StringIO import StringIO
+from io import StringIO
 import lxml.html
 
@@ -112,9 +113,9 @@
                              SIMBRIEF_RESULT_NONE, None)
 
-    def _onLoadEnd(self, browser, frame, httpCode):
+    def _onLoadEnd(self, browser, frame, http_code):
         """Called when a page has been loaded in the SimBrief browser."""
         url = frame.GetUrl()
-        print "gui.cef.SimBriefHandler._onLoadEnd", httpCode, url
-        if httpCode>=300:
+        print("gui.cef.SimBriefHandler._onLoadEnd", http_code, url)
+        if http_code>=300:
             self._updateProgress(self._lastProgress,
                                  SIMBRIEF_RESULT_ERROR_OTHER, None)
@@ -127,7 +128,7 @@
 
             js = "form=document.getElementById(\"sbapiform\");"
-            for (name, value) in self._plan.iteritems():
+            for (name, value) in self._plan.items():
                 js += "form." + name + ".value=\"" + value + "\";"
-            for (name, value) in SimBriefHandler._querySettings.iteritems():
+            for (name, value) in SimBriefHandler._querySettings.items():
                 if isinstance(value, bool):
                     js += "form." + name + ".checked=" + \
@@ -175,6 +176,6 @@
 
             thread = threading.Thread(target = self._getResults, args = (link,))
-            thread.daemon = True
-            thread.start()
+            _thread.daemon = True
+            _thread.start()
         else:
             self._updateProgress(SIMBRIEF_PROGRESS_RETRIEVING_BRIEFING,
@@ -194,8 +195,10 @@
         self._lastProgress = progress
         if results!=SIMBRIEF_RESULT_NONE:
-            gobject.source_remove(self._timeoutID)
+            if self._timeoutID is not None:
+                gobject.source_remove(self._timeoutID)
             self._plan = None
 
-        self._updateProgressFn(progress, results, flightInfo)
+        if self._updateProgressFn is not None:
+            self._updateProgressFn(progress, results, flightInfo)
 
     def _timedOut(self):
@@ -219,5 +222,5 @@
 
         # Obtaining the xml
-        response = urllib2.urlopen(link)
+        response = urllib.request.urlopen(link)
         xmlContent = response.read()
         # Processing xml
@@ -242,5 +245,5 @@
                     imageLinks.append(imageLink[2])
         flightInfo["image_links"] = imageLinks
-        print(sorted(availableInfo.keys()))
+        print((sorted(availableInfo.keys())))
         htmlFilePath = "simbrief_plan.html" if self._htmlFilePath is None \
           else self._htmlFilePath
@@ -266,5 +269,5 @@
 def _initializeCEF(args, initializedCallback):
     """Perform the actual initialization of CEF using the given arguments."""
-    print "Initializing CEF with args:", args
+    print("Initializing CEF with args:", args)
 
     settings = {
@@ -290,5 +293,5 @@
                     switches[arg[2:assignIndex]] = arg[assignIndex+1:]
         else:
-            print "Unhandled switch", arg
+            print("Unhandled switch", arg)
 
     cefpython.Initialize(settings, switches)
@@ -296,5 +299,5 @@
     gobject.timeout_add(10, _handleTimeout)
 
-    print "Initialized, executing callback..."
+    print("Initialized, executing callback...")
     initializedCallback()
 
@@ -320,12 +323,17 @@
     """Start a browser instance in the given container with the given URL."""
     if os.name=="nt":
-        window = container.get_window()
-        if window is None:
-            print "mlx.gui.cef.startInContainer: no window found!"
-            windowID = None
-        else:
-            windowID = window.handle
+        gdk.threads_enter()
+        ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
+        ctypes.pythonapi.PyCapsule_GetPointer.argtypes = \
+            [ctypes.py_object]
+        gpointer = ctypes.pythonapi.PyCapsule_GetPointer(
+            container.get_property("window").__gpointer__, None)
+        libgdk = ctypes.CDLL("libgdk-3-0.dll")
+        windowID = libgdk.gdk_win32_window_get_handle(gpointer)
+        container.windowID = windowID
+        gdk.threads_leave()
     else:
-        windowID = container.window.xid
+        container.set_visual(container.get_screen().lookup_visual(0x21))
+        windowID = container.get_window().get_xid()
 
     windowInfo = cefpython.WindowInfo()
@@ -340,12 +348,12 @@
 
 class OffscreenRenderHandler(object):
-    def GetRootScreenRect(self, browser, rect):
+    def GetRootScreenRect(self, browser, rect_out):
         #print "GetRootScreenRect"
-        rect += [0, 0, 800, 600]
+        rect_out += [0, 0, 800, 600]
         return True
 
-    def GetViewRect(self, browser, rect):
+    def GetViewRect(self, browser, rect_out):
         #print "GetViewRect"
-        rect += [0, 0, 800, 600]
+        rect_out += [0, 0, 800, 600]
         return True
 
@@ -367,5 +375,5 @@
         pass
 
-    def OnPaint(self, browser, paintElementType, dirtyRects, buffer, width, height):
+    def OnPaint(self, browser, element_type, dirty_rects, paint_buffer, width, height):
         #print "OnPaint", paintElementType, dirtyRects, buffer, width, height
         pass
@@ -424,6 +432,5 @@
 
 def _handleSizeAllocate(widget, sizeAlloc):
-    """Handle the size-allocate event."""
-    window = widget.get_window()
+    """Handle the size-allocate event on Windows."""
     if widget is not None:
-        cefpython.WindowUtils.OnSize(window.handle, 0, 0, 0)
+        cefpython.WindowUtils.OnSize(widget.windowID, 0, 0, 0)
Index: src/mlx/gui/checklist.py
===================================================================
--- src/mlx/gui/checklist.py	(revision 300)
+++ src/mlx/gui/checklist.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -190,5 +190,5 @@
             self._saveChecklist()
             config = self._gui.config
-            for (aircraftType, checklist) in self._checklists.iteritems():
+            for (aircraftType, checklist) in self._checklists.items():
                 config.setChecklist(aircraftType, checklist)
             config.save()
@@ -204,5 +204,4 @@
         numSelected = 0
         for path in fileChooser.get_filenames():
-            path = text2unicode(path)
             numSelected += 1
             if os.path.isfile(path): numFiles += 1
@@ -213,5 +212,4 @@
         """Called when the Add button is clicked."""
         for path in self._fileChooser.get_filenames():
-            path = text2unicode(path)
             self._fileListModel.append([os.path.basename(path),
                                         path])
Index: src/mlx/gui/common.py
===================================================================
--- src/mlx/gui/common.py	(revision 863)
+++ src/mlx/gui/common.py	(revision 954)
@@ -31,5 +31,5 @@
 
 if not pygobject:
-    print "Using PyGTK"
+    print("Using PyGTK")
     pygobject = False
     import pygtk
@@ -42,5 +42,5 @@
         import appindicator
         appIndicator = True
-    except Exception, e:
+    except Exception as e:
         pass
 
@@ -111,20 +111,19 @@
     pixbuf_new_from_file = gdk.pixbuf_new_from_file
 
-    def text2unicode(text):
-        """Convert the given text, returned by a Gtk widget, to Unicode."""
-        return unicode(text)
-
-    def text2str(text):
-        """Convert the given text, returned by xstr to a string."""
-        return str(text)
-
 else: # pygobject
+    import gi
+    gi.require_version("Gdk", "3.0")
     from gi.repository import Gdk as gdk
     from gi.repository import GdkPixbuf as gdkPixbuf
+    gi.require_version("Gtk", "3.0")
     from gi.repository import Gtk as gtk
-    from gi.repository import AppIndicator3 as appindicator
+    try:
+        gi.require_version("AppIndicator3", "0.1")
+        from gi.repository import AppIndicator3 as appindicator
+        appIndicator = True
+    except:
+        pass
     from gi.repository import Pango as pango
 
-    appIndicator = True
 
 
@@ -193,12 +192,4 @@
     _utf8Decoder = codecs.getdecoder("utf-8")
 
-    def text2unicode(str):
-        """Convert the given text, returned by a Gtk widget, to Unicode."""
-        return _utf8Decoder(str)[0]
-
-    def text2str(text):
-        """Convert the given text, returned by xstr to a string."""
-        return _utf8Decoder(text)[0]
-
 import cairo
 
@@ -296,5 +287,6 @@
     def __init__(self):
         """Construct the entry"""
-        super(TimeEntry, self).__init__(max = 5)
+        super(TimeEntry, self).__init__()
+        self.set_max_width_chars(5)
 
         self.connect("insert-text", self._insertText)
Index: src/mlx/gui/delaycodes.py
===================================================================
--- src/mlx/gui/delaycodes.py	(revision 840)
+++ src/mlx/gui/delaycodes.py	(revision 919)
@@ -3,5 +3,5 @@
 #------------------------------------------------------------------------------
 
-from dcdata import CAPTION, DELAYCODE, getTable
+from .dcdata import CAPTION, DELAYCODE, getTable
 
 from mlx.gui.common import *
Index: src/mlx/gui/faultexplain.py
===================================================================
--- src/mlx/gui/faultexplain.py	(revision 842)
+++ src/mlx/gui/faultexplain.py	(revision 919)
@@ -247,5 +247,5 @@
     def reset(self):
         """Reset the widget by removing all faults."""
-        for (alignment, faultFrame) in self._faultWidgets.itervalues():
+        for (alignment, faultFrame) in self._faultWidgets.values():
             self._faults.remove(alignment)
         self._faults.show_all()
Index: src/mlx/gui/flight.py
===================================================================
--- src/mlx/gui/flight.py	(revision 872)
+++ src/mlx/gui/flight.py	(revision 954)
@@ -405,10 +405,10 @@
     def _offlineClicked(self, button):
         """Called when the offline button was clicked."""
-        print "mlx.flight.LoginPage: offline flight selected"
+        print("mlx.flight.LoginPage: offline flight selected")
         self._wizard.nextPage()
 
     def _loginClicked(self, button):
         """Called when the login button was clicked."""
-        print "mlx.flight.LoginPage: logging in"
+        print("mlx.flight.LoginPage: logging in")
         self._wizard.login(self._handleLoginResult,
                            self._pilotID.get_text(),
@@ -648,11 +648,11 @@
 
         if response==RESPONSETYPE_OK:
-            fileName = text2unicode(dialog.get_filename())
-            print "Saving", fileName
+            fileName = dialog.get_filename()
+            print("Saving", fileName)
             try:
                 with open(fileName, "wt") as f:
                     flight.writeIntoFile(f)
-            except Exception, e:
-                print "Failed to save flight:", util.utf2unicode(str(e))
+            except Exception as e:
+                print("Failed to save flight:", util.utf2unicode(str(e)))
                 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
                                            type = MESSAGETYPE_ERROR,
@@ -706,5 +706,5 @@
         flight=self._getSelectedFlight()
 
-        print "DPI", context.get_dpi_x(), context.get_dpi_y()
+        print("DPI", context.get_dpi_x(), context.get_dpi_y())
 
         scale = context.get_dpi_x() / 72.0
@@ -719,5 +719,5 @@
 
         layout = cr.create_layout()
-        layout.set_text(u"Malév VA official briefing")
+        layout.set_text("Malév VA official briefing")
         font = pango.FontDescription("sans")
         font.set_size(int(32 * scale * pango.SCALE))
@@ -740,5 +740,5 @@
 
         layout = cr.create_layout()
-        layout.set_text(u"%s (%s) részére" %
+        layout.set_text("%s (%s) részére" %
                         (loginResult.pilotName, loginResult.pilotID))
         font = pango.FontDescription("sans")
@@ -939,6 +939,6 @@
 
         if response==RESPONSETYPE_OK:
-            fileName = text2unicode(dialog.get_filename())
-            print "Loading", fileName
+            fileName = dialog.get_filename()
+            print("Loading", fileName)
             bookedFlight = web.BookedFlight()
             try:
@@ -946,6 +946,6 @@
                     bookedFlight.readFromFile(f)
                 self.addFlight(bookedFlight)
-            except Exception, e:
-                print "Failed to load flight:", util.utf2unicode(str(e))
+            except Exception as e:
+                print("Failed to load flight:", util.utf2unicode(str(e)))
                 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
                                            type = MESSAGETYPE_ERROR,
@@ -1629,13 +1629,13 @@
                                             self.phoneNumber, self.nationality,
                                             self.password)
-        print "Registering with data:"
-        print "  name:", self.name1, self.name2, registrationData.firstName, registrationData.surName, requestedNameOrder
-        print "  yearOfBirth:", self.yearOfBirth, registrationData.yearOfBirth
-        print "  emailAddress:", self.emailAddress, registrationData.emailAddress
-        print "  emailAddressPublic:", self.emailAddressPublic, registrationData.emailAddressPublic
-        print "  vatsimID:", self.vatsimID, registrationData.vatsimID
-        print "  ivaoID:", self.ivaoID, registrationData.ivaoID
-        print "  phoneNumber:", self.phoneNumber, registrationData.phoneNumber
-        print "  nationality:", self.nationality, registrationData.nationality
+        print("Registering with data:")
+        print("  name:", self.name1, self.name2, registrationData.firstName, registrationData.surName, requestedNameOrder)
+        print("  yearOfBirth:", self.yearOfBirth, registrationData.yearOfBirth)
+        print("  emailAddress:", self.emailAddress, registrationData.emailAddress)
+        print("  emailAddressPublic:", self.emailAddressPublic, registrationData.emailAddressPublic)
+        print("  vatsimID:", self.vatsimID, registrationData.vatsimID)
+        print("  ivaoID:", self.ivaoID, registrationData.ivaoID)
+        print("  phoneNumber:", self.phoneNumber, registrationData.phoneNumber)
+        print("  nationality:", self.nationality, registrationData.nationality)
 
         gui = self._wizard.gui
@@ -1653,13 +1653,13 @@
         gui.endBusy()
 
-        print "Registration result:"
-        print "  returned:", returned
+        print("Registration result:")
+        print("  returned:", returned)
         if returned:
-            print "  registered:", result.registered
+            print("  registered:", result.registered)
             if result.registered:
-                print "  pilotID", result.pilotID
-                print "  loggedIn", result.loggedIn
-            print "  emailAlreadyRegistered:", result.emailAlreadyRegistered
-            print "  invalidData:", result.invalidData
+                print("  pilotID", result.pilotID)
+                print("  loggedIn", result.loggedIn)
+            print("  emailAlreadyRegistered:", result.emailAlreadyRegistered)
+            print("  invalidData:", result.invalidData)
 
         registrationOK = returned and result.registered
@@ -1830,5 +1830,5 @@
     def activate(self):
         """Activate the student page."""
-        print "StudentPage.activate"
+        print("StudentPage.activate")
         self._getEntryExamStatusCancelled = False
 
@@ -1844,5 +1844,5 @@
     def finalize(self):
         """Finalize the page."""
-        print "StudentPage.finalize"
+        print("StudentPage.finalize")
         self._getEntryExamStatusCancelled = True
 
@@ -1864,5 +1864,5 @@
     def _handleEntryExamStatus(self, returned, result):
         """Called when the entry exam status is availabe."""
-        print "_handleEntryExamStatus", returned, result
+        print("_handleEntryExamStatus", returned, result)
         if returned and not self._getEntryExamStatusCancelled:
             self._entryExamLink = result.entryExamLink
@@ -2991,5 +2991,5 @@
 
             plan = self._getPlan()
-            print "plan:", plan
+            print("plan:", plan)
 
             takeoffRunway = self._takeoffRunway.get_text()
@@ -3027,5 +3027,5 @@
         are returned. Otherwise a dialog box is displayed informing the user of
         invalid credentials and requesting another set of them."""
-        print "_getCredentials", count
+        print("_getCredentials", count)
         if count==0:
             return (self._userName.get_text(), self._password.get_text())
@@ -3061,5 +3061,5 @@
     def _simBriefProgress(self, progress, result, flightInfo):
         """The real SimBrief progress handler."""
-        print "_simBriefProgress", progress, result, flightInfo
+        print("_simBriefProgress", progress, result, flightInfo)
         if result==cef.SIMBRIEF_RESULT_NONE:
             message = SimBriefSetupPage.progress2Message.get(progress,
@@ -3758,5 +3758,5 @@
     def _metarChanged(self, buffer):
         """Called when the METAR has changed."""
-        print "BriefingPage.metarChanged", self._updatingMETAR
+        print("BriefingPage.metarChanged", self._updatingMETAR)
         if not self._updatingMETAR:
             self.metarEdited = True
@@ -3770,5 +3770,5 @@
 
         It uppercases all characters."""
-        print "BriefingPage.metarInserted", self._updatingMETAR
+        print("BriefingPage.metarInserted", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updatingMETAR = True
@@ -4025,5 +4025,5 @@
     def activate(self):
         """Activate the page."""
-        print "TakeoffPage.activate"
+        print("TakeoffPage.activate")
 
         self._updatingMETAR = True
@@ -4069,5 +4069,5 @@
     def allowForward(self):
         """Allow going to the next page."""
-        print "TakeoffPage.allowForward"
+        print("TakeoffPage.allowForward")
         self._forwardAllowed = True
         self._updateForwardButton()
@@ -4075,5 +4075,5 @@
     def reset(self):
         """Reset the page if the wizard is reset."""
-        print "TakeoffPage.reset"
+        print("TakeoffPage.reset")
 
         super(TakeoffPage, self).reset()
@@ -4095,5 +4095,5 @@
         pages."""
         if self._active:
-            print "TakeoffPage.changeMETAR"
+            print("TakeoffPage.changeMETAR")
             self._updatingMETAR = True
             self._metar.get_buffer().set_text(metar, -1)
@@ -4116,14 +4116,14 @@
                      self.derate is not None)
 
-        print "TakeoffPage._updateForwardButton: forwardAllowed:", self._forwardAllowed, ", sensitive:", sensitive
+        print("TakeoffPage._updateForwardButton: forwardAllowed:", self._forwardAllowed, ", sensitive:", sensitive)
         if self._forwardAllowed:
-            print "  METAR: ", self._metar.get_text()
-            print "  runway: ", self._runway.get_text()
-            print "  SID:", self.sid
-            print "  V1:", self.v1
-            print "  VR:", self.vr
-            print "  V2:", self.v2
-            print "  derateType:", self._derateType
-            print "  derate:", self.derate
+            print("  METAR: ", self._metar.get_text())
+            print("  runway: ", self._runway.get_text())
+            print("  SID:", self.sid)
+            print("  V1:", self.v1)
+            print("  VR:", self.vr)
+            print("  V2:", self.v2)
+            print("  derateType:", self._derateType)
+            print("  derate:", self.derate)
 
         self._button.set_sensitive(sensitive)
@@ -4131,5 +4131,5 @@
     def _valueChanged(self, widget, arg = None):
         """Called when the value of some widget has changed."""
-        print "TakeoffPage._valueChanged"
+        print("TakeoffPage._valueChanged")
 
         self._updateForwardButton()
@@ -4138,5 +4138,5 @@
         """Called when the value of some entry widget has changed and the value
         should be converted to uppercase."""
-        print "TakeoffPage._upperChanged"
+        print("TakeoffPage._upperChanged")
         entry.set_text(entry.get_text().upper())
         self._valueChanged(entry, arg)
@@ -4151,5 +4151,5 @@
     def _derateChanged(self, entry):
         """Called when the value of the derate is changed."""
-        print "TakeoffPage._derateChanged"
+        print("TakeoffPage._derateChanged")
         self._updateForwardButton()
 
@@ -4262,5 +4262,5 @@
     def _metarChanged(self, entry):
         """Called when the METAR has changed."""
-        print "TakeoffPage.metarChanged", self._updatingMETAR
+        print("TakeoffPage.metarChanged", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updateForwardButton()
@@ -4271,5 +4271,5 @@
 
         It uppercases all characters."""
-        print "TakeoffPage.metarInserted", self._updatingMETAR
+        print("TakeoffPage.metarInserted", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updatingMETAR = True
@@ -4628,5 +4628,5 @@
         pages."""
         if self._active:
-            print "LandingPage.changeMETAR"
+            print("LandingPage.changeMETAR")
             self._updatingMETAR = True
             self._metar.get_buffer().set_text(metar, -1)
@@ -4689,5 +4689,5 @@
     def _metarChanged(self, entry):
         """Called when the METAR has changed."""
-        print "LandingPage.metarChanged", self._updatingMETAR
+        print("LandingPage.metarChanged", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updateForwardButton()
@@ -4698,5 +4698,5 @@
 
         It uppercases all characters."""
-        print "LandingPage.metarInserted", self._updatingMETAR
+        print("LandingPage.metarInserted", self._updatingMETAR)
         if not self._updatingMETAR:
             self._updatingMETAR = True
@@ -4740,5 +4740,5 @@
         self._lastSavePath = os.path.join(self._wizard.gui.config.pirepDirectory,
                                           self._getDefaultPIREPName())
-        self._lastSavePath = text2unicode(self._lastSavePath)
+        self._lastSavePath = self._lastSavePath
         self._savePIREP(page, automatic = True)
 
@@ -4777,5 +4777,5 @@
 
         if result==RESPONSETYPE_OK:
-            self._lastSavePath = text2unicode(dialog.get_filename())
+            self._lastSavePath = dialog.get_filename()
             self._savePIREP(page)
 
@@ -4797,5 +4797,5 @@
             type = MESSAGETYPE_ERROR
             message = xstr("finish_save_failed")
-            secondary = xstr("finish_save_failed_sec") % (text2unicode(error),)
+            secondary = xstr("finish_save_failed_sec") % (error,)
         else:
             type = MESSAGETYPE_INFO
@@ -5217,7 +5217,8 @@
         pass
 
-    def _formatTime(self, scheduledTime, realTimestamp, (warning, error)):
+    def _formatTime(self, scheduledTime, realTimestamp, xxx_todo_changeme):
         """Format the departure or arrival time based on the given data as a
         markup for a label."""
+        (warning, error) = xxx_todo_changeme
         realTime = time.gmtime(realTimestamp)
 
@@ -5752,5 +5753,5 @@
         elif stage==const.STAGE_LANDING:
             if not self._arrivalBriefingPage.metarEdited:
-                print "Downloading arrival METAR again"
+                print("Downloading arrival METAR again")
                 self.gui.webHandler.getMETARs(self._arrivalMETARCallback,
                                               [self._bookedFlight.arrivalICAO])
Index: src/mlx/gui/flightlist.py
===================================================================
--- src/mlx/gui/flightlist.py	(revision 868)
+++ src/mlx/gui/flightlist.py	(revision 927)
@@ -61,5 +61,5 @@
 
         if self._extraColumnAttributes is not None:
-            for (key, value) in self._extraColumnAttributes.iteritems():
+            for (key, value) in self._extraColumnAttributes.items():
                 if key=="alignment":
                     self._renderer.set_alignment(value, 0.5)
@@ -171,5 +171,5 @@
     def hasFlights(self):
         """Determine if there are any flights in the list."""
-        return self._model.get_iter_root() is not None
+        return self._model.get_iter_first() is not None
 
     def clear(self):
@@ -271,5 +271,6 @@
     def __init__(self, which, wizard, window, pirepEditable = False):
         """Construct the frame with the given title."""
-        super(PendingFlightsFrame, self).__init__(xstr("pendflt_title_" + which))
+        super(PendingFlightsFrame, self).__init__()
+        self.set_label(xstr("pendflt_title_" + which))
 
         self._which = which
@@ -401,5 +402,5 @@
         gui.endBusy()
 
-        print "PendingFlightsFrame._handleReflyResult", returned, result
+        print("PendingFlightsFrame._handleReflyResult", returned, result)
 
         if returned:
@@ -444,5 +445,5 @@
         gui.endBusy()
 
-        print "PendingFlightsFrame._handleDeleteResult", returned, result
+        print("PendingFlightsFrame._handleDeleteResult", returned, result)
 
         if returned:
Index: src/mlx/gui/gates.py
===================================================================
--- src/mlx/gui/gates.py	(revision 619)
+++ src/mlx/gui/gates.py	(revision 919)
@@ -143,5 +143,5 @@
         self._fleetStore.clear()
         if fleet is None:
-            for (gateNumber, label) in self._gateLabels.iteritems():
+            for (gateNumber, label) in self._gateLabels.items():
                 label.set_markup("<b>" + gateNumber + "</b>")
         else:        
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 951)
+++ src/mlx/gui/gui.py	(revision 954)
@@ -1,8 +1,8 @@
 # -*- coding: utf-8 -*-
 
-from statusicon import StatusIcon
-from statusbar import Statusbar
-from info import FlightInfo
-from update import Updater
+from .statusicon import StatusIcon
+from .statusbar import Statusbar
+from .info import FlightInfo
+from .update import Updater
 from mlx.gui.common import *
 from mlx.gui.flight import Wizard
@@ -18,5 +18,5 @@
 from mlx.gui.acars import ACARS
 from mlx.gui.timetable import TimetableWindow
-import cef
+from . import cef
 
 import mlx.const as const
@@ -51,13 +51,13 @@
 class GUI(fs.ConnectionListener):
     """The main GUI class."""
-    _authors = [ (u"Váradi", u"István", "prog_test"),
-                 (u"Galyassy", u"Tamás", "negotiation"),
-                 (u"Kurják", u"Ákos", "test"),
-                 (u"Nagy", u"Dániel", "test"),
-                 (u"Radó", u"Iván", "test"),
-                 (u"Petrovszki", u"Gábor", "test"),
-                 (u"Serfőző", u"Tamás", "test"),
-                 (u"Szebenyi", u"Bálint", "test"),
-                 (u"Zsebényi-Loksa", u"Gergely", "test") ]
+    _authors = [ ("Váradi", "István", "prog_test"),
+                 ("Galyassy", "Tamás", "negotiation"),
+                 ("Kurják", "Ákos", "test"),
+                 ("Nagy", "Dániel", "test"),
+                 ("Radó", "Iván", "test"),
+                 ("Petrovszki", "Gábor", "test"),
+                 ("Serfőző", "Tamás", "test"),
+                 ("Szebenyi", "Bálint", "test"),
+                 ("Zsebényi-Loksa", "Gergely", "test") ]
 
     def __init__(self, programDirectory, config):
@@ -109,4 +109,6 @@
 
         self._mainWindow = window = gtk.Window()
+        if os.name!="nt":
+            window.set_visual(window.get_screen().lookup_visual(0x21))
         window.set_title(WINDOW_TITLE_BASE)
         window.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
@@ -197,6 +199,4 @@
 
         window.show_all()
-        if os.name=="nt":
-            window.get_window().focus()
 
         self._wizard.grabDefault()
@@ -763,5 +763,5 @@
         Here we reset the focus to the main window as CEF might have acquired
         it earlier."""
-        self._mainWindow.get_window().focus()
+        self._mainWindow.get_window().focus(0)
 
     def raiseCallback(self):
@@ -1460,5 +1460,5 @@
                 secondaryMarkup = xstr("sendPIREP_unknown_sec")
         else:
-            print "PIREP sending failed", result
+            print("PIREP sending failed", result)
             messageFormat = xstr("sendPIREP_failed")
             secondaryMarkup = xstr("sendPIREP_failed_sec")
@@ -1492,5 +1492,5 @@
 
         if result==RESPONSETYPE_OK:
-            self._lastLoadedPIREP = text2unicode(dialog.get_filename())
+            self._lastLoadedPIREP = dialog.get_filename()
 
             pirep = PIREP.load(self._lastLoadedPIREP)
@@ -1684,5 +1684,5 @@
                 secondaryMarkup = xstr("sendPIREP_unknown_sec")
         else:
-            print "PIREP sending failed", result
+            print("PIREP sending failed", result)
             messageFormat = xstr("sendPIREP_failed")
             secondaryMarkup = xstr("sendPIREP_failed_sec")
@@ -1709,5 +1709,5 @@
 
         for (timestampString, text) in self._logger.lines:
-            description += unicode(formatFlightLogLine(timestampString, text))
+            description += str(formatFlightLogLine(timestampString, text))
 
         description += "\n\n" + ("=" * 40)
@@ -1796,11 +1796,11 @@
             for index in hotkeys:
                 if index==self._pilotHotkeyIndex:
-                    print "gui.GUI._handleHotkeys: pilot hotkey pressed"
+                    print("gui.GUI._handleHotkeys: pilot hotkey pressed")
                     self._flight.pilotHotkeyPressed()
                 elif index==self._checklistHotkeyIndex:
-                    print "gui.GUI._handleHotkeys: checklist hotkey pressed"
+                    print("gui.GUI._handleHotkeys: checklist hotkey pressed")
                     self._flight.checklistHotkeyPressed()
                 else:
-                    print "gui.GUI._handleHotkeys: unhandled hotkey index:", index
+                    print("gui.GUI._handleHotkeys: unhandled hotkey index:", index)
 
     def _showManual(self, menuitem):
Index: src/mlx/gui/info.py
===================================================================
--- src/mlx/gui/info.py	(revision 846)
+++ src/mlx/gui/info.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.gui.delaycodes import DelayCodeTable
@@ -108,6 +108,6 @@
         """Get the comments."""
         buffer = self._comments.get_buffer()
-        return text2unicode(buffer.get_text(buffer.get_start_iter(),
-                                            buffer.get_end_iter(), True))
+        return buffer.get_text(buffer.get_start_iter(),
+                               buffer.get_end_iter(), True)
 
     @comments.setter
Index: src/mlx/gui/pirep.py
===================================================================
--- src/mlx/gui/pirep.py	(revision 855)
+++ src/mlx/gui/pirep.py	(revision 919)
@@ -1,7 +1,7 @@
 
-from common import *
-from dcdata import getTable
-from info import FlightInfo
-from flight import comboModel
+from .common import *
+from .dcdata import getTable
+from .info import FlightInfo
+from .flight import comboModel
 
 from mlx.pirep import PIREP
Index: src/mlx/gui/prefs.py
===================================================================
--- src/mlx/gui/prefs.py	(revision 738)
+++ src/mlx/gui/prefs.py	(revision 954)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 from mlx.i18n import xstr
@@ -6,5 +6,5 @@
 import mlx.config as config
 
-import urlparse
+import urllib.parse
 
 #------------------------------------------------------------------------------
@@ -63,5 +63,5 @@
 
         self._hotkeyModel = gtk.ListStore(str)
-        for keyCode in range(ord("0"), ord("9")+1) + range(ord("A"), ord("Z")+1):
+        for keyCode in list(range(ord("0"), ord("9")+1)) + list(range(ord("A"), ord("Z")+1)):
             self._hotkeyModel.append([chr(keyCode)])
 
@@ -296,5 +296,5 @@
                                                        self._vsSmoothingLength)
         config.useSimBrief = self._useSimBrief.get_active()
-        config.pirepDirectory = text2unicode(self._pirepDirectory.get_text())
+        config.pirepDirectory = self._pirepDirectory.get_text()
         config.pirepAutoSave = self._pirepAutoSave.get_active()
 
@@ -565,5 +565,5 @@
 
         if result==RESPONSETYPE_OK:
-            self._pirepDirectory.set_text(text2unicode(dialog.get_filename()))
+            self._pirepDirectory.set_text(dialog.get_filename())
 
     def _pirepDirectoryChanged(self, entry):
@@ -829,5 +829,5 @@
         sensitive = False
         try:
-            result = urlparse.urlparse(self._updateURL.get_text())
+            result = urllib.parse.urlparse(self._updateURL.get_text())
             sensitive = result.scheme!="" and (result.netloc + result.path)!=""
         except:
Index: src/mlx/gui/statusbar.py
===================================================================
--- src/mlx/gui/statusbar.py	(revision 679)
+++ src/mlx/gui/statusbar.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 import mlx.const as const
Index: src/mlx/gui/statusicon.py
===================================================================
--- src/mlx/gui/statusicon.py	(revision 544)
+++ src/mlx/gui/statusicon.py	(revision 919)
@@ -1,4 +1,4 @@
 
-from common import *
+from .common import *
 
 import mlx.const as const
@@ -154,5 +154,5 @@
     def _updateFlightStatus(self):
         """Update the flight status."""
-        stage = u"-" if self._stage is None \
+        stage = "-" if self._stage is None \
                 else xstr("flight_stage_" + const.stage2string(self._stage))
 
@@ -172,5 +172,5 @@
             if self._noGoReason is not None:
                 rating = '<span foreground="red">' + rating + '</span>'
-            markup = u"MAVA Logger X %s\n\n%s: %s\n%s: %s" %\
+            markup = "MAVA Logger X %s\n\n%s: %s\n%s: %s" %\
                      (const.VERSION, xstr("statusicon_stage"), stage,
                       xstr("statusicon_rating"), rating)
Index: src/mlx/gui/timetable.py
===================================================================
--- src/mlx/gui/timetable.py	(revision 879)
+++ src/mlx/gui/timetable.py	(revision 927)
@@ -4,5 +4,5 @@
 
 from mlx.gui.common import *
-from flightlist import ColumnDescriptor
+from .flightlist import ColumnDescriptor
 from mlx.rpc import ScheduledFlight
 
@@ -82,6 +82,4 @@
         self._view = gtk.TreeView(self._model)
 
-        self._tooltips = gtk.Tooltips()
-        self._tooltips.disable()
         self._view.connect("motion-notify-event", self._updateTooltip)
 
@@ -225,6 +223,5 @@
             result = widget.get_path_at_pos( int(event.x), int(event.y))
             if result is None:
-                self._tooltips.set_tip(widget, "")
-                self._tooltips.disable()
+                widget.set_tooltip_text("")
             else:
                 (path, col, x, y) = result
@@ -244,13 +241,18 @@
                         text += date.strftime("%Y-%m-%d")
 
-                    self._tooltips.set_tip(widget, text)
-                    self._tooltips.enable()
+                    widget.set_tooltip_text(text)
                 else:
-                    self._tooltips.set_tip(widget, "")
-                    self._tooltips.disable()
-        except Exception, e:
-            print e
-            self._tooltips.set_tip(widget, "")
-            self._tooltips.disable()
+                    widget.set_tooltip_text("")
+        except Exception as e:
+            print(e)
+            widget.set_tooltip_text("")
+
+#-----------------------------------------------------------------------------
+
+gobject.signal_new("row-activated", Timetable, gobject.SIGNAL_RUN_FIRST,
+                   None, (int,))
+
+gobject.signal_new("selection-changed", Timetable, gobject.SIGNAL_RUN_FIRST,
+                   None, (object,))
 
 #-----------------------------------------------------------------------------
@@ -520,5 +522,6 @@
                                         xscale = 1.0, yscale = 1.0)
 
-        filterFrame = gtk.Frame(xstr("timetable_filter"))
+        filterFrame = gtk.Frame()
+        filterFrame.set_label(xstr("timetable_filter"))
 
         filterVBox = gtk.VBox()
@@ -656,5 +659,5 @@
             typeFamilies.add(const.aircraftType2Family(aircraftType))
 
-        for (typeFamily, checkButton) in self._typeFamilyButtons.iteritems():
+        for (typeFamily, checkButton) in self._typeFamilyButtons.items():
             checkButton.set_sensitive(typeFamily in typeFamilies)
 
@@ -712,5 +715,5 @@
         """Update the timetable list."""
         aircraftTypes = []
-        for (aircraftFamily, button) in self._typeFamilyButtons.iteritems():
+        for (aircraftFamily, button) in self._typeFamilyButtons.items():
             if button.get_active():
                 aircraftTypes += const.aircraftFamily2Types[aircraftFamily]
@@ -752,5 +755,5 @@
         planes = [plane for plane in fleet
                   if plane.aircraftType == aircraftType]
-        planes.sort(cmp = lambda p1, p2: cmp(p1.tailNumber, p2.tailNumber))
+        planes.sort(key = lambda p: p.tailNumber)
 
         dialog = BookDialog(self, flightPair, planes)
