<commit_before># Copyright (c) 2008, <NAME>. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import asyncio
import functools
import io
import logging
import os
import pickle
import shlex
import signal
import sys
import time
import traceback
import warnings
from typing import Optional

import xcffib
import xcffib.xinerama
import xcffib.xproto

from libqtile import command_interface, hook, utils, window
from libqtile.backend.x11 import xcbq
from libqtile.backend.x11.xcore import XCore
from libqtile.command_client import InteractiveCommandClient
from libqtile.command_interface import IPCCommandServer, QtileCommandInterface
from libqtile.command_object import (
    CommandError,
    CommandException,
    CommandObject,
)
from libqtile.config import Click, Drag, Match, Rule
from libqtile.config import ScratchPad as ScratchPadConfig
from libqtile.config import Screen
from libqtile.confreader import Config, ConfigError
from libqtile.dgroups import DGroups
from libqtile.extension.base import _Extension
from libqtile.group import _Group
from libqtile.lazy import lazy
from libqtile.log_utils import logger
from libqtile.scratchpad import ScratchPad
from libqtile.state import QtileState
from libqtile.utils import get_cache_dir, send_notification
from libqtile.widget.base import _Widget


def validate_config(file_path):
    """
    Validate a configuration file.

    This function reloads and imports the given configuration file.
    It re-raises a ConfigError with a detailed message for any caught exception.
    """
    output = [
        "The configuration file '",
        file_path,
        "' generated the following error:\n\n",
    ]

    try:
        Config.from_file(XCore(), file_path)

    except ConfigError as error:
        output.append(str(error))
        raise ConfigError("".join(output))

    except Exception as error:
        # Handle SyntaxError and the likes
        output.append("{}: {}".format(sys.exc_info()[0].__name__, str(error)))
        raise ConfigError("".join(output))


def _import_module(module_name, dir_path):
    import imp
    fp = None
    try:
        fp, pathname, description = imp.find_module(module_name, [dir_path])
        module = imp.load_module(module_name, fp, pathname, description)
    finally:
        if fp:
            fp.close()
    return module


def handle_exception(loop, context):
    if "exception" in context:
        logger.error(context["exception"], exc_info=True)
    else:
        logger.error("exception in event loop: %s", context)


