Example #1
0
    def quoteOSHPark(self):
        """Function for navigating OSHPark's website."""

        url, user, pw = self.readConfig('oshpark', 'rigid')
        # Open new tab and go to URL
        self.newTab()
        self.driver.get(url)
        # Enter login information
        self.driver.find_element_by_css_selector('#user_email').send_keys(user)
        self.driver.find_element_by_css_selector('#user_password').send_keys(pw)
        # Click login button
        self.driver.find_element_by_css_selector('.buttons > input:nth-child(1)').click()

        self.driver.find_element_by_css_selector('#ember291').click()
        self.driver.find_element_by_css_selector('#file_selector > input:nth-child(2)').click()

        e = EWMH()
        windows = e.getClientList()
        for window in windows:
            if e.getWmName(window) == 'File Upload':
                time.sleep(0.5)
                e.setActiveWindow(window)
                e.display.flush()

        time.sleep(0.5)
        pyautogui.hotkey('ctrl', 'a')
        pyautogui.press('backspace')
        # '''get file location from config file'''
        # pyautogui.typewrite(fileLocation)
        pyautogui.press('return')
Example #2
0
def find_by_pid(pid):
    ewmh = EWMH()
    wnds = list(ewmh.getClientList())
    # pprint(wnds)
    matched = list(filter(check_wnd, wnds))
    if matched:
        got_wnd(matched[0])
Example #3
0
    def __init__(self, parent = None, widget = None):
        super(BlinkYourEyesWidget, self).__init__()
        # Avoid this window appearing from alt-tab window selection
        # see the followings:
        # https://stackoverflow.com/questions/3553428/how-can-i-prevent-gnome-from-showing-two-windows-when-doing-alt-tab-c-qt-app
        # https://doc.qt.io/qt-5/qt.html#WindowType-enum
        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint|QtCore.Qt.FramelessWindowHint
                |QtCore.Qt.Tool)
        #self.setAttribute(Qt.Qt.WA_NoSystemBackground)
        #self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setWindowOpacity(0.8)

        #self.setFocusPolicy(QtCore.Qt.NoFocus)
        #self.setStyleSheet("background-color:transparent;")

        self.background_color = QtCore.Qt.black
        self.timer_count = 0
        self.timer = QtCore.QTimer()
        self.timer.setInterval(100)  # [milliseconds]
        self.timer.timeout.connect(self.timer_callback)

        self.initUI()
        self.timer.start()

        self.dragmode = None
        self.dragstartpos = None
        self.dragstartgeom = None

        if platform.system() == 'Linux':
            ewmh = EWMH()
            all_wins = ewmh.getClientList()
            wins = filter(lambda w: 'blinkyoureyes' in w.get_wm_class()[1], all_wins)
            for w in wins:
                ewmh.setWmDesktop(w, 0xffffffff)
            ewmh.display.flush()
Example #4
0
def count_on_current_ws(ignored_classes: List[str], ewmh: EWMH) -> int:
    """
    Count the number of open windows on the current workspace.

    Windows with a class in the given ignore list, bad windows,
    or ones missing a _NET_WM_DESKTOP property are not counted.

    :param ignored_classes: A list of window classes to ignore
    :param ewmh: An instance of EWMH for workspace retrieval
    :return: The number of open windows on the workspace
    """
    window_count = 0

    all_windows = ewmh.getClientList()
    windows_on_ws = [
        w for w in all_windows
        if get_workspace(w, ewmh) == ewmh.getCurrentDesktop()
    ]

    for window in windows_on_ws:
        try:
            window_class = window.get_wm_class()
        except Xlib.error.BadWindow:
            logging.info('Ignoring bad window (id: %s)', window.id)
            continue

        if window_class is not None and window_class[1] in ignored_classes:
            logging.info("Ignoring window with class '%s'.", window_class[1])
            continue

        window_count += 1

    return window_count
Example #5
0
r = redis.Redis(host='localhost', port=6379, db=0)

if args.init:
    desktops_map = prepare_desktops_map()
    if not desktops_map:
        sys.exit(128)
    r.set("xserver/desktops_map", json.dumps(desktops_map))
    sys.exit(0)

desktops_map = json.loads(r.get("xserver/desktops_map"))
window_rules = json.loads(r.get("xserver/window_rules"))

ewmh = EWMH()
NET_WM_NAME = ewmh.display.intern_atom('_NET_WM_NAME')
UTF8_STRING = ewmh.display.intern_atom('UTF8_STRING')
windows = ewmh.getClientList()

