# Source code for gi.overrides.Gdk

    # Copyright (C) 2009 Johan Dahlin <johan@gnome.org>
    #               2010 Simon van der Linden <svdlinden@src.gnome.org>
    #
    # This library is free software; you can redistribute it and/or
    # modify it under the terms of the GNU Lesser General Public
    # License as published by the Free Software Foundation; either
    # version 2.1 of the License, or (at your option) any later version.
    #
    # This library is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    # Lesser General Public License for more details.
    #
    # You should have received a copy of the GNU Lesser General Public
    # License along with this library; if not, write to the Free Software
    # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
    # USA

    import sys
    import warnings

    from ..overrides import override, strip_boolean_result
    from ..module import get_introspection_module
    from gi import PyGIDeprecationWarning, require_version, get_option

    Gdk = get_introspection_module("Gdk")
    GDK3 = Gdk._version == "3.0"
    GDK4 = Gdk._version == "4.0"

    __all__ = []

    # https://bugzilla.gnome.org/show_bug.cgi?id=673396
    try:
        require_version("GdkX11", Gdk._version)
        from gi.repository import GdkX11

        GdkX11
    except (ValueError, ImportError):
        pass

    if GDK3:
        # Gdk.Color was deprecated since 3.14 and dropped in Gtk-4.0
        class Color(Gdk.Color):
            MAX_VALUE = 65535

            def __init__(self, red, green, blue):
                Gdk.Color.__init__(self)
                self.red = red
                self.green = green
                self.blue = blue

            def __eq__(self, other):
                if not isinstance(other, Gdk.Color):
                    return False
                return self.equal(other)

            # This is required (even when __eq__ is defined) in order
            # for != operator to work as expected
            def __ne__(self, other):
                return not self == other

            def __repr__(self):
                return f"Gdk.Color(red={self.red}, green={self.green}, blue={self.blue})"

            red_float = property(
                fget=lambda self: self.red / float(self.MAX_VALUE),
                fset=lambda self, v: setattr(self, "red", int(v * self.MAX_VALUE)),
            )

            green_float = property(
                fget=lambda self: self.green / float(self.MAX_VALUE),
                fset=lambda self, v: setattr(self, "green", int(v * self.MAX_VALUE)),
            )

            blue_float = property(
                fget=lambda self: self.blue / float(self.MAX_VALUE),
                fset=lambda self, v: setattr(self, "blue", int(v * self.MAX_VALUE)),
            )

            def to_floats(self):
                """Return (red_float, green_float, blue_float) triple."""
                return (self.red_float, self.green_float, self.blue_float)

            @staticmethod
            def from_floats(red, green, blue):
                """Return a new Color object from red/green/blue values from 0.0 to 1.0."""
                return Color(
                    int(red * Color.MAX_VALUE),
                    int(green * Color.MAX_VALUE),
                    int(blue * Color.MAX_VALUE),
                )

        Color = override(Color)
        __all__.append("Color")

    # Introduced since Gtk-3.0
    class RGBA(Gdk.RGBA):
        def __init__(self, red=1.0, green=1.0, blue=1.0, alpha=1.0):
            Gdk.RGBA.__init__(self)
            self.red = red
            self.green = green
            self.blue = blue
            self.alpha = alpha

        def __eq__(self, other):
            if not isinstance(other, Gdk.RGBA):
                return False
            return self.equal(other)

        # This is required (even when __eq__ is defined) in order
        # for != operator to work as expected
        def __ne__(self, other):
            return not self == other

        def __repr__(self):
            return f"Gdk.RGBA(red={self.red:f}, green={self.green:f}, blue={self.blue:f}, alpha={self.alpha:f})"

        def __iter__(self):
            """Iterator which allows easy conversion to tuple and list types."""
            yield self.red
            yield self.green
            yield self.blue
            yield self.alpha

        if GDK3:

            def to_color(self):
                """Converts this RGBA into a Color instance which excludes alpha."""
                return Color(
                    int(self.red * Color.MAX_VALUE),
                    int(self.green * Color.MAX_VALUE),
                    int(self.blue * Color.MAX_VALUE),
                )

            @classmethod
            def from_color(cls, color):
                """Returns a new RGBA instance given a Color instance."""
                return cls(color.red_float, color.green_float, color.blue_float)

    RGBA = override(RGBA)
    __all__.append("RGBA")

    if GDK3:
        # Newer GTK/gobject-introspection (3.17.x) include GdkRectangle in the
        # typelib. See https://bugzilla.gnome.org/show_bug.cgi?id=748832 and
        # https://bugzilla.gnome.org/show_bug.cgi?id=748833
        if not hasattr(Gdk, "Rectangle"):
            from gi.repository import cairo as _cairo

            Rectangle = _cairo.RectangleInt

            __all__.append("Rectangle")
        else:
            # https://bugzilla.gnome.org/show_bug.cgi?id=756364
            # These methods used to be functions, keep aliases for backwards compat
            rectangle_intersect = Gdk.Rectangle.intersect
            rectangle_union = Gdk.Rectangle.union

            __all__.append("rectangle_intersect")
            __all__.append("rectangle_union")

    if GDK3:

        class Window(Gdk.Window):
            def __new__(cls, parent, attributes, attributes_mask):
                # Gdk.Window had to be made abstract,
                # this override allows using the standard constructor
                return Gdk.Window.new(parent, attributes, attributes_mask)

            def __init__(self, parent, attributes, attributes_mask):
                pass

            def cairo_create(self):
                return Gdk.cairo_create(self)

        Window = override(Window)
        __all__.append("Window")

    if GDK3:
        Gdk.EventType._2BUTTON_PRESS = getattr(Gdk.EventType, "2BUTTON_PRESS")
        Gdk.EventType._3BUTTON_PRESS = getattr(Gdk.EventType, "3BUTTON_PRESS")

        class Event(Gdk.Event):
            _UNION_MEMBERS = {
                Gdk.EventType.DELETE: "any",
                Gdk.EventType.DESTROY: "any",
                Gdk.EventType.MOTION_NOTIFY: "motion",
                Gdk.EventType.BUTTON_PRESS: "button",
                Gdk.EventType.BUTTON_RELEASE: "button",
                Gdk.EventType.KEY_PRESS: "key",
                Gdk.EventType.KEY_RELEASE: "key",
                Gdk.EventType.ENTER_NOTIFY: "crossing",
                Gdk.EventType.LEAVE_NOTIFY: "crossing",
                Gdk.EventType.FOCUS_CHANGE: "focus_change",
                Gdk.EventType.CONFIGURE: "configure",
                Gdk.EventType.PROXIMITY_IN: "proximity",
                Gdk.EventType.PROXIMITY_OUT: "proximity",
                Gdk.EventType.DRAG_ENTER: "dnd",
                Gdk.EventType.DRAG_LEAVE: "dnd",
                Gdk.EventType.DRAG_MOTION: "dnd",
                Gdk.EventType.DROP_START: "dnd",
                Gdk.EventType._2BUTTON_PRESS: "button",
                Gdk.EventType._3BUTTON_PRESS: "button",
                Gdk.EventType.PROPERTY_NOTIFY: "property",
                Gdk.EventType.SELECTION_CLEAR: "selection",
                Gdk.EventType.SELECTION_REQUEST: "selection",
                Gdk.EventType.SELECTION_NOTIFY: "selection",
                Gdk.EventType.DRAG_STATUS: "dnd",
                Gdk.EventType.DROP_FINISHED: "dnd",
                Gdk.EventType.CLIENT_EVENT: "client",
                Gdk.EventType.VISIBILITY_NOTIFY: "visibility",
                Gdk.EventType.SCROLL: "scroll",
                Gdk.EventType.EXPOSE: "expose",
                Gdk.EventType.MAP: "any",
                Gdk.EventType.UNMAP: "any",
            }

            if hasattr(Gdk.EventType, "TOUCH_BEGIN"):
                _UNION_MEMBERS.update(
                    {
                        Gdk.EventType.TOUCH_BEGIN: "touch",
                        Gdk.EventType.TOUCH_UPDATE: "touch",
                        Gdk.EventType.TOUCH_END: "touch",
                        Gdk.EventType.TOUCH_CANCEL: "touch",
                    }
                )

            def __getattr__(self, name):
                real_event = getattr(self, "_UNION_MEMBERS").get(self.type)
                if real_event:
                    return getattr(getattr(self, real_event), name)
                raise AttributeError(
                    f"'{self.__class__.__name__}' object has no attribute '{name}'"
                )

            def __setattr__(self, name, value):
                real_event = getattr(self, "_UNION_MEMBERS").get(self.type)
                if real_event:
                    setattr(getattr(self, real_event), name, value)
                else:
                    Gdk.Event.__setattr__(self, name, value)

            def __repr__(self):
                base_repr = Gdk.Event.__repr__(self).strip("><")
                return f"<{base_repr} type={self.type!r}>"

        Event = override(Event)
        __all__.append("Event")

        # manually bind GdkEvent members to GdkEvent

        modname = globals()["__name__"]
        module = sys.modules[modname]

        # right now we can't get the type_info from the
        # field info so manually list the class names
        event_member_classes = [
            "EventAny",
            "EventExpose",
            "EventMotion",
            "EventButton",
            "EventScroll",
            "EventKey",
            "EventCrossing",
            "EventFocus",
            "EventConfigure",
            "EventProximity",
            "EventDND",
            "EventSetting",
            "EventGrabBroken",
            "EventVisibility",
            "EventProperty",
            "EventSelection",
            "EventOwnerChange",
            "EventWindowState",
            "EventVisibility",
        ]

        if hasattr(Gdk, "EventTouch"):
            event_member_classes.append("EventTouch")

        # whitelist all methods that have a success return we want to mask
        gsuccess_mask_funcs = ["get_state", "get_axis", "get_coords", "get_root_coords"]

        for event_class in event_member_classes:
            override_class = type(event_class, (getattr(Gdk, event_class),), {})
            # add the event methods
            for method_info in Gdk.Event.__info__.get_methods():
                name = method_info.get_name()
                event_method = getattr(Gdk.Event, name)

                # use the _gsuccess_mask decorator if this method is whitelisted
                if name in gsuccess_mask_funcs:
                    event_method = strip_boolean_result(event_method)
                setattr(override_class, name, event_method)

            setattr(module, event_class, override_class)
            __all__.append(event_class)

        # end GdkEvent overrides

        class DragContext(Gdk.DragContext):
            def finish(self, success, del_, time):
                Gtk = get_introspection_module("Gtk")
                Gtk.drag_finish(self, success, del_, time)

        DragContext = override(DragContext)
        __all__.append("DragContext")

        class Cursor(Gdk.Cursor):
            def __new__(cls, *args, **kwds):
                arg_len = len(args)
                kwd_len = len(kwds)
                total_len = arg_len + kwd_len

                if total_len == 1:
                    # Since g_object_newv (super.__new__) does not seem valid for
                    # direct use with GdkCursor, we must assume usage of at least
                    # one of the C constructors to be valid.
                    return cls.new(*args, **kwds)

                if total_len == 2:
                    warnings.warn(
                        'Calling "Gdk.Cursor(display, cursor_type)" has been deprecated. '
                        "Please use Gdk.Cursor.new_for_display(display, cursor_type). "
                        "See: https://pygobject.gnome.org/devguide/initializer_deprecations.html",
                        PyGIDeprecationWarning,
                    )
                    return cls.new_for_display(*args, **kwds)

                if total_len == 4:
                    warnings.warn(
                        'Calling "Gdk.Cursor(display, pixbuf, x, y)" has been deprecated. '
                        "Please use Gdk.Cursor.new_from_pixbuf(display, pixbuf, x, y). "
                        "See: https://pygobject.gnome.org/devguide/initializer_deprecations.html",
                        PyGIDeprecationWarning,
                    )
                    return cls.new_from_pixbuf(*args, **kwds)

                raise ValueError("Wrong number of parameters")

        Cursor = override(Cursor)
        __all__.append("Cursor")

        # Gdk.Color was deprecated since 3.14 and dropped in Gtk-4.0
        color_parse = strip_boolean_result(Gdk.color_parse)
        __all__.append("color_parse")

        # Note, we cannot override the entire class as Gdk.Atom has no gtype, so just
        # hack some individual methods
        def _gdk_atom_str(atom):
            n = atom.name()
            if n:
                return n
            # fall back to atom index
            return f"Gdk.Atom<{hash(atom):d}>"

        def _gdk_atom_repr(atom):
            n = atom.name()
            if n:
                return f'Gdk.Atom.intern("{n}", False)'
            # fall back to atom index
            return f"<Gdk.Atom({hash(atom):d})>"

        Gdk.Atom.__str__ = _gdk_atom_str
        Gdk.Atom.__repr__ = _gdk_atom_repr

    if GDK4:
        from gi.repository import Gio

        class FileList(Gdk.FileList):
            if hasattr(Gdk.FileList, "new_from_list"):

                def __new__(cls, files):
                    files_list = []
                    if isinstance(files, (tuple, list)):
                        for f in files:
                            if isinstance(f, Gio.File):
                                files_list.append(f)
                            else:
                                raise TypeError(
                                    "Constructor requires a list or tuple of Gio.File instances"
                                )
                    else:
                        raise TypeError(
                            "Constructor requires a list or tuple of Gio.File instances"
                        )
                    return Gdk.FileList.new_from_list(files)

            def __iter__(self):
                return iter(self.get_files())

            def __len__(self):
                return len(self.get_files())

            def __getitem__(self, index):
                return self.get_files()[index]

        FileList = override(FileList)
        __all__.append("FileList")

    # constants
    if GDK3:
        SELECTION_PRIMARY = Gdk.atom_intern("PRIMARY", True)
        __all__.append("SELECTION_PRIMARY")

        SELECTION_SECONDARY = Gdk.atom_intern("SECONDARY", True)
        __all__.append("SELECTION_SECONDARY")

        SELECTION_CLIPBOARD = Gdk.atom_intern("CLIPBOARD", True)
        __all__.append("SELECTION_CLIPBOARD")

        TARGET_BITMAP = Gdk.atom_intern("BITMAP", True)
        __all__.append("TARGET_BITMAP")

        TARGET_COLORMAP = Gdk.atom_intern("COLORMAP", True)
        __all__.append("TARGET_COLORMAP")

        TARGET_DRAWABLE = Gdk.atom_intern("DRAWABLE", True)
        __all__.append("TARGET_DRAWABLE")

        TARGET_PIXMAP = Gdk.atom_intern("PIXMAP", True)
        __all__.append("TARGET_PIXMAP")

        TARGET_STRING = Gdk.atom_intern("STRING", True)
        __all__.append("TARGET_STRING")

        SELECTION_TYPE_ATOM = Gdk.atom_intern("ATOM", True)
        __all__.append("SELECTION_TYPE_ATOM")

        SELECTION_TYPE_BITMAP = Gdk.atom_intern("BITMAP", True)
        __all__.append("SELECTION_TYPE_BITMAP")

        SELECTION_TYPE_COLORMAP = Gdk.atom_intern("COLORMAP", True)
        __all__.append("SELECTION_TYPE_COLORMAP")

        SELECTION_TYPE_DRAWABLE = Gdk.atom_intern("DRAWABLE", True)
        __all__.append("SELECTION_TYPE_DRAWABLE")

        SELECTION_TYPE_INTEGER = Gdk.atom_intern("INTEGER", True)
        __all__.append("SELECTION_TYPE_INTEGER")

        SELECTION_TYPE_PIXMAP = Gdk.atom_intern("PIXMAP", True)
        __all__.append("SELECTION_TYPE_PIXMAP")

        SELECTION_TYPE_WINDOW = Gdk.atom_intern("WINDOW", True)
        __all__.append("SELECTION_TYPE_WINDOW")

        SELECTION_TYPE_STRING = Gdk.atom_intern("STRING", True)
        __all__.append("SELECTION_TYPE_STRING")

    if GDK4 and not hasattr(Gdk.PaintableFlags, "SIZE"):
        Gdk.PaintableFlags.SIZE = getattr(Gdk.PaintableFlags, "STATIC_SIZE")
        Gdk.PaintableFlags.CONTENTS = getattr(Gdk.PaintableFlags, "STATIC_CONTENTS")

    if GDK3 and get_option("legacy_autoinit"):
        import sys

        initialized, argv = Gdk.init_check(sys.argv)