class Qtile(CommandObject):
    """This object is the `root` of the command graph"""
    def __init__(
        self,
        kore,
        config,
        eventloop,
        no_spawn=False,
        state=None
    ):
        self._restart = False
        self.no_spawn = no_spawn

        self.mouse_position = (0, 0)

        self.core = kore
        self.config = config
        hook.init(self)

        self.windows_map = {}
        self.widgets_map = {}
        self.groups_map = {}
        self.groups = []
        self.keys_map = {}

        self.numlock_mask, self.valid_mask = self.core.masks

        self.core.wmname = getattr(self.config, "wmname", "qtile")
        if config.main:
            config.main(self)

        self.dgroups = None
        if self.config.groups:
            key_binder = None
            if hasattr(self.config, 'dgroups_key_binder'):
                key_binder = self.config.dgroups_key_binder
            self.dgroups = DGroups(self, self.config.groups, key_binder)

        if hasattr(config, "widget_defaults") and config.widget_defaults:
            _Widget.global_defaults = config.widget_defaults
        else:
            _Widget.global_defaults = {}

        if hasattr(config, "extension_defaults") and config.extension_defaults:
            _Extension.global_defaults = config.extension_defaults
        else:
            _Extension.global_defaults = {}

        for installed_extension in _Extension.installed_extensions:
            installed_extension._configure(self)

        for i in self.groups:
            self.groups_map[i.name] = i

        for grp in self.config.groups:
            if isinstance(grp, ScratchPadConfig):
                sp = ScratchPad(grp.name, grp.dropdowns, grp.label)
                sp._configure([self.config.floating_layout],
                              self.config.floating_layout, self)
                self.groups.append(sp)
                self.groups_map[sp.name] = sp

        self._eventloop = eventloop
        self.setup_eventloop()
        self.server = IPCCommandServer(self)

        self.current_screen = None
        self.screens = []
        self._process_screens()
        self.current_screen = self.screens[0]
        self._drag = None

        self.conn.flush()
        self.conn.xsync()
        self.core._xpoll()

        # Map and Grab keys
        for key in self.config.keys:
            self.grab_key(key)

        # It fixes problems with focus when clicking windows of some specific clients like xterm
        def noop(qtile):
            pass
        self.config.mouse += (Click([], "Button1", lazy.function(noop), focus="after"),)

        self.mouse_map = {}
        for i in self.config.mouse:
            if self.mouse_map.get(i.button_code) is None:
                self.mouse_map[i.button_code] = []
            self.mouse_map[i.button_code].append(i)

        self.grab_mouse()

        # no_spawn is set when we are restarting; we only want to run the
        # startup hook once.
        if not no_spawn:
            hook.fire("startup_once")
        hook.fire("startup")

        if state:
            st = pickle.load(io.BytesIO(state.encode()))
            try:
                st.apply(self)
            except:  # noqa: E722
                logger.exception("failed restoring state")

        self.core.scan()
        self.update_net_desktops()
        hook.subscribe.setgroup(self.update_net_desktops)

        hook.fire("startup_complete")

    @property
    def root(self):
        return self.core._root

    @property
    def conn(self):
        return self.core.conn

    @property
    def selection(self):
        return self.core._selection

    def setup_eventloop(self) -> None:
        self._eventloop.add_signal_handler(signal.SIGINT, self.stop)
        self._eventloop.add_signal_handler(signal.SIGTERM, self.stop)
        self._eventloop.set_exception_handler(handle_exception)

        logger.debug('Adding io watch')
        self.core.setup_listener(self, self._eventloop)

        self._stopped_event = asyncio.Event(loop=self._eventloop)
<commit_msg>manager: drop loop arg from stop event<commit_after># Copyright (c) 2008, <NAME>. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import asyncio
import functools
import io
import logging
import os
import pickle
import shlex
import signal
import sys
import time
import traceback
import warnings
from typing import Optional

import xcffib
import xcffib.xinerama
import xcffib.xproto

from libqtile import command_interface, hook, utils, window
from libqtile.backend.x11 import xcbq
from libqtile.backend.x11.xcore import XCore
from libqtile.command_client import InteractiveCommandClient
from libqtile.command_interface import IPCCommandServer, QtileCommandInterface
from libqtile.command_object import (
    CommandError,
    CommandException,
    CommandObject,
)
from libqtile.config import Click, Drag, Match, Rule
from libqtile.config import ScratchPad as ScratchPadConfig
from libqtile.config import Screen
from libqtile.confreader import Config, ConfigError
from libqtile.dgroups import DGroups
from libqtile.extension.base import _Extension
from libqtile.group import _Group
from libqtile.lazy import lazy
from libqtile.log_utils import logger
from libqtile.scratchpad import ScratchPad
from libqtile.state import QtileState
from libqtile.utils import get_cache_dir, send_notification
from libqtile.widget.base import _Widget


def validate_config(file_path):
    """
    Validate a configuration file.

    This function reloads and imports the given configuration file.
    It re-raises a ConfigError with a detailed message for any caught exception.
    """
    output = [
        "The configuration file '",
        file_path,
        "' generated the following error:\n\n",
    ]

    try:
        Config.from_file(XCore(), file_path)

    except ConfigError as error:
        output.append(str(error))
        raise ConfigError("".join(output))

    except Exception as error:
        # Handle SyntaxError and the likes
        output.append("{}: {}".format(sys.exc_info()[0].__name__, str(error)))
        raise ConfigError("".join(output))


def _import_module(module_name, dir_path):
    import imp
    fp = None
    try:
        fp, pathname, description = imp.find_module(module_name, [dir_path])
        module = imp.load_module(module_name, fp, pathname, description)
    finally:
        if fp:
            fp.close()
    return module