for window in sorted(
        windows,
        key=lambda w: w.get_full_text_property(NET_WM_NAME, UTF8_STRING)):
    similarities = {}
    rule = None
    desktop_name = None
    print("================================")
    window_title = window.get_full_text_property(NET_WM_NAME, UTF8_STRING)
    window_class = window.get_wm_class()[1]
    if args.verbosity >= 1:
        print(f"window ({window_class}): {window_title}")
    for tokens in window_rules.keys():
        ratio = fuzz.token_set_ratio(" ".join(tokens.split()[1:]),
                                     window_title,
Example #6
0
from ewmh import EWMH

ewmh = EWMH()


def filter_window(wins, windowclass):
    for w in wins:
        if w.get_wm_class()[1] == windowclass:
            return w


wins = ewmh.getClientList()

user_input = raw_input("Enter a Valid Input:")

diawin = filter_window(wins, 'Dia-normal')

ewmh.setActiveWindow(diawin)

if user_input == "1":
    ewmh.setWmState(diawin, 1, '_NET_WM_STATE_FULLSCREEN')

ewmh.display.flush()
Example #7
0
class Recorder:

    ID = {}
    QUEUE = {}

    def __init__(self, output: str, fps: float = 30.0):
        self._ewmh = EWMH()
        self._sct = None
        self._geometry = self._ewmh.getDesktopGeometry()
        self._writer = None
        self._output = output
        self._delay = 1.0 / fps
        self._fps = fps

        self._width = 0
        self._height = 0

        if not os.path.exists('recorded'):
            os.mkdir('recorded')

    async def record(self, wm_name: str):
        await self.__class__.wait(wm_name)
        asyncio.ensure_future(self._record(wm_name))

    @classmethod
    def fromCase(cls, case):
        return Recorder(cls.naming(case)).record

    @classmethod
    async def wait(cls, wm_name: str):
        # ID
        if wm_name not in cls.ID.keys():
            cls.ID[wm_name] = max([0, *cls.ID.values()])
        _id = cls.ID[wm_name]
        # wait by ID
        while (_id in cls.QUEUE.keys()) or (_id > len(cls.QUEUE)):
            await asyncio.sleep(0.1)
        cls.QUEUE[wm_name] = {
            'top': 0,
            'left': 0,
            'width': 0,
            'height': 0,
        }

    @classmethod
    async def signal(cls, wm_name: str):
        del cls.QUEUE[wm_name]

    @classmethod
    def naming(cls, case):
        def _shorten(name):
            # int
            if isinstance(name, float) and name % 1 == 0:
                return str(int(name))
            # maybe path
            if isinstance(name, str):
                return name.split('/')[-1]
            return str(name)

        return '_'.join(reversed([_shorten(c[1]) for c in case]))

    async def _record(self, wm_name: str):
        begin, tick = datetime.now(), 0
        tracking = False
        await asyncio.sleep(1)
        while True:
            ts_last = datetime.now()
            # retrieve
            try:
                frames = [
                    w for w in self._ewmh.getClientList()
                    if wm_name in (w.get_wm_name() or '')
                ]
                if len(frames) != 1:
                    if len(frames) > 1:
                        print(
                            '-' * 36 + '\n' +
                            f'!  {len(frames)} windows have been captured.\n' +
                            '.\n'.join(f'| {self._ewmh.getWmName(w).decode()}'
                                       for w in frames) + '\n' + ('-' * 36))
                        break
                    if tracking:
                        break
                    await asyncio.sleep(self._delay / 2)
                    continue
                # the only frame
                bbox = self._get_frame(frames[0]).get_geometry()
                monitor = {
                    'top': bbox.y,
                    'left': bbox.x,
                    'width': bbox.width,
                    'height': bbox.height
                }
            except Xlib.error.BadWindow:
                continue
            # move window
            if not tracking:
                tracking = True
                monitor = self._update_window(wm_name, monitor, frames[0])
                self._sct = mss.mss()
            if bbox.x + bbox.width > self._geometry[0]:
                monitor['width'] = self._geometry[0] - bbox.x
            if bbox.y + bbox.height > self._geometry[1]:
                monitor['height'] = self._geometry[1] - bbox.y
            img = np.array(self._sct.grab(monitor))
            img = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
            self._write(img, wm_name)
            # end
            tick += 1
            ts = datetime.now()
            await asyncio.sleep(
                max(
                    0,
                    self._delay *
                    (tick - (ts - begin).total_seconds() * self._fps) * 0.9))
        # flush
        self.__close__()
        await self.__class__.signal(wm_name)

    def _write(self, img, wm_name):
        height, width = img.shape[:2]
        if self._writer is None or self._width != width or self._height != height:
            fourcc = cv2.VideoWriter_fourcc(*'FMP4')
            self._writer = cv2.VideoWriter(
                f'recorded/{self._output}-{"_".join(wm_name.lower().split(" "))}.avi',
                fourcc, self._fps, (width, height), False)
            self._width, self._height = width, height
        self._writer.write(img)

    def _get_frame(self, client):
        frame = client
        while frame.query_tree().parent != self._ewmh.root:
            frame = frame.query_tree().parent
        return frame

    def _update_window(self, wm_name, monitor, frame):
        width = sum(m['width'] for m in self.__class__.QUEUE.values())
        monitor['left'] = width
        monitor['top'] = 0
        if frame.get_wm_class() is None:
            w, h = monitor['width'], monitor['height']
        else:
            w, h = 0, None
        # TODO 2-d replacement
        self.__class__.QUEUE[wm_name] = monitor
        self._ewmh.setMoveResizeWindow(frame,
                                       x=monitor['left'],
                                       y=monitor['top'],
                                       w=w,
                                       h=h)
        self._ewmh.display.flush()
        return monitor

    def __close__(self):
        if hasattr(self, '_writer') and self._writer is not None:
            self._writer.release()
            self._writer = None
        if hasattr(self, '_sct') and self._sct is not None:
            self._sct.close()
            self._sct = None

    def __del__(self):
        self.__close__()
Example #8
0
import classes.Window as Window
from ewmh import EWMH
from Xlib.display import Display

import time

ewmh = EWMH()

NewWindow = Window.Window

windows = []
try:
    for window in ewmh.getClientList():
        if ewmh.getWmDesktop(window) == 2:
            windows.append(window)
except (TypeError):
    pass

display = Display()

window = NewWindow()
data = windows[0].get_geometry()
print(data)
window.init(display, windows[0], data.x, data.y, data.width, data.height)
window.debug()
window.set(300, 300, 200, 200)
window.set_last_update()
window.debug()
while True:
    time.sleep(0.1)
    window.update()
Example #9
0
class BaseWidget(Toplevel):
    def __init__(self, name, master=None, **kw):
        """
        Create a  desktop widget that sticks on the desktop.
        """
        Toplevel.__init__(self, master)
        self.name = name
        if CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.attributes('-type', 'splash')
        else:
            self.attributes('-type', 'toolbar')

        self.style = Style(self)

        self._position = StringVar(self, CONFIG.get(self.name, 'position'))
        self._position.trace_add(
            'write',
            lambda *x: CONFIG.set(self.name, 'position', self._position.get()))

        self.ewmh = EWMH()
        self.title('scheduler.{}'.format(self.name.lower()))

        self.withdraw()

        # control main menu checkbutton
        self.variable = BooleanVar(self, False)

        # --- menu
        self.menu = Menu(self, relief='sunken', activeborderwidth=0)
        self._populate_menu()

        self.create_content(**kw)

        self.x = None
        self.y = None

        # --- geometry
        geometry = CONFIG.get(self.name, 'geometry')
        self.update_idletasks()
        if geometry:
            self.geometry(geometry)
        self.update_idletasks()

        if CONFIG.getboolean(self.name, 'visible', fallback=True):
            self.show()

        # --- bindings
        self.bind('<Configure>', self._on_configure)

    def create_content(self):
        # to be overriden by subclass
        pass

    def _populate_menu(self):
        self.menu_pos = Menu(self.menu, relief='sunken', activeborderwidth=0)
        self.menu_pos.add_radiobutton(label=_('Normal'),
                                      value='normal',
                                      variable=self._position,
                                      command=self.show)
        self.menu_pos.add_radiobutton(label=_('Above'),
                                      value='above',
                                      variable=self._position,
                                      command=self.show)
        self.menu_pos.add_radiobutton(label=_('Below'),
                                      value='below',
                                      variable=self._position,
                                      command=self.show)
        self.menu.add_cascade(label=_('Position'), menu=self.menu_pos)
        self.menu.add_command(label=_('Hide'), command=self.hide)

    def update_style(self):
        bg = CONFIG.get(self.name, 'background', fallback='grey10')
        fg = CONFIG.get(self.name, 'foreground', fallback='white')
        active_bg = active_color(*self.winfo_rgb(bg))
        self.attributes('-alpha', CONFIG.get(self.name, 'alpha',
                                             fallback=0.85))
        self.configure(bg=bg)
        self.menu.configure(bg=bg,
                            fg=fg,
                            selectcolor=fg,
                            activeforeground=fg,
                            activebackground=active_bg)
        self.menu_pos.configure(bg=bg,
                                fg=fg,
                                selectcolor=fg,
                                activeforeground=fg,
                                activebackground=active_bg)

    def update_position(self):
        if self._position.get() == 'normal':
            if CONFIG.getboolean('General', 'splash_supported', fallback=True):
                self.attributes('-type', 'splash')
            else:
                self.attributes('-type', 'toolbar')
        if self.variable.get():
            self.withdraw()
            self.deiconify()

    def _on_configure(self, event):
        CONFIG.set(self.name, 'geometry', self.geometry())
        save_config()

    def hide(self):
        CONFIG.set(self.name, 'visible', 'False')
        self.variable.set(False)
        save_config()
        self.withdraw()

    def show(self):
        ''' make widget sticky '''
        self.deiconify()
        self.update_idletasks()
        splash_supp = CONFIG.getboolean('General',
                                        'splash_supported',
                                        fallback=True)
        try:
            pos = self._position.get()
            for w in self.ewmh.getClientList():
                if w.get_wm_name() == self.title():
                    if pos == 'above':
                        self.attributes('-type', 'dock')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY')
                        self.ewmh.setWmState(w, 1,
                                             '_NET_WM_STATE_SKIP_TASKBAR')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_PAGER')
                    elif pos == 'below':
                        self.attributes('-type', 'desktop')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_BELOW')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY')
                        self.ewmh.setWmState(w, 1,
                                             '_NET_WM_STATE_SKIP_TASKBAR')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_PAGER')
                    else:
                        if splash_supp:
                            self.attributes('-type', 'splash')
                        else:
                            self.attributes('-type', 'toolbar')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY')
                        self.ewmh.setWmState(w, 1,
                                             '_NET_WM_STATE_SKIP_TASKBAR')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_PAGER')
            self.ewmh.display.flush()
            if not splash_supp:
                self.withdraw()
                self.deiconify()
            CONFIG.set(self.name, 'visible', 'True')
            self.variable.set(True)
            save_config()
        except TypeError:
            pass

    def _start_move(self, event):
        self.x = event.x
        self.y = event.y

    def _stop_move(self, event):
        self.x = None
        self.y = None
        self.configure(cursor='arrow')

    def _move(self, event):
        if self.x is not None and self.y is not None:
            self.configure(cursor='fleur')
            deltax = event.x - self.x
            deltay = event.y - self.y
            x = self.winfo_x() + deltax
            y = self.winfo_y() + deltay
            self.geometry("+%s+%s" % (x, y))
Example #10
0
    def __init__(self):
        Tk.__init__(self, className="WorkHourGlass")
        self.on = False  # is the timer on?

        if not CONFIG.options("Tasks"):
            CONFIG.set("Tasks", _("Work"), CMAP[0])
        # colors
        self.background = {
            _("Work"): CONFIG.get("Work", "bg"),
            _("Break"): CONFIG.get("Break", "bg"),
            _("Rest"): CONFIG.get("Rest", "bg")
        }
        self.foreground = {
            _("Work"): CONFIG.get("Work", "fg"),
            _("Break"): CONFIG.get("Break", "fg"),
            _("Rest"): CONFIG.get("Rest", "fg")
        }
        # window configuration
        if PL[0] == "w":
            self.iconbitmap(ICON_WIN, default=ICON_WIN)
        else:
            self.icon = PhotoImage(master=self, file=ICON)
            self.iconphoto(True, self.icon)

        self.title("WorkHourGlass")
        self.protocol("WM_DELETE_WINDOW", self.exit)
        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.minsize(181, 190)
        self.geometry("200x190+%i+%i" %
                      ((self.winfo_screenwidth() - 200) // 2,
                       (self.winfo_screenheight() - 190) // 2))
        self.configure(background=self.background[_("Work")])

        # style
        self.style = Style(self)
        self.style.theme_use(STYLE)
        self.style.configure('fen.TLabel',
                             foreground=self.foreground[_("Work")],
                             background=self.background[_("Work")])

        # nombre de séquence de travail effectuées d'affilée (pour
        # faire des pauses plus longues tous les 4 cycles)
        self.nb_cycles = 0
        self.pomodori = IntVar(self, 0)

        # images
        self.im_go = PhotoImage(master=self, file=GO)
        self.im_stop = PhotoImage(master=self, file=STOP)
        self.im_plus = PhotoImage(master=self, file=PLUS)
        self.im_moins = PhotoImage(master=self, file=MOINS)
        self.im_params = PhotoImage(master=self, file=PARAMS)
        self.im_tomate = PhotoImage(master=self, file=TOMATE)
        self.im_graph = PhotoImage(master=self, file=GRAPH)

        # tasks list
        tasks_frame = Frame(self)
        tasks_frame.grid(row=3, column=0, columnspan=3, sticky="wnse")
        tasks = [t.capitalize() for t in CONFIG.options("Tasks")]
        self.task = StringVar(self, tasks[0])
        self.menu_tasks = Menu(tasks_frame, tearoff=False)
        for task in tasks:
            self.menu_tasks.add_radiobutton(label=task,
                                            value=task,
                                            variable=self.task)
        self.menu_tasks.add_command(label=_("New task"),
                                    image=self.im_plus,
                                    compound="left",
                                    command=self.add_task)
        self.menu_tasks.add_command(label=_("Remove task"),
                                    image=self.im_moins,
                                    compound="left",
                                    command=self.del_task)
        self.menu_tasks.add_command(label=_("Statistics"),
                                    image=self.im_graph,
                                    compound="left",
                                    command=self.display_stats)
        self.choose_task = Menubutton(tasks_frame,
                                      textvariable=self.task,
                                      menu=self.menu_tasks)
        Label(tasks_frame,
              text=_("Task: "),
              font="CMU\ Sans\ Serif\ Demi\ Condensed 12",
              width=6,
              anchor="e").pack(side="left")
        self.choose_task.pack(side="right", fill="x")

        # display
        self.tps = [CONFIG.getint("Work", "time"), 0]  # time: min, sec
        self.activite = StringVar(self, _("Work"))
        self.titre = Label(self,
                           textvariable=self.activite,
                           font='CMU\ Sans\ Serif\ Demi\ Condensed 14',
                           style='fen.TLabel',
                           anchor="center")
        self.titre.grid(row=0, column=0, columnspan=2, sticky="we")
        self.temps = Label(
            self,
            text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]),
            font="%s %i" % (CONFIG.get(
                "General", "font"), CONFIG.getint("General", "fontsize")),
            style='fen.TLabel',
            anchor="center")
        self.temps.grid(row=1,
                        column=0,
                        columnspan=2,
                        sticky="nswe",
                        pady=(0, 10))

        self.aff_pomodori = Label(self,
                                  textvariable=self.pomodori,
                                  image=self.im_tomate,
                                  compound="left",
                                  style='fen.TLabel',
                                  font='CMU\ Sans\ Serif\ Demi\ Condensed 14')
        self.aff_pomodori.grid(row=2, columnspan=2, sticky="e", padx=20)

        # buttons
        self.b_go = Button(self, image=self.im_go, command=self.go)
        self.b_go.grid(row=4, column=0, sticky="ew")
        self.b_params = Button(self, image=self.im_params, command=self.params)
        self.b_params.grid(row=4, column=1, sticky="ew")

        # --- make window sticky
        self.update_idletasks()
        e = EWMH()
        try:
            for w in e.getClientList():
                if w.get_wm_name() == self.title():
                    e.setWmState(w, 1, '_NET_WM_STATE_STICKY')
            e.display.flush()
        except ewmh.display.error.BadWindow:
            pass
