File indexing completed on 2024-04-21 05:47:01

0001 /*****************************************************************************
0002  *   Copyright 2003 - 2010 Craig Drummond <craig.p.drummond@gmail.com>       *
0003  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0004  *                                                                           *
0005  *   This program is free software; you can redistribute it and/or modify    *
0006  *   it under the terms of the GNU Lesser General Public License as          *
0007  *   published by the Free Software Foundation; either version 2.1 of the    *
0008  *   License, or (at your option) version 3, or any later version accepted   *
0009  *   by the membership of KDE e.V. (or its successor approved by the         *
0010  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0011  *   Section 6 of version 3 of the license.                                  *
0012  *                                                                           *
0013  *   This program is distributed in the hope that it will be useful,         *
0014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0016  *   Lesser General Public License for more details.                         *
0017  *                                                                           *
0018  *   You should have received a copy of the GNU Lesser General Public        *
0019  *   License along with this library. If not,                                *
0020  *   see <http://www.gnu.org/licenses/>.                                     *
0021  *****************************************************************************/
0022 
0023 #include "scrolledwindow.h"
0024 
0025 #include "qt_settings.h"
0026 
0027 #include <qtcurve-utils/gtkprops.h>
0028 #include <qtcurve-cairo/utils.h>
0029 #include <common/common.h>
0030 
0031 namespace QtCurve {
0032 namespace ScrolledWindow {
0033 
0034 static void
0035 cleanup(GtkWidget *widget)
0036 {
0037     GtkWidgetProps props(widget);
0038     if (widget && props->scrolledWindowHacked) {
0039         props->scrolledWindowDestroy.disconn();
0040         props->scrolledWindowUnrealize.disconn();
0041         props->scrolledWindowStyleSet.disconn();
0042         if (opts.unifyCombo && opts.unifySpin) {
0043             props->scrolledWindowEnter.disconn();
0044             props->scrolledWindowLeave.disconn();
0045         }
0046         props->scrolledWindowFocusIn.disconn();
0047         props->scrolledWindowFocusOut.disconn();
0048         props->scrolledWindowHacked = false;
0049     }
0050 }
0051 
0052 static gboolean
0053 styleSet(GtkWidget *widget, GtkStyle*, void*)
0054 {
0055     cleanup(widget);
0056     return false;
0057 }
0058 
0059 static gboolean
0060 destroy(GtkWidget *widget, GdkEvent*, void*)
0061 {
0062     cleanup(widget);
0063     return false;
0064 }
0065 
0066 static GtkWidget *focusWidget = nullptr;
0067 static GtkWidget *hoverWidget = nullptr;
0068 
0069 static gboolean
0070 enter(GtkWidget *widget, GdkEventMotion*, void *data)
0071 {
0072     GtkWidget *w = data ? (GtkWidget*)data : widget;
0073     if (GTK_IS_SCROLLED_WINDOW(w) && hoverWidget != w) {
0074         hoverWidget = w;
0075         gtk_widget_queue_draw(w);
0076     }
0077     return false;
0078 }
0079 
0080 static gboolean
0081 leave(GtkWidget *widget, GdkEventMotion*, void *data)
0082 {
0083     GtkWidget *w = data ? (GtkWidget*)data : widget;
0084     if (GTK_IS_SCROLLED_WINDOW(w) && hoverWidget == w) {
0085         hoverWidget = nullptr;
0086         gtk_widget_queue_draw(w);
0087     }
0088     return false;
0089 }
0090 
0091 static gboolean
0092 focusIn(GtkWidget *widget, GdkEventMotion*, void *data)
0093 {
0094     GtkWidget *w = data ? (GtkWidget*)data : widget;
0095     if (GTK_IS_SCROLLED_WINDOW(w) && focusWidget != w) {
0096         focusWidget = w;
0097         gtk_widget_queue_draw(w);
0098     }
0099     return false;
0100 }
0101 
0102 static gboolean
0103 focusOut(GtkWidget *widget, GdkEventMotion*, void *data)
0104 {
0105     GtkWidget *w = data ? (GtkWidget*)data : widget;
0106     if (GTK_IS_SCROLLED_WINDOW(w) && focusWidget == w) {
0107         focusWidget = nullptr;
0108         gtk_widget_queue_draw(w);
0109     }
0110     return false;
0111 }
0112 
0113 static void
0114 setupConnections(GtkWidget *widget, GtkWidget *parent)
0115 {
0116     GtkWidgetProps props(widget);
0117     if (widget && !props->scrolledWindowHacked) {
0118         props->scrolledWindowHacked = true;
0119         gtk_widget_add_events(widget, GDK_LEAVE_NOTIFY_MASK |
0120                               GDK_ENTER_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK);
0121         props->scrolledWindowDestroy.conn("destroy-event", destroy, parent);
0122         props->scrolledWindowUnrealize.conn("unrealize", destroy, parent);
0123         props->scrolledWindowStyleSet.conn("style-set", styleSet, parent);
0124         if (opts.unifyCombo && opts.unifySpin) {
0125             props->scrolledWindowEnter.conn("enter-notify-event",
0126                                             enter, parent);
0127             props->scrolledWindowLeave.conn("leave-notify-event",
0128                                             leave, parent);
0129         }
0130         props->scrolledWindowFocusIn.conn("focus-in-event", focusIn, parent);
0131         props->scrolledWindowFocusOut.conn("focus-out-event", focusOut, parent);
0132         if (parent && opts.unifyCombo && opts.unifySpin) {
0133             QtcRect alloc = Widget::getAllocation(parent);
0134             int x;
0135             int y;
0136             gdk_window_get_pointer(gtk_widget_get_window(parent),
0137                                    &x, &y, nullptr);
0138             if (x >= 0 && x <alloc.width && y >= 0 && y < alloc.height) {
0139                 hoverWidget = parent;
0140             }
0141         }
0142     }
0143 }
0144 
0145 void
0146 setup(GtkWidget *widget)
0147 {
0148     GtkWidgetProps props(widget);
0149     if (widget && GTK_IS_SCROLLED_WINDOW(widget) &&
0150         !props->scrolledWindowHacked) {
0151         GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(widget);
0152         GtkWidget *child;
0153 
0154         if ((child = gtk_scrolled_window_get_hscrollbar(scrolledWindow))) {
0155             setupConnections(child, widget);
0156         }
0157         if ((child = gtk_scrolled_window_get_vscrollbar(scrolledWindow))) {
0158             setupConnections(child, widget);
0159         }
0160         if ((child = gtk_bin_get_child(GTK_BIN(widget)))) {
0161             if (GTK_IS_TREE_VIEW(child) || GTK_IS_TEXT_VIEW(child) ||
0162                 GTK_IS_ICON_VIEW(child)) {
0163                 setupConnections(child, widget);
0164             } else if (oneOf(gTypeName(child), "ExoIconView",
0165                              "FMIconContainer")) {
0166                 setupConnections(child, widget);
0167             }
0168         }
0169         props->scrolledWindowHacked = true;
0170     }
0171 }
0172 
0173 void
0174 registerChild(GtkWidget *child)
0175 {
0176     GtkWidget *parent = child ? gtk_widget_get_parent(child) : nullptr;
0177 
0178     GtkWidgetProps parentProps(parent);
0179     if (parent && GTK_IS_SCROLLED_WINDOW(parent) &&
0180         parentProps->scrolledWindowHacked) {
0181         setupConnections(child, parent);
0182     }
0183 }
0184 
0185 bool
0186 hasFocus(GtkWidget *widget)
0187 {
0188     return widget && (gtk_widget_has_focus(widget) || widget == focusWidget);
0189 }
0190 
0191 bool
0192 hovered(GtkWidget *widget)
0193 {
0194     return widget && (gtk_widget_get_state(widget) == GTK_STATE_PRELIGHT ||
0195                       widget == hoverWidget);
0196 }
0197 
0198 }
0199 }