def handle_exception(loop, context):
    if "exception" in context:
        logger.error(context["exception"], exc_info=True)
    else:
        logger.error("exception in event loop: %s", context)


class Qtile(CommandObject):
    """This object is the `root` of the command graph"""
    def __init__(
        self,
        kore,
        config,
        eventloop,
        no_spawn=False,
        state=None
    ):
        self._restart = False
        self.no_spawn = no_spawn

        self.mouse_position = (0, 0)

        self.core = kore
        self.config = config
        hook.init(self)

        self.windows_map = {}
        self.widgets_map = {}
        self.groups_map = {}
        self.groups = []
        self.keys_map = {}

        self.numlock_mask, self.valid_mask = self.core.masks

        self.core.wmname = getattr(self.config, "wmname", "qtile")
        if config.main:
            config.main(self)

        self.dgroups = None
        if self.config.groups:
            key_binder = None
            if hasattr(self.config, 'dgroups_key_binder'):
                key_binder = self.config.dgroups_key_binder
            self.dgroups = DGroups(self, self.config.groups, key_binder)

        if hasattr(config, "widget_defaults") and config.widget_defaults:
            _Widget.global_defaults = config.widget_defaults
        else:
            _Widget.global_defaults = {}

        if hasattr(config, "extension_defaults") and config.extension_defaults:
            _Extension.global_defaults = config.extension_defaults
        else:
            _Extension.global_defaults = {}

        for installed_extension in _Extension.installed_extensions:
            installed_extension._configure(self)

        for i in self.groups:
            self.groups_map[i.name] = i

        for grp in self.config.groups:
            if isinstance(grp, ScratchPadConfig):
                sp = ScratchPad(grp.name, grp.dropdowns, grp.label)
                sp._configure([self.config.floating_layout],
                              self.config.floating_layout, self)
                self.groups.append(sp)
                self.groups_map[sp.name] = sp

        self._eventloop = eventloop
        self.setup_eventloop()
        self.server = IPCCommandServer(self)

        self.current_screen = None
        self.screens = []
        self._process_screens()
        self.current_screen = self.screens[0]
        self._drag = None

        self.conn.flush()
        self.conn.xsync()
        self.core._xpoll()

        # Map and Grab keys
        for key in self.config.keys:
            self.grab_key(key)

        # It fixes problems with focus when clicking windows of some specific clients like xterm
        def noop(qtile):
            pass
        self.config.mouse += (Click([], "Button1", lazy.function(noop), focus="after"),)

        self.mouse_map = {}
        for i in self.config.mouse:
            if self.mouse_map.get(i.button_code) is None:
                self.mouse_map[i.button_code] = []
            self.mouse_map[i.button_code].append(i)

        self.grab_mouse()

        # no_spawn is set when we are restarting; we only want to run the
        # startup hook once.
        if not no_spawn:
            hook.fire("startup_once")
        hook.fire("startup")

        if state:
            st = pickle.load(io.BytesIO(state.encode()))
            try:
                st.apply(self)
            except:  # noqa: E722
                logger.exception("failed restoring state")

        self.core.scan()
        self.update_net_desktops()
        hook.subscribe.setgroup(self.update_net_desktops)

        hook.fire("startup_complete")

    @property
    def root(self):
        return self.core._root

    @property
    def conn(self):
        return self.core.conn

    @property
    def selection(self):
        return self.core._selection

    def setup_eventloop(self) -> None:
        self._eventloop.add_signal_handler(signal.SIGINT, self.stop)
        self._eventloop.add_signal_handler(signal.SIGTERM, self.stop)
        self._eventloop.set_exception_handler(handle_exception)

        logger.debug('Adding io watch')
        self.core.setup_listener(self, self._eventloop)

        self._stopped_event = asyncio.Event()

{'fraction_non_alphanumeric': 0.08192219679633868, 'fraction_numerical': 0.0020921869892121608, 'mean_word_length': 2.657580105212817, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3066912', 'n_tokens_mistral': 4391, 'n_tokens_neox': 4244, 'n_words': 1258}