Example #11
0
class MainWindow(QtWidgets.QMainWindow):
    config = Config()
    iface = config.getConfig('iface')
    version = config.getVersion()
    app = QtWidgets.QApplication(sys.argv)
    threadNetworkStats = ThreadNetworkStats()
    threadNvidia = ThreadNvidia()
    threadFast = ThreadFast()
    threadSlow = ThreadSlow()
    threadweather = ThreadWeather()
    partitionsWidgets = []
    upDownRateWidgets = []
    diskWidgets = []
    dtwWidgets = dict()
    systemWidgets = dict()
    nvidiaWidgets = list()
    verticalLayout = QtWidgets.QVBoxLayout()
    weather = Weather()
    debugRed = 'background-color: rgb(255, 48, 79);'
    nvidia = Nvidia()
    smart = Smart()
    pbDefaultHeight = 20
    tempLabelWidth = 50

    def __init__(self):
        super(MainWindow, self).__init__()
        logger.info('Starting...')
        # -------------------------------------------------------------
        # Window Flags
        flags = QtCore.Qt.FramelessWindowHint
        flags |= QtCore.Qt.WindowStaysOnBottomHint
        flags |= QtCore.Qt.Tool
        # -------------------------------------------------------------
        # Styles
        self.groupBoxStyle = """
        QGroupBox {
            border: 1px solid white;
            border-radius: 5px;
            margin-top: 12px;
            padding-left: 2px;
        }
        QGroupBox:title {
            subcontrol-origin: margin;
            subcontrol-position: top left;
            color: rgb(252, 126, 0);
            left: 15px;
        }
        """
        self.redPBStyle = """
        QProgressBar {
            text-align: left;
            font-weight: bold;
            color: rgb(255, 255, 255);
            background-color : rgba(0, 0, 0, 0);
            border: 0px solid rgba(0, 0, 0, 0);
            border-radius: 3px;                                    
        }
        QProgressBar::chunk {
            background: rgb(255, 51, 0);
            border-radius: 3px;            
        }
        """
        self.greenPBStyle = """
        QProgressBar {
            text-align: left;
            font-weight: bold;
            color: rgb(255, 255, 255);
            background-color : rgba(0, 0, 0, 0);
            border: 0px solid rgba(0, 0, 0, 0);
            border-radius: 3px;           
        }
        QProgressBar::chunk {
            background: rgb(51, 153, 51);
            border-radius: 3px;            
        }
        """
        self.orange = 'color: rgb(252, 126, 0);'
        self.white = 'color: rgb(255, 255, 255);'
        self.green = 'color: rgb(34, 255, 19);'
        self.red = 'color: rgb(255, 48, 79);'

        # ---------------------------------------------------------------------
        # Default font
        self.fontDefault = QtGui.QFont('Fira Code', 11)
        self.fontGroupBox = QtGui.QFont('Fira Code', 14)
        # -------------------------------------------------------------
        self.verticalLayout.setAlignment(QtCore.Qt.AlignTop)
        # --------------------------------------------------------------
        self.setWindowFlags(flags)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        # Connect Threads Signals
        self.threadFast.signal.connect(self.receiveThreadFastfinish)
        self.threadSlow.signal.connect(self.receiveThreadSlowFinish)
        self.threadNetworkStats.signal.connect(self.receiveThreadNetworkStats)
        self.threadweather.signal.connect(self.receiveThreadWeatherFinish)
        self.threadNvidia.signal.connect(self.receiveThreadNvidia)
        centralWidGet = QtWidgets.QWidget(self)
        centralWidGet.setLayout(self.verticalLayout)
        self.setCentralWidget(centralWidGet)
        # -----------------------------------------------------------------------------------------------
        # before show main window, check all dependencies and refuse if any thing wrong
        self.checkDependencies()
        #
        self.show()
        # Show in all workspaces
        self.ew = EWMH()
        self.all_wins = self.ew.getClientList()
        self.wins = filter(lambda wHandle: wHandle.get_wm_class()[1] == 'gonha', self.all_wins)
        for w in self.wins:
            self.ew.setWmDesktop(w, 0xffffffff)

        self.ew.display.flush()

        self.threadFast.start()
        self.threadSlow.start()
        self.threadNetworkStats.start()

        self.loadPosition()
        self.displayDTWeather()
        self.displaySystem()
        if self.nvidia.getStatus():
            self.displayNvidia()

        self.displayIface()
        self.displayPartitions()

    def checkDependencies(self):
        # ------------------------------------------------------------------------
        # Check if user need update config file
        oldVersion = self.config.getConfig('version')
        if self.config.getVersion() != oldVersion:
            dialog = Alert('You need run "gonha --config" on terminal')
            dialog.exec_()
            sys.exit()
        # ------------------------------------------------------------------------
        # check for hddtemp
        if not self.smart.hddtempIsOk():
            dialog = Alert(
                'You need run hddtemp as daemon. Please read the README.md (install instructions)')
            dialog.exec_()
            sys.exit()

        # Check Kernel dependencies only run in kernel >=5.5
        kernel = self.config.getKernelInfo()
        if not ((kernel['kernelVersion'] >= 5) and (kernel['majorRevision'] >= 5)):
            dialog = Alert(
                'You are running kernel version unsupported. Please, upgrade your kernel to version 5.5.x or latest')
            dialog.exec_()
            sys.exit()

    def getDefaultGb(self, title):
        defaultGb = QtWidgets.QGroupBox(title)
        defaultGb.setFont(self.fontGroupBox)
        defaultGb.setStyleSheet(self.groupBoxStyle)
        return defaultGb

    def displayNvidia(self):
        gpuMessage = self.nvidia.getDeviceHealth()

        nvidiaGroupBox = self.getDefaultGb('nvidia')
        verticalLayout = QtWidgets.QVBoxLayout()
        # ---------------------------------------------------
        # nvidia data
        nvidiaHBLayout = QtWidgets.QHBoxLayout()

        nvidiaLabel = QtWidgets.QLabel()
        nvidiaLabel.setPixmap(QtGui.QPixmap(f"{self.config.resource_path}/images/nvidia.png"))
        nvidiaLabel.setFixedWidth(64)
        nvidiaHBLayout.addWidget(nvidiaLabel)

        infoVLayout = QtWidgets.QVBoxLayout()
        infoVLayout.setSpacing(0)
        infoVLayout.setAlignment(QtCore.Qt.AlignVCenter)
        for gpu in gpuMessage:
            tempDict = dict()
            infoHLayout = QtWidgets.QHBoxLayout()

            nameLabel = QtWidgets.QLabel(gpu['name'])
            tempDict['name'] = nameLabel
            nameLabel.setFixedWidth(240)
            nameLabel.setAlignment(QtCore.Qt.AlignLeft)
            self.setLabel(nameLabel, self.white, self.fontDefault)
            infoHLayout.addWidget(nameLabel)

            loadLabel = QtWidgets.QLabel('load:')
            loadLabel.setAlignment(QtCore.Qt.AlignRight)
            self.setLabel(loadLabel, self.orange, self.fontDefault)
            infoHLayout.addWidget(loadLabel)

            loadValueLabel = QtWidgets.QLabel(f"{gpu['load']}%")
            tempDict['load'] = loadValueLabel
            loadValueLabel.setAlignment(QtCore.Qt.AlignRight)
            self.setLabel(loadValueLabel, self.white, self.fontDefault)
            infoHLayout.addWidget(loadValueLabel)

            infoVLayout.addLayout(infoHLayout)

            mtempHLayout = QtWidgets.QHBoxLayout()
            mtempHLayout.setAlignment(QtCore.Qt.AlignLeft)

            memoryLabel = QtWidgets.QLabel('memory:')
            memoryLabel.setFixedWidth(70)
            self.setLabel(memoryLabel, self.orange, self.fontDefault)
            mtempHLayout.addWidget(memoryLabel)

            usedTotalMemLabel = QtWidgets.QLabel(f"{gpu['memoryUsed']}MB/{gpu['memoryTotal']}MB")
            tempDict['usedTotalMemory'] = usedTotalMemLabel
            self.setLabel(usedTotalMemLabel, self.white, self.fontDefault)
            mtempHLayout.addWidget(usedTotalMemLabel)
            mtempHLayout.addStretch(2)

            tempIcon = QtWidgets.QLabel()
            tempIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/temp.png'))
            tempIcon.setFixedHeight(24)
            tempIcon.setFixedWidth(24)
            mtempHLayout.addWidget(tempIcon)

            tempLabel = QtWidgets.QLabel(f"{int(gpu['temp'])}°{gpu['scale']}")
            tempDict['temp'] = tempLabel
            self.setLabel(tempLabel, self.white, self.fontDefault)
            tempLabel.setAlignment(QtCore.Qt.AlignRight)
            tempLabel.setFixedWidth(self.tempLabelWidth)
            mtempHLayout.addWidget(tempLabel)

            infoVLayout.addLayout(mtempHLayout)
            self.nvidiaWidgets.append(tempDict)

        nvidiaHBLayout.addLayout(infoVLayout)
        verticalLayout.addLayout(nvidiaHBLayout)

        nvidiaGroupBox.setLayout(verticalLayout)
        self.verticalLayout.addWidget(nvidiaGroupBox)
        self.threadNvidia.start()

    def displayIface(self):
        ifaceGroupBox = self.getDefaultGb('net')
        verticalLayout = QtWidgets.QVBoxLayout()
        # ---------------------------------------------------
        # Ip int Label
        ipintHBLayout = QtWidgets.QHBoxLayout()

        intipLabel = QtWidgets.QLabel('int. IP:')
        self.setLabel(intipLabel, self.orange, self.fontDefault)

        ipintHBLayout.addWidget(intipLabel)

        # ip int value label
        intipValueLabel = QtWidgets.QLabel('')
        self.setLabel(intipValueLabel, self.white, self.fontDefault)
        self.systemWidgets['intip'] = intipValueLabel

        ipintHBLayout.addWidget(intipValueLabel)

        # Ext Ip
        extipLabel = QtWidgets.QLabel('ext. IP:')
        self.setLabel(extipLabel, self.orange, self.fontDefault)

        ipintHBLayout.addWidget(extipLabel)

        extipValueLabel = QtWidgets.QLabel('')
        self.setLabel(extipValueLabel, self.white, self.fontDefault)
        self.systemWidgets['extip'] = extipValueLabel

        ipintHBLayout.addWidget(extipValueLabel)

        verticalLayout.addLayout(ipintHBLayout)
        # -------------------------------------------------
        horizontalLayout = QtWidgets.QHBoxLayout()

        netCardIcon = QtWidgets.QLabel()
        netCardIcon.setPixmap(QtGui.QPixmap(f"{self.config.resource_path}/images/netcard.png"))
        netCardIcon.setFixedSize(24, 24)
        horizontalLayout.addWidget(netCardIcon)

        # -------------------------------------------------
        # ifaceValueLabel
        ifaceValueLabel = QtWidgets.QLabel('')
        self.setLabel(ifaceValueLabel, self.white, self.fontDefault)
        ifaceValueLabel.setAlignment(QtCore.Qt.AlignLeft)
        self.upDownRateWidgets.append(ifaceValueLabel)
        horizontalLayout.addWidget(ifaceValueLabel)

        # -------------------------------------------------
        # Download Icon
        downloadIcon = QtWidgets.QLabel()
        downloadIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/download.png'))
        horizontalLayout.addWidget(downloadIcon)
        # -------------------------------------------------

        # ---------------------------------------------------
        # download rate label
        ifaceDownRateLabel = QtWidgets.QLabel('')
        self.setLabel(ifaceDownRateLabel, self.white, self.fontDefault)
        ifaceDownRateLabel.setAlignment(QtCore.Qt.AlignRight)
        ifaceDownRateLabel.setFixedWidth(110)
        self.upDownRateWidgets.append(ifaceDownRateLabel)
        horizontalLayout.addWidget(ifaceDownRateLabel)
        # ---------------------------------------------------

        # -------------------------------------------------
        # Upload Icon
        uploadIcon = QtWidgets.QLabel()
        uploadIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/upload.png'))
        horizontalLayout.addWidget(uploadIcon)
        # -------------------------------------------------

        # ---------------------------------------------------
        # upload rate label
        ifaceUpRateLabel = QtWidgets.QLabel('')
        self.setLabel(ifaceUpRateLabel, self.white, self.fontDefault)
        ifaceUpRateLabel.setAlignment(QtCore.Qt.AlignRight)
        ifaceUpRateLabel.setFixedWidth(110)
        self.upDownRateWidgets.append(ifaceUpRateLabel)
        horizontalLayout.addWidget(ifaceUpRateLabel)

        verticalLayout.addLayout(horizontalLayout)
        # ---------------------------------------------------

        # Total in
        bytesSentRcvHLayout = QtWidgets.QHBoxLayout()

        bytesRcvLabel = QtWidgets.QLabel('total in:')
        self.setLabel(bytesRcvLabel, self.orange, self.fontDefault)
        bytesSentRcvHLayout.addWidget(bytesRcvLabel)

        bytesRcvValueLabel = QtWidgets.QLabel('')
        self.setLabel(bytesRcvValueLabel, self.white, self.fontDefault)
        bytesRcvValueLabel.setAlignment(QtCore.Qt.AlignRight)
        self.upDownRateWidgets.append(bytesRcvValueLabel)
        bytesSentRcvHLayout.addWidget(bytesRcvValueLabel)

        # Total out
        bytesSentLabel = QtWidgets.QLabel('total out:')
        self.setLabel(bytesSentLabel, self.orange, self.fontDefault)
        bytesSentRcvHLayout.addWidget(bytesSentLabel)

        bytesSentValueLabel = QtWidgets.QLabel('')
        self.setLabel(bytesSentValueLabel, self.white, self.fontDefault)
        bytesSentValueLabel.setAlignment(QtCore.Qt.AlignRight)
        self.upDownRateWidgets.append(bytesSentValueLabel)
        bytesSentRcvHLayout.addWidget(bytesSentValueLabel)

        verticalLayout.addLayout(bytesSentRcvHLayout)

        ifaceGroupBox.setLayout(verticalLayout)
        self.verticalLayout.addWidget(ifaceGroupBox)

    def displayDTWeather(self):
        countries = dict(countries_for_language('en'))
        timeHeight = 50
        dateHeight = 25
        tempHeight = 60

        timeFont = QtGui.QFont('Fira Code', 45)
        dayFont = QtGui.QFont('Fira Code', 20)
        weekdayFont = QtGui.QFont('Fira Code', 15)
        yearFont = QtGui.QFont('Fira Code', 12)
        monthFont = QtGui.QFont('Fira Code', 12)

        gray = 'color: rgb(143, 143, 143);'

        mainHBLayout = QtWidgets.QHBoxLayout()
        mainHBLayout.setSpacing(0)
        mainHBLayout.setAlignment(QtCore.Qt.AlignHCenter)

        # Horizontal Layout for time
        timeHBLayout = QtWidgets.QHBoxLayout()
        timeHBLayout.setAlignment(QtCore.Qt.AlignHCenter)

        twoPointLabel = [QtWidgets.QLabel(':'), QtWidgets.QLabel(':')]
        for label in twoPointLabel:
            label.setFont(timeFont)
            label.setStyleSheet(gray)
            label.setFixedHeight(timeHeight)

        hourLabel = QtWidgets.QLabel('22')
        self.setLabel(hourLabel, self.white, timeFont)
        hourLabel.setFixedHeight(timeHeight)
        self.dtwWidgets['hour'] = hourLabel

        minLabel = QtWidgets.QLabel('24')
        self.setLabel(minLabel, self.white, timeFont)
        minLabel.setFixedHeight(timeHeight)
        self.dtwWidgets['min'] = minLabel

        timeHBLayout.addWidget(hourLabel)
        timeHBLayout.addWidget(twoPointLabel[0])
        timeHBLayout.addWidget(minLabel)

        self.dtwWidgets['hour'] = hourLabel
        self.dtwWidgets['min'] = minLabel

        mainHBLayout.addLayout(timeHBLayout)

        # date vertical layout
        dateVBLayout = QtWidgets.QVBoxLayout()
        # date horizontal layout
        dateHBLayout = QtWidgets.QHBoxLayout()
        dateHBLayout.setAlignment(QtCore.Qt.AlignLeft)

        dayLabel = QtWidgets.QLabel('05')
        self.setLabel(dayLabel, self.orange, dayFont)
        dayLabel.setFixedHeight(dateHeight)

        monthLabel = QtWidgets.QLabel('June')
        self.setLabel(monthLabel, self.orange, monthFont)
        monthLabel.setFixedHeight(dateHeight)
        monthLabel.setAlignment(QtCore.Qt.AlignBottom)

        yearLabel = QtWidgets.QLabel('2020')
        yearLabel.setFont(yearFont)
        yearLabel.setStyleSheet(self.white)
        self.setLabel(yearLabel, self.orange, yearFont)
        yearLabel.setFixedHeight(dateHeight)
        yearLabel.setAlignment(QtCore.Qt.AlignBottom)

        dateHBLayout.addWidget(dayLabel)
        dateHBLayout.addWidget(monthLabel)
        dateHBLayout.addWidget(yearLabel)
        self.dtwWidgets['day'] = dayLabel
        self.dtwWidgets['month'] = monthLabel
        self.dtwWidgets['year'] = yearLabel

        dateVBLayout.addLayout(dateHBLayout)

        weekdayHBLayout = QtWidgets.QHBoxLayout()

        weekdayLabel = QtWidgets.QLabel('Saturday')
        self.setLabel(weekdayLabel, self.orange, weekdayFont)
        weekdayLabel.setFixedHeight(20)

        weekdayHBLayout.addWidget(weekdayLabel)
        self.dtwWidgets['weekday'] = weekdayLabel

        dateVBLayout.addLayout(weekdayHBLayout)

        mainHBLayout.addLayout(dateVBLayout)

        # --------------------------------------------------------
        # weather conditions

        weatherHBLayout = QtWidgets.QHBoxLayout()

        weatherVBLayout = QtWidgets.QVBoxLayout()
        weatherVBLayout.setSpacing(0)
        weatherVBLayout.setAlignment(QtCore.Qt.AlignVCenter)

        tempLabel = QtWidgets.QLabel('')
        self.setLabel(tempLabel, self.white, timeFont)
        tempLabel.setFixedHeight(tempHeight)
        self.dtwWidgets['temp'] = tempLabel

        weatherHBLayout.addWidget(tempLabel)

        # Cloud Icon
        cloudIconLabel = QtWidgets.QLabel()
        cloudIconLabel.setFixedHeight(42)
        cloudIconLabel.setFixedHeight(tempHeight)
        self.dtwWidgets['cloudicon'] = cloudIconLabel

        weatherHBLayout.addWidget(cloudIconLabel)
        weatherHBLayout.setAlignment(QtCore.Qt.AlignHCenter)

        cityRegionLabel = QtWidgets.QLabel(
            f"{self.config.getConfig('location')['city']}")
        self.setLabel(cityRegionLabel, self.orange, self.fontDefault)

        countryLabel = QtWidgets.QLabel(countries[self.config.getConfig('location')['country']])
        self.setLabel(countryLabel, self.orange, self.fontDefault)

        weatherVBLayout.addWidget(cityRegionLabel)
        weatherVBLayout.addWidget(countryLabel)

        weatherHBLayout.addLayout(weatherVBLayout)
        # ---------------------------------------------------------------------
        # humidity, pressure, visibility,  wind,
        weatherGridLayout = QtWidgets.QGridLayout()
        weatherGridLayout.setSpacing(0)

        # humidityIcon
        humidityIcon = QtWidgets.QLabel()
        humidityIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/humidity.png'))
        humidityIcon.setFixedWidth(32)

        pressureIcon = QtWidgets.QLabel()
        pressureIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/pressure.png'))
        pressureIcon.setFixedWidth(32)

        visibilityIcon = QtWidgets.QLabel()
        visibilityIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/visibility.png'))
        visibilityIcon.setFixedWidth(32)

        windIcon = QtWidgets.QLabel()
        windIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/wind.png'))
        windIcon.setFixedWidth(32)

        weatherGridLayout.addWidget(humidityIcon, 0, 0, 1, 1, QtCore.Qt.AlignHCenter)
        weatherGridLayout.addWidget(pressureIcon, 0, 1, 1, 1, QtCore.Qt.AlignHCenter)
        weatherGridLayout.addWidget(visibilityIcon, 0, 2, 1, 1, QtCore.Qt.AlignHCenter)
        weatherGridLayout.addWidget(windIcon, 0, 3, 1, 1, QtCore.Qt.AlignHCenter)
        # ---------------------------------------------------------------------

        humidityLabel = QtWidgets.QLabel('')
        self.setLabel(humidityLabel, self.white, self.fontDefault)
        self.dtwWidgets['humidity'] = humidityLabel

        pressureLabel = QtWidgets.QLabel('')
        self.setLabel(pressureLabel, self.white, self.fontDefault)
        self.dtwWidgets['pressure'] = pressureLabel

        visibilityLabel = QtWidgets.QLabel('')
        self.setLabel(visibilityLabel, self.white, self.fontDefault)
        self.dtwWidgets['visibility'] = visibilityLabel

        windLabel = QtWidgets.QLabel('')
        self.setLabel(windLabel, self.white, self.fontDefault)
        self.dtwWidgets['wind'] = windLabel

        weatherGridLayout.addWidget(humidityLabel, 1, 0, 1, 1, QtCore.Qt.AlignHCenter)
        weatherGridLayout.addWidget(pressureLabel, 1, 1, 1, 1, QtCore.Qt.AlignHCenter)
        weatherGridLayout.addWidget(visibilityLabel, 1, 2, 1, 1, QtCore.Qt.AlignHCenter)
        weatherGridLayout.addWidget(windLabel, 1, 3, 1, 1, QtCore.Qt.AlignHCenter)

        self.verticalLayout.addLayout(mainHBLayout)
        self.verticalLayout.addLayout(weatherHBLayout)
        self.verticalLayout.addLayout(weatherGridLayout)
        self.threadweather.updateWeather()

    def displaySystem(self):
        labelDefaultWidth = 80
        labelDefaultHeight = 15
        labelDefaultAlignment = QtCore.Qt.AlignRight
        pbDefaultWidth = 180
        systemGroupBox = self.getDefaultGb('system')

        verticalLayout = QtWidgets.QVBoxLayout()
        verticalLayout.setSpacing(0)

        # distro Label
        distroJson = self.config.getConfig('distro')
        distroStr = f"{distroJson['name']} {distroJson['version']}"
        if not distroJson['codename'] == '':
            distroStr = f"{distroStr} {distroJson['codename']}"

        # ---------------------------------------------------------------------------
        distroHBLayout = QtWidgets.QHBoxLayout()
        distroHBLayout.setAlignment(QtCore.Qt.AlignHCenter)
        distroVBLayout = QtWidgets.QVBoxLayout()
        distroVBLayout.setSpacing(0)

        distroIcon = QtWidgets.QLabel()
        distroIcon.setPixmap(QtGui.QPixmap(distroJson['iconfile']))
        distroIcon.setFixedHeight(64)

        distroHBLayout.addWidget(distroIcon)
        # ---------------------------------------------------------------------------
        # Distro label
        distroLabel = QtWidgets.QLabel(distroStr)
        self.setLabel(distroLabel, self.white, self.fontDefault)
        distroLabel.setFixedHeight(labelDefaultHeight)
        # ---------------------------------------------------------------------------
        # kernel label
        platJson = self.config.getConfig('platform')
        kernelLabel = QtWidgets.QLabel(f"Kernel {platJson['release']}")
        self.setLabel(kernelLabel, self.white, self.fontDefault)
        kernelLabel.setFixedHeight(labelDefaultHeight)
        # ---------------------------------------------------------------------------
        # Machine Label
        machineLabel = QtWidgets.QLabel(f"node {platJson['node']} arch {platJson['machine']}")
        self.setLabel(machineLabel, self.white, self.fontDefault)
        machineLabel.setFixedHeight(labelDefaultHeight)
        # ---------------------------------------------------------------------------
        distroVBLayout.addWidget(distroLabel)
        distroVBLayout.addWidget(kernelLabel)
        distroVBLayout.addWidget(machineLabel)

        distroHBLayout.addLayout(distroVBLayout)

        verticalLayout.addLayout(distroHBLayout)
        # ---------------------------------------------------------------------------
        # boot time label
        bootTimeHboxLayout = QtWidgets.QHBoxLayout()

        bootTimeValueLabel = QtWidgets.QLabel()
        self.setLabel(bootTimeValueLabel, self.white, self.fontDefault)
        self.systemWidgets['boottime'] = bootTimeValueLabel

        bootTimeValueLabel.setAlignment(QtCore.Qt.AlignCenter)

        bootTimeHboxLayout.addWidget(bootTimeValueLabel)

        verticalLayout.addLayout(bootTimeHboxLayout)
        # ---------------------------------------------------------------------------
        cpuHBLayout = QtWidgets.QHBoxLayout()

        cpuBrandLabel = QtWidgets.QLabel(self.config.getConfig('cpuinfo'))
        self.setLabel(cpuBrandLabel, self.white, self.fontDefault)
        cpuBrandLabel.setAlignment(QtCore.Qt.AlignHCenter)
        cpuHBLayout.addWidget(cpuBrandLabel)

        verticalLayout.addLayout(cpuHBLayout)

        # Cpu load
        cpuLoadHBLayout = QtWidgets.QHBoxLayout()

        cpuIcon = QtWidgets.QLabel()
        cpuIcon.setPixmap(QtGui.QPixmap(f"{self.config.resource_path}/images/cpu.png"))
        cpuIcon.setFixedSize(labelDefaultWidth, 24)
        cpuLoadHBLayout.addWidget(cpuIcon)

        cpuProgressBar = QtWidgets.QProgressBar()
        cpuProgressBar.setFixedHeight(self.pbDefaultHeight)
        cpuProgressBar.setFixedWidth(pbDefaultWidth)
        cpuProgressBar.setFont(self.fontDefault)
        cpuProgressBar.setStyleSheet(self.greenPBStyle)
        cpuProgressBar.setValue(12)
        self.systemWidgets['cpuProgressBar'] = cpuProgressBar

        cpuLoadHBLayout.addWidget(cpuProgressBar)

        cpuFreqLabel = QtWidgets.QLabel('14343.34 Mhz')
        cpuFreqLabel.setAlignment(labelDefaultAlignment)
        self.setLabel(cpuFreqLabel, self.white, self.fontDefault)
        self.systemWidgets['cpufreq'] = cpuFreqLabel

        cpuLoadHBLayout.addWidget(cpuFreqLabel)

        verticalLayout.addLayout(cpuLoadHBLayout)

        # ---------------------------------------------------------------------------
        # ram load
        ramLoadHBLayout = QtWidgets.QHBoxLayout()

        ramIcon = QtWidgets.QLabel()
        ramIcon.setPixmap(QtGui.QPixmap(f"{self.config.resource_path}/images/ram.png"))
        ramIcon.setFixedSize(labelDefaultWidth, 24)
        ramLoadHBLayout.addWidget(ramIcon)

        ramProgressBar = QtWidgets.QProgressBar()
        ramProgressBar.setFixedHeight(self.pbDefaultHeight)
        ramProgressBar.setFixedWidth(pbDefaultWidth)
        ramProgressBar.setFont(self.fontDefault)
        ramProgressBar.setStyleSheet(self.greenPBStyle)
        self.systemWidgets['ramProgressBar'] = ramProgressBar
        ramProgressBar.setValue(32)

        ramLoadHBLayout.addWidget(ramProgressBar)

        ramUsedLabel = QtWidgets.QLabel('15443 MB')
        ramUsedLabel.setAlignment(labelDefaultAlignment)
        self.setLabel(ramUsedLabel, self.white, self.fontDefault)
        self.systemWidgets['ramused'] = ramUsedLabel

        ramLoadHBLayout.addWidget(ramUsedLabel)

        verticalLayout.addLayout(ramLoadHBLayout)
        # ---------------------------------------------------------------------------
        # swap load
        swapHBLayout = QtWidgets.QHBoxLayout()

        swapIcon = QtWidgets.QLabel()
        swapIcon.setPixmap(QtGui.QPixmap(f"{self.config.resource_path}/images/swap.png"))
        swapIcon.setFixedSize(labelDefaultWidth, 24)

        swapHBLayout.addWidget(swapIcon)

        swapProgressBar = QtWidgets.QProgressBar()
        swapProgressBar.setFixedHeight(self.pbDefaultHeight)
        swapProgressBar.setFixedWidth(pbDefaultWidth)
        swapProgressBar.setFont(self.fontDefault)
        swapProgressBar.setStyleSheet(self.greenPBStyle)
        self.systemWidgets['swapProgressBar'] = swapProgressBar
        swapProgressBar.setValue(52)

        swapHBLayout.addWidget(swapProgressBar)

        swapUsedLabel = QtWidgets.QLabel('16654 MB')
        swapUsedLabel.setAlignment(labelDefaultAlignment)
        self.setLabel(swapUsedLabel, self.white, self.fontDefault)
        self.systemWidgets['swapused'] = swapUsedLabel

        swapHBLayout.addWidget(swapUsedLabel)

        verticalLayout.addLayout(swapHBLayout)

        # ---------------------------------------------------------------------------
        # Temperature
        tempHBLayout = QtWidgets.QHBoxLayout()
        tempHBLayout.setAlignment(QtCore.Qt.AlignRight)
        # tempHBLayout.setSpacing(5)

        tempValueLabel = QtWidgets.QLabel('')
        self.systemWidgets['label'] = tempValueLabel
        self.setLabel(tempValueLabel, self.white, self.fontDefault)

        tempHBLayout.addWidget(tempValueLabel)

        tempIcon = QtWidgets.QLabel()
        tempIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/temp.png'))
        tempIcon.setFixedHeight(24)
        tempIcon.setFixedWidth(24)

        tempHBLayout.addWidget(tempIcon)

        tempCurrentValueLabel = QtWidgets.QLabel('30C')
        tempCurrentValueLabel.setFixedWidth(self.tempLabelWidth)
        tempCurrentValueLabel.setAlignment(QtCore.Qt.AlignRight)
        self.setLabel(tempCurrentValueLabel, self.white, self.fontDefault)
        self.systemWidgets['current'] = tempCurrentValueLabel

        tempHBLayout.addWidget(tempCurrentValueLabel)

        verticalLayout.addLayout(tempHBLayout)

        # ---------------------------------------------------------------------------
        systemGroupBox.setLayout(verticalLayout)
        self.verticalLayout.addWidget(systemGroupBox)

    def displayPartitions(self):
        mntPoints = self.threadSlow.getPartitions()
        diskGroupBox = self.getDefaultGb('disks')
        verticalLayout = QtWidgets.QVBoxLayout()
        verticalLayout.setSpacing(3)
        verticalLayout.setAlignment(QtCore.Qt.AlignTop)
        pbFixedWidth = 260
        labelAlignment = QtCore.Qt.AlignRight
        labelDefaultWidth = 80

        # Devices Health
        devices = self.smart.getDevicesHealth()
        for i, d in enumerate(devices):
            deviceHBLayout = QtWidgets.QHBoxLayout()

            ssdIcon = QtWidgets.QLabel()
            ssdIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/ssd.png'))
            ssdIcon.setFixedSize(20, 20)
            deviceHBLayout.addWidget(ssdIcon)

            deviceLabel = QtWidgets.QLabel(d['device'])
            deviceLabel.setFixedWidth(120)
            self.setLabel(deviceLabel, self.white, self.fontDefault)
            deviceHBLayout.addWidget(deviceLabel)

            deviceModelLabel = QtWidgets.QLabel(d['model'])
            deviceModelLabel.setFixedWidth(200)
            self.setLabel(deviceModelLabel, self.white, self.fontDefault)
            deviceHBLayout.addWidget(deviceModelLabel)

            tempIcon = QtWidgets.QLabel()
            tempIcon.setPixmap(QtGui.QPixmap(f'{self.config.resource_path}/images/temp.png'))
            tempIcon.setFixedHeight(20)
            tempIcon.setFixedWidth(20)
            deviceHBLayout.addWidget(tempIcon)

            deviceTempLabel = QtWidgets.QLabel(f"{d['temp']}")
            self.setLabel(deviceTempLabel, self.white, self.fontDefault)
            deviceTempLabel.setAlignment(QtCore.Qt.AlignRight)
            deviceTempLabel.setFixedWidth(self.tempLabelWidth)
            deviceHBLayout.addWidget(deviceTempLabel)

            deviceScaleLabel = QtWidgets.QLabel(f"°{d['scale']}")

            self.diskWidgets.append(
                {'device': deviceLabel, 'model': deviceModelLabel, 'temp': deviceTempLabel, 'scale': deviceScaleLabel})

            verticalLayout.addLayout(deviceHBLayout)

        for mntPoint in mntPoints:
            mountpointHorizontalLayout = QtWidgets.QHBoxLayout()

            # ------------- mountpoint ----------------------
            mountpointValueLabel = QtWidgets.QLabel(mntPoint['mountpoint'])
            self.setLabel(mountpointValueLabel, self.white, self.fontDefault)
            mountpointHorizontalLayout.addWidget(mountpointValueLabel)

            totalValueLabel = QtWidgets.QLabel(mntPoint['total'])
            self.setLabel(totalValueLabel, self.white, self.fontDefault)
            totalValueLabel.setAlignment(QtCore.Qt.AlignRight)
            mountpointHorizontalLayout.addWidget(totalValueLabel)

            verticalLayout.addLayout(mountpointHorizontalLayout)
            # ----------------------------------------------------------
            # used stats
            usedHorizontalLayout = QtWidgets.QHBoxLayout()
            usedLabel = QtWidgets.QLabel('used:')
            self.setLabel(usedLabel, self.orange, self.fontDefault)
            usedLabel.setFixedWidth(labelDefaultWidth)
            usedHorizontalLayout.addWidget(usedLabel)

            # ProgressBar
            usedPB = QtWidgets.QProgressBar()
            usedPB.setFixedHeight(self.pbDefaultHeight)
            usedPB.setFont(self.fontDefault)
            usedPB.setStyleSheet(self.redPBStyle)
            usedPB.setFixedWidth(pbFixedWidth)
            usedPB.setValue(mntPoint['percentUsed'])

            usedHorizontalLayout.addWidget(usedPB)

            usedValueLabel = QtWidgets.QLabel(mntPoint['used'])
            self.setLabel(usedValueLabel, self.white, self.fontDefault)
            usedValueLabel.setAlignment(labelAlignment)

            usedHorizontalLayout.addWidget(usedValueLabel)

            verticalLayout.addLayout(usedHorizontalLayout)
            # ----------------------------------------------------------
            # free stats
            freeHorizontalLayout = QtWidgets.QHBoxLayout()
            freeLabel = QtWidgets.QLabel('free:')
            self.setLabel(freeLabel, self.orange, self.fontDefault)
            freeLabel.setFixedWidth(labelDefaultWidth)
            freeHorizontalLayout.addWidget(freeLabel)

            freePB = QtWidgets.QProgressBar()
            freePB.setFixedHeight(self.pbDefaultHeight)
            freePB.setFont(self.fontDefault)
            freePB.setStyleSheet(self.greenPBStyle)
            freePB.setFixedWidth(pbFixedWidth)
            freePB.setAlignment(QtCore.Qt.AlignLeft)
            freePB.setValue(mntPoint['percentFree'])

            freeHorizontalLayout.addWidget(freePB)

            freeValueLabel = QtWidgets.QLabel(mntPoint['free'])
            self.setLabel(freeValueLabel, self.white, self.fontDefault)
            freeValueLabel.setAlignment(labelAlignment)
            freeHorizontalLayout.addWidget(freeValueLabel)

            verticalLayout.addLayout(freeHorizontalLayout)

            # ----------------------------------------------------------

            tempDict = dict()
            tempDict['mountpointValueLabel'] = mountpointValueLabel
            tempDict['totalValueLabel'] = totalValueLabel
            tempDict['usedValueLabel'] = usedValueLabel
            tempDict['usedPB'] = usedPB
            tempDict['freeValueLabel'] = freeValueLabel
            tempDict['freePB'] = freePB
            self.partitionsWidgets.append(tempDict)

        diskGroupBox.setLayout(verticalLayout)
        self.verticalLayout.addWidget(diskGroupBox)

    def loadPosition(self):
        # Adjust initial position
        if self.config.getConfig('position') == 'Top Left':
            self.moveTopLeft()
        else:
            self.moveTopRight()

    def contextMenuEvent(self, event: QtGui.QContextMenuEvent):
        contextMenu = QtWidgets.QMenu(self)
        quitAction = contextMenu.addAction('&Quit')
        action = contextMenu.exec_(self.mapToGlobal(event.pos()))
        if action == quitAction:
            sys.exit()

    def moveTopLeft(self):
        self.move(0, 10)

    def moveTopRight(self):
        screen = self.app.primaryScreen()
        logger.info('Screen: {}'.format(screen.name()))
        size = screen.size()
        logger.info('Screen Resolution: {} x {}'.format(size.width(), size.height()))
        rect = screen.availableGeometry()
        logger.info('Available space for gonha: {} x {}'.format(rect.width(), rect.height()))
        # move window to top right
        win = self.geometry()
        self.move(rect.width() - win.width(), 0)

    def receiveThreadSlowFinish(self, message):
        for i, msg in enumerate(message):
            self.partitionsWidgets[i]['mountpointValueLabel'].setText(msg['mountpoint'])
            self.partitionsWidgets[i]['totalValueLabel'].setText(msg['total'])
            self.partitionsWidgets[i]['usedValueLabel'].setText(msg['used'])
            self.partitionsWidgets[i]['usedPB'].setValue(msg['percentUsed'])
            self.partitionsWidgets[i]['freeValueLabel'].setText(msg['free'])
            self.partitionsWidgets[i]['freePB'].setValue(msg['percentFree'])

        if self.config.isOnline():
            ipaddrs = self.threadSlow.getIpAddrs()
            self.systemWidgets['intip'].setText(ipaddrs['intip'])
            self.systemWidgets['extip'].setText(ipaddrs['extip'])

    def receiveThreadFastfinish(self, message):

        self.dtwWidgets['hour'].setText(message['hour'])
        self.dtwWidgets['min'].setText(message['min'])
        # self.dtwWidgets['sec'].setText(message['sec'])
        self.dtwWidgets['day'].setText(f"{message['day']}")
        self.dtwWidgets['month'].setText(f", {message['month']} ")
        self.dtwWidgets['year'].setText(message['year'])
        self.dtwWidgets['weekday'].setText(message['weekday'])
        # --------------------------------------------------------
        # update cpu load
        self.systemWidgets['cpuProgressBar'].setValue(message['cpuProgressBar'])
        self.systemWidgets['ramProgressBar'].setValue(message['ramProgressBar'])
        self.systemWidgets['swapProgressBar'].setValue(message['swapProgressBar'])
        # ----------------------------
        # update  cpu temperature
        # print(message)
        self.systemWidgets['label'].setText(message['label'])
        self.systemWidgets['current'].setText(f"{int(message['current'])}°{message['scale']}")

        self.systemWidgets['cpufreq'].setText(f"{message['cpufreq']}/{message['cpufreqMax']} Mhz")
        self.systemWidgets['ramused'].setText(f"{message['ramused']}/{message['ramTotal']}")
        self.systemWidgets['swapused'].setText(f"{message['swapused']}/{message['swapTotal']}")

        self.systemWidgets['boottime'].setText(message['boottime'])

        self.analizeTemp(self.systemWidgets['current'], message['current'], message['high'], message['critical'])

        for i, d in enumerate(message['devices']):
            # print(d)
            self.diskWidgets[i]['device'].setText(d['device'])
            self.diskWidgets[i]['model'].setText(d['model'])
            self.diskWidgets[i]['temp'].setText(f"{int(d['temp'])}°{message['scale']}")
            self.analizeTemp(self.diskWidgets[i]['temp'], d['temp'], d['high'], d['critical'])

    def receiveThreadWeatherFinish(self, message):
        # logger.info(message)
        self.dtwWidgets['temp'].setText(f"{int(message['temp'])}°{message['scale']}")
        self.dtwWidgets['humidity'].setText(message['humidity'])
        self.dtwWidgets['pressure'].setText(message['pressure'])
        self.dtwWidgets['visibility'].setText(message['visibility'])
        self.dtwWidgets['wind'].setText(message['wind'])
        self.dtwWidgets['cloudicon'].setPixmap(message['icon'])

    @staticmethod
    def setLabel(label, labelcolor, font):
        label.setFont(font)
        label.setStyleSheet(labelcolor)

    def receiveThreadNetworkStats(self, message):
        self.upDownRateWidgets[0].setText(message['iface'])
        self.upDownRateWidgets[1].setText('{}/s'.format(humanfriendly.format_size(message['downSpeed'])))
        self.upDownRateWidgets[2].setText('{}/s'.format(humanfriendly.format_size(message['upSpeed'])))
        self.upDownRateWidgets[3].setText(humanfriendly.format_size(message['bytesRcv']))
        self.upDownRateWidgets[4].setText(humanfriendly.format_size(message['bytesSent']))

    def receiveThreadNvidia(self, message):
        for msg in message:
            # get the id
            idx = int(msg['id'])
            self.nvidiaWidgets[idx]['name'].setText(msg['name'])
            self.nvidiaWidgets[idx]['load'].setText(f"{str(msg['load'])}%")
            self.nvidiaWidgets[idx]['usedTotalMemory'].setText(f"{msg['memoryUsed']}MB/{msg['memoryTotal']}MB")
            self.nvidiaWidgets[idx]['temp'].setText(f"{int(msg['temp'])}°{msg['scale']}")
            self.analizeTemp(self.nvidiaWidgets[idx]['temp'], msg['temp'], msg['high'], msg['critical'])

    @staticmethod
    def analizeTemp(label, current, highValue, criticalValue):
        colorNormal = 'color: rgb(157, 255, 96);'
        colorWarning = 'color: rgb(255, 255, 153);'
        colorAlarm = 'color: rgb(255, 79, 79);'
        label.setStyleSheet(colorNormal)
        if current >= criticalValue:
            label.setStyleSheet(colorAlarm)
        elif (current < criticalValue) and (current >= highValue):
            label.setStyleSheet(colorWarning)
Example #12
0
from ewmh import EWMH

ewmh = EWMH()

print ewmh.getClientList()

Example #13
0
class MonMon:
    def __init__(self):
        # Display modes
        self.allmodes = {}

        # Monitor objects for all the connected monitors, indexed by name
        self.monitors = {}

        # width, height and xinerama x, y for all active monitors,
        # indexed by name
        self.mon_geom = {}

        # If this is a laptop, the name of its native display
        self.laptop_screen = None

        # A list of [ (win, geom) ] for all windows on screen
        self.allwindows = []

    def find_monitors(self):
        self.dpy = display.Display()
        self.root = self.dpy.screen().root
        self.resources = self.root.xrandr_get_screen_resources()._data
        self.ewmh = EWMH()

        # Accessing modes sometimes makes outputs mysteriously disappear,
        # so save outputs first.
        outputs = self.resources['outputs']

        # Build up a mode table. There's probably some clever IterTools
        # construct that could do this in one line.
        for m in self.resources['modes']:
            self.allmodes[m['id']] = '%dx%d' % (m['width'], m['height'])

        # Loop over the outputs.
        for output in outputs:
            mondata = self.dpy.xrandr_get_output_info(
                output, self.resources['config_timestamp'])._data

            if mondata['mm_width'] <= 0 or mondata['mm_height'] <= 0:
                # Not an actual monitor; I'm not sure what these are for
                # but they don't seem to have any useful info
                print("Not real monitor, skipping", file=DEBUGFILE)
                continue

            try:
                prefmode = mondata['modes'][mondata['num_preferred']] - 1
                mondata['preferred'] = self.allmodes[prefmode]
            except:
                print("Couldn't get",
                      mondata['name'],
                      "preferred modes",
                      file=DEBUGFILE)

            name = mondata['name']
            self.monitors[name] = mondata
            if name.startswith('eDP') or name.startswith('LVDS'):
                self.laptop_screen = name

            # Get the geometry, and Figure out if it's cloned or extended,
            # and its xinerama position
            # https://stackoverflow.com/questions/49136692/python-xlib-how-to-deterministically-tell-whether-display-output-is-in-extendi
            # which references https://www.x.org/wiki/Development/Documentation/HowVideoCardsWork/#index3h3
            # crtcInfo also includes rotation info but I'm not doing anything
            # with that since I don't personally use it.
            try:
                crtcInfo = self.dpy.xrandr_get_crtc_info(
                    mondata['crtc'], self.resources['config_timestamp'])

                self.mon_geom[name] = {
                    'x': crtcInfo.x,
                    'y': crtcInfo.y,
                    'width': crtcInfo.width,
                    'height': crtcInfo.height,
                    'mm_width': mondata['mm_width'],
                    'mm_height': mondata['mm_height']
                }

            except XError:
                # If get_crtc_info fails it means that the monitor is
                # connected but not active.
                print("No crtc info", file=DEBUGFILE)
                pass

    def active_monitors(self):
        """List monitors xrandr is actually using"""
        active = []
        for mname in self.monitors:
            if mname in self.mon_geom:
                active.append(mname)
        return active

    def inactive_monitors(self):
        """List monitors that are connected but not being used"""
        inactive = []
        for mname in self.monitors:
            if mname not in self.mon_geom:
                inactive.append(mname)
        return inactive

    def connected_monitors(self):
        """List all connected monitors"""
        return list(self.monitors.keys())

    def print_monitor(self, mon, show_all_modes):
        if show_all_modes:
            print("\n%s:" % mon['name'])
            print(", ".join([self.allmodes[m] for m in mon['modes']]))

        try:
            geom = self.mon_geom[mon['name']]
            if self.laptop_screen == mon['name']:
                islaptop = "    **laptop"
            else:
                islaptop = ""
            print("%s: %4dx%4d   Position: (%4d, %4d)   mm: %d x %d%s" %
                  (mon['name'], geom['width'], geom['height'], geom['x'],
                   geom['y'], geom['mm_width'], geom['mm_height'], islaptop))

        except KeyError:
            print("%s: Inactive" % mon['name'])

    def print_monitors(self, show_all_modes):
        for mname in self.monitors:
            self.print_monitor(self.monitors[mname], show_all_modes)

    def move_window(self, win, newx, newy):
        """Move a window so it's visible on the screen.
        """
        geom = win.get_geometry()
        if win.get_wm_name() == WINDOW_NAME:
            print("Current size", geom.width, geom.height)

            print('Moving Win')
            win.configure(
                x=newx,
                y=newy,
                width=geom.width,
                height=geom.height,
                # border_width=0,
                stack_mode=Xlib.X.Above)
            dpy.sync()
        else:
            print("%s: %dx%d +%d+%d" %
                  (win.get_wm_name(), geom.width, geom.height, geom.x, geom.y))

    def find_all_windows(self):
        def topframe(client):
            frame = client
            while frame.query_tree().parent != self.ewmh.root:
                frame = frame.query_tree().parent
            return frame

        for client in self.ewmh.getClientList():
            geom = topframe(client).get_geometry()
            self.allwindows.append((client, geom))

    def print_all_windows(self):
        if not self.allwindows:
            self.find_all_windows()

        for win, geom in self.allwindows:
            name, classname = win.get_wm_class()
            print("%4d x %4d   +%4d + %4d   %s: %s" %
                  (geom.width, geom.height, geom.x, geom.y, name,
                   win.get_wm_name()))

    def is_visible(self, x, y):
        """Is the point x, y currently visible? That is, is there
           currently a connected screen that is showing that point?
        """
        x_visible = False
        y_visible = False
        for mname in self.mon_geom:
            geom = self.mon_geom[mname]

            # Is x visible?
            if x > geom['x'] and x < geom['x'] + geom['width']:
                x_visible = True

            # Is y visible?
            if y > geom['y'] and y < geom['y'] + geom['height']:
                y_visible = True

            if x_visible and y_visible:
                print("%d, %d visible on monitor %s" % (x, y, mname))
                return True

        return False

    def find_orphans(self):
        print("Trying to find orphans")

        if not self.allwindows:
            self.find_all_windows()

        # A safe place to move orphans, on the laptop screen or, otherwise,
        # the first connected display.
        if self.laptop_screen:
            safegeom = self.mon_geom[self.laptop_screen]
        else:
            # Just pick the first one, understanding that dicts have no "first"
            safegeom = self.mon_geom[self.mon_geom.keys()[0]]
        safe_x = safegeom['x'] + 25
        safe_y = safegeom['y'] + 25

        for win, geom in self.allwindows:
            name, classname = win.get_wm_class()

            if not self.is_visible(geom.x, geom.y):
                self.move_orphan(win, geom, safe_x, safe_y)

    def move_orphan(self, win, geom, newx, newy):
        print("Moving %s from %d, %d. Current size %dx%d" %
              (win.get_wm_name(), geom.x, geom.y, geom.width, geom.height))

        win.configure(x=newx, y=newy, width=geom.width, height=geom.height)
        # border_width=0,
        # stack_mode=Xlib.X.Above)
        self.dpy.sync()
Example #14
0
class BaseWidget(Toplevel):
    def __init__(self, master, name, config, save_config):
        """Create base desktop widget."""
        Toplevel.__init__(self, master, class_=APP_NAME)

        self.rowconfigure(2, weight=1)
        self.columnconfigure(0, weight=1)
        self.minsize(50, 50)
        self.protocol('WM_DELETE_WINDOW', self.withdraw)

        self.ewmh = EWMH()

        self.name = name
        self.config = config  # configparser
        self.save_config = save_config  # save config method

        # get splash window type compatibility
        if CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.attributes('-type', 'splash')
        else:
            self.attributes('-type', 'toolbar')

        # control main menu checkbutton
        self.variable = BooleanVar(self, False)
        # save widget's position
        self._position = StringVar(
            self, self.config.get(name, 'position', fallback='normal'))
        add_trace(self._position, 'write', self._position_trace)

        self.title('feedagregator.widget.{}'.format(name.replace(' ', '_')))
        self.withdraw()

        # window dragging
        self.x = None
        self.y = None

        # --- menu
        self._create_menu()

        # --- elements
        # --- --- title bar
        frame = Frame(self, style='widget.TFrame')
        Button(frame, style='widget.close.TButton',
               command=self.withdraw).pack(side='left')
        self.label = Label(frame,
                           text=name,
                           style='widget.title.TLabel',
                           anchor='center')
        self.label.pack(side='left', fill='x', expand=True)
        frame.grid(row=0, columnspan=2, padx=4, pady=4, sticky='ew')

        sep = Separator(self, style='widget.Horizontal.TSeparator')
        sep.grid(row=1, columnspan=2, sticky='ew')
        # --- --- widget body
        self.canvas = Canvas(self, highlightthickness=0)
        self.canvas.grid(row=2,
                         column=0,
                         sticky='ewsn',
                         padx=(2, 8),
                         pady=(2, 4))
        scroll = AutoScrollbar(self,
                               orient='vertical',
                               style='widget.Vertical.TScrollbar',
                               command=self.canvas.yview)
        scroll.grid(row=2, column=1, sticky='ns', pady=(2, 14))
        self.canvas.configure(yscrollcommand=scroll.set)
        self.display = Frame(self.canvas, style='widget.TFrame')
        self.canvas.create_window(0,
                                  0,
                                  anchor='nw',
                                  window=self.display,
                                  tags=('display', ))

        self.display.columnconfigure(0, weight=1)

        # --- style
        self.style = Style(self)
        self._font_size = 10
        self.update_style()

        # --- resizing and geometry
        corner = Sizegrip(self, style="widget.TSizegrip")
        corner.place(relx=1, rely=1, anchor='se', bordermode='outside')

        geometry = self.config.get(self.name, 'geometry')
        if geometry:
            self.geometry(geometry)
        self.update_idletasks()
        if self.config.getboolean(self.name, 'visible', fallback=True):
            self.deiconify()

        # --- bindings
        self.bind('<3>', lambda e: self.menu.tk_popup(e.x_root, e.y_root))
        for widget in [self.label, self.canvas, sep]:
            widget.bind('<ButtonPress-1>', self._start_move)
            widget.bind('<ButtonRelease-1>', self._stop_move)
            widget.bind('<B1-Motion>', self._move)
        self.label.bind('<Map>', self._change_position)
        self.bind('<Configure>', self._on_configure)
        self.bind('<4>', lambda e: self._scroll(-1))
        self.bind('<5>', lambda e: self._scroll(1))

        self.update_idletasks()
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))

        self.populate_widget()

        if not CONFIG.getboolean('General', 'splash_supported',
                                 fallback=True) and self.config.getboolean(
                                     self.name, 'visible', fallback=True):
            Toplevel.withdraw(self)
            Toplevel.deiconify(self)

    def _create_menu(self):
        self.menu = Menu(self, tearoff=False)
        self.menu_sort = Menu(self.menu, tearoff=False)

        menu_pos = Menu(self.menu, tearoff=False)
        menu_pos.add_radiobutton(label=_('Normal'),
                                 value='normal',
                                 variable=self._position,
                                 command=self._change_position)
        menu_pos.add_radiobutton(label=_('Above'),
                                 value='above',
                                 variable=self._position,
                                 command=self._change_position)
        menu_pos.add_radiobutton(label=_('Below'),
                                 value='below',
                                 variable=self._position,
                                 command=self._change_position)
        self.menu.add_cascade(label=_('Sort'), menu=self.menu_sort)
        self.menu.add_cascade(label=_('Position'), menu=menu_pos)
        self.menu.add_command(label=_('Hide'), command=self.withdraw)
        self.menu.add_command(label=_('Open all'), command=self.open_all)
        self.menu.add_command(label=_('Close all'), command=self.close_all)

    def populate_widget(self):
        pass  # to be overriden by subclass

    def open_all(self):
        pass  # to be overriden by subclass

    def close_all(self):
        pass  # to be overriden by subclass

    def entry_add(self, title, date, summary, url):
        """Display entry and return the toggleframe and htmlframe."""
        def unwrap(event):
            l.update_idletasks()
            try:
                h = l.html.bbox()[-1]
            except TclError:
                pass
            else:
                l.configure(height=h + 2)

        def resize(event):
            if l.winfo_viewable():
                try:
                    h = l.html.bbox()[-1]
                except TclError:
                    pass
                else:
                    l.configure(height=h + 2)

        # convert date to locale time
        formatted_date = format_datetime(datetime.strptime(
            date, '%Y-%m-%d %H:%M').astimezone(tz=None),
                                         'short',
                                         locale=getlocale()[0])

        tf = ToggledFrame(self.display,
                          text="{} - {}".format(title, formatted_date),
                          style='widget.TFrame')
        l = HtmlFrame(tf.interior, height=50, style='widget.interior.TFrame')
        l.set_content(summary)
        l.set_style(self._stylesheet)
        l.set_font_size(self._font_size)
        tf.interior.configure(style='widget.interior.TFrame')
        tf.interior.rowconfigure(0, weight=1)
        tf.interior.columnconfigure(0, weight=1)
        l.grid(padx=4, sticky='eswn')
        Button(tf.interior,
               text='Open',
               style='widget.TButton',
               command=lambda: webopen(url)).grid(pady=4, padx=6, sticky='e')
        tf.grid(sticky='we', row=len(self.entries), pady=2, padx=(8, 4))
        tf.bind("<<ToggledFrameOpen>>", unwrap)
        l.bind("<Configure>", resize)
        return tf, l

    def update_position(self):
        if self._position.get() == 'normal':
            if CONFIG.getboolean('General', 'splash_supported', fallback=True):
                self.attributes('-type', 'splash')
            else:
                self.attributes('-type', 'toolbar')
        if self.variable.get():
            Toplevel.withdraw(self)
            Toplevel.deiconify(self)

    def update_style(self):
        self.attributes('-alpha', CONFIG.getint('Widget', 'alpha') / 100)
        text_font = Font(self, font=CONFIG.get('Widget', 'font')).actual()
        bg = CONFIG.get('Widget', 'background')
        feed_bg = CONFIG.get('Widget', 'feed_background', fallback='gray20')
        feed_fg = CONFIG.get('Widget', 'feed_foreground', fallback='white')

        self._stylesheet = """
body {
  background-color: %(bg)s;
  color: %(fg)s;
  font-family: %(family)s;
  font-weight: %(weight)s;
  font-style: %(slant)s;
}

ul {
padding-left: 5px;
}

ol {
padding-left: 5px;
}

#title {
  font-weight: bold;
  font-size: large;
}

a {
  color: %(link)s;
  font-style: italic;
}

code {font-family: monospace;}

a:hover {
  font-style: italic;
  border-bottom: 1px solid %(link)s;
}
""" % (dict(bg=feed_bg,
            fg=feed_fg,
            link=CONFIG.get('Widget', 'link_color', fallback='#89B9F6'),
            **text_font))

        self.configure(bg=bg)
        self.canvas.configure(background=bg)
        self._font_size = text_font['size']

    def withdraw(self):
        Toplevel.withdraw(self)
        self.variable.set(False)

    def deiconify(self):
        Toplevel.deiconify(self)
        self.variable.set(True)

    def _scroll(self, delta):
        top, bottom = self.canvas.yview()
        top += delta * 0.05
        top = min(max(top, 0), 1)
        self.canvas.yview_moveto(top)

    def _position_trace(self, *args):
        self.config.set(self.name, 'position', self._position.get())
        self.save_config()

    def _change_position(self, event=None):
        '''Make widget sticky and set its position with respects to the other windows.'''
        pos = self._position.get()
        splash_supp = CONFIG.getboolean('General',
                                        'splash_supported',
                                        fallback=True)
        try:
            for w in self.ewmh.getClientList():
                if w.get_wm_name() == self.title():
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY')
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_TASKBAR')
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_PAGER')
                    if pos == 'above':
                        self.attributes('-type', 'dock')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                    elif pos == 'below':
                        self.attributes('-type', 'desktop')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_BELOW')
                    else:
                        if splash_supp:
                            self.attributes('-type', 'splash')
                        else:
                            self.attributes('-type', 'toolbar')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
            self.ewmh.display.flush()
            if event is None and not splash_supp:
                Toplevel.withdraw(self)
                Toplevel.deiconify(self)
        except ewmh.display.error.BadWindow:
            pass

    def _on_configure(self, event):
        if event.widget is self:
            geometry = self.geometry()
            if geometry != '1x1+0+0':
                self.config.set(self.name, 'geometry', geometry)
                self.save_config()
        elif event.widget in [self.canvas, self.display]:
            self.canvas.configure(scrollregion=self.canvas.bbox('all'))
            self.canvas.itemconfigure('display',
                                      width=self.canvas.winfo_width() - 4)

    def _start_move(self, event):
        self.x = event.x
        self.y = event.y
        self.configure(cursor='fleur')
        self.display.configure(cursor='fleur')

    def _stop_move(self, event):
        self.x = None
        self.y = None
        self.configure(cursor='arrow')
        self.display.configure(cursor='arrow')

    def _move(self, event):
        if self.x is not None and self.y is not None:
            deltax = event.x - self.x
            deltay = event.y - self.y
            x = self.winfo_x() + deltax
            y = self.winfo_y() + deltay
            self.geometry("+%s+%s" % (x, y))