File indexing completed on 2024-04-28 05:32:12

0001 #ifndef oxygengtkutils_h
0002 #define oxygengtkutils_h
0003 /*
0004 * this file is part of the oxygen gtk engine
0005 * SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0006 * SPDX-FileCopyrightText: 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
0007 *
0008 * GdkPixbuf modification code from Walmis
0009 * <http://gnome-look.org/content/show.php?content=77783&forumpage=3>
0010 *
0011 * SPDX-License-Identifier: LGPL-2.0-or-later
0012 */
0013 
0014 #include <gdk/gdk.h>
0015 #include <gtk/gtk.h>
0016 #include <string>
0017 
0018 #include "oxygenrgba.h"
0019 
0020 namespace Oxygen
0021 {
0022 
0023     //! GdkRectangle streamer
0024     inline std::ostream& operator << (std::ostream& out, const GdkRectangle& rect )
0025     {
0026         out << "( " << rect.x << "," << rect.y << "," << rect.width << "," << rect.height << ")";
0027         return out;
0028     }
0029 
0030     //! GtkBorder streamer
0031     inline std::ostream& operator << (std::ostream& out, const GtkBorder& border )
0032     {
0033         out << "( " << border.left << "," << border.right << "," << border.top << "," << border.bottom << ")";
0034         return out;
0035     }
0036 
0037     //! GtkContainer streamer
0038     inline std::ostream& operator << (std::ostream& out, GtkContainer* container)
0039     {
0040         GList* children=gtk_container_get_children(container);
0041         for(GList* child=g_list_first(children); child; child=g_list_next(child))
0042         {
0043             out << G_OBJECT_TYPE_NAME(child->data) << " ";
0044         }
0045         g_list_free(children);
0046         return out;
0047     }
0048 
0049     namespace Gtk
0050     {
0051 
0052         //! mouse button enumeration
0053         enum MouseButton
0054         {
0055             NoButton = 0,
0056             LeftButton = 1,
0057             RightButton = 2,
0058             MidButton = 3
0059         };
0060 
0061         //@!name gdk utilities
0062         //@{
0063 
0064         //! returns OxygenRgba color from GdkColor
0065         inline ColorUtils::Rgba gdk_get_color( const GdkColor& color )
0066         {
0067             return ColorUtils::Rgba(
0068                 double(color.red)/0xffff,
0069                 double(color.green)/0xffff,
0070                 double(color.blue)/0xffff );
0071         }
0072 
0073         //! map window origin to top level
0074         /*!
0075         x and y correspond to (0,0) maped to toplevel window;
0076         w and h correspond to toplevel window frame size
0077         */
0078         bool gdk_window_map_to_toplevel( GdkWindow*, gint*, gint*, gint*, gint*, bool frame = false );
0079 
0080         //! map widget origin to top level
0081         /*!
0082         x and y correspond to (0,0) maped to toplevel window;
0083         w and h correspond to toplevel window frame size
0084         */
0085         bool gtk_widget_map_to_toplevel( GtkWidget*, gint*, gint*, gint*, gint*, bool frame = false );
0086 
0087         //! map widget onto another (parent) widget
0088         /*! second argument can be any parent in widget's ancestry tree */
0089         bool gtk_widget_map_to_parent( GtkWidget*, GtkWidget*, gint*, gint*, gint*, gint* );
0090 
0091         //! map window/widget origin to top level
0092         inline bool gdk_map_to_toplevel( GdkWindow* window, GtkWidget* widget, gint* x, gint* y, gint* w, gint* h, bool frame = false )
0093         {
0094             if( window && GDK_IS_WINDOW( window ) ) return gdk_window_map_to_toplevel( window, x, y, w, h, frame );
0095             else return gtk_widget_map_to_toplevel( widget, x, y, w, h, frame );
0096         }
0097 
0098         //! map window origin to top level
0099         inline bool gdk_map_to_toplevel( GdkWindow* window, gint* x, gint* y, gint* w, gint* h, bool frame = false )
0100         { return gdk_window_map_to_toplevel( window, x, y, w, h, frame ); }
0101 
0102         //! translate origin of child window into parent
0103         /*! returns true on success */
0104         bool gdk_window_translate_origin( GdkWindow*, GdkWindow*, gint*, gint* );
0105 
0106         //! get top level windows dimension
0107         void gdk_toplevel_get_size( GdkWindow*, gint*, gint* );
0108 
0109         //! get top level windows dimension
0110         void gdk_toplevel_get_frame_size( GdkWindow*, gint*, gint* );
0111 
0112         //! get position relatve to toplevel
0113         void gdk_window_get_toplevel_origin( GdkWindow*, gint*, gint* );
0114 
0115         //! add alpha channel to pixbuf
0116         GdkPixbuf* gdk_pixbuf_set_alpha( const GdkPixbuf*, double );
0117 
0118         //! changes the gamma value of an image
0119         bool gdk_pixbuf_to_gamma( GdkPixbuf* pixbuf, double value );
0120 
0121         //! resize pixbuf
0122         GdkPixbuf* gdk_pixbuf_resize( GdkPixbuf* src, int width, int height );
0123 
0124         //! returns initialized GdkRectangle
0125         inline GdkRectangle gdk_rectangle( int x = 0, int y = 0, int w = -1, int h = -1 )
0126         {
0127             GdkRectangle out = {x, y, w, h};
0128             return out;
0129         }
0130 
0131         //! returns true if rectangle is valid
0132         inline bool gdk_rectangle_is_valid( const GdkRectangle* rect )
0133         { return rect && rect->width > 0 && rect->height > 0; }
0134 
0135         //! performs union of two rectangle, properly accounting for their validity
0136         inline void gdk_rectangle_union( const GdkRectangle* first, const GdkRectangle* second, GdkRectangle* out )
0137         {
0138             if( !out ) return;
0139             const bool firstIsValid( Gtk::gdk_rectangle_is_valid( first ) );
0140             const bool secondIsValid( Gtk::gdk_rectangle_is_valid( second ) );
0141             if( firstIsValid && secondIsValid )  ::gdk_rectangle_union( first, second, out );
0142             else if( secondIsValid ) *out = *second;
0143             else *out = *first;
0144         }
0145 
0146         //! returns true if given rectangle contains point
0147         inline bool gdk_rectangle_contains( const GdkRectangle* rect, int x, int y )
0148         {
0149             return
0150                 rect &&
0151                 ( rect->x <= x && (rect->x + rect->width) > x ) &&
0152                 ( rect->y <= y && (rect->y + rect->height) > y );
0153         }
0154 
0155         //@}
0156 
0157         //! returns true if widget's layout is reversed
0158         inline bool gtk_widget_layout_is_reversed( GtkWidget* widget )
0159         { return widget ? gtk_widget_get_direction( widget ) == GTK_TEXT_DIR_RTL : false; }
0160 
0161         //! set all buttons in the container to state NORMAL
0162         void gtk_container_adjust_buttons_state( GtkContainer*, gpointer=0L );
0163 
0164         //! returns widget allocation
0165         inline GtkAllocation gtk_widget_get_allocation( GtkWidget* widget )
0166         {
0167             #if GTK_CHECK_VERSION(2, 18, 0)
0168             GtkAllocation allocation = { 0, 0, -1, -1 };
0169             ::gtk_widget_get_allocation( widget, &allocation );
0170             return allocation;
0171             #else
0172             assert( widget );
0173             return widget->allocation;
0174             #endif
0175 
0176         }
0177 
0178         //! returns true if widget is a groupbox (a la Qt)
0179         inline bool gtk_widget_is_groupbox( GtkWidget* widget )
0180         {
0181             return
0182                 GTK_IS_FRAME( widget ) &&
0183                 gtk_frame_get_label_widget( GTK_FRAME( widget ) ) &&
0184                 gtk_frame_get_shadow_type( GTK_FRAME( widget ) ) == GTK_SHADOW_OUT;
0185         }
0186 
0187         //! returns true if widget (or one of its parent) has a custom background
0188         bool gtk_widget_has_custom_background( GtkWidget*, GtkStateType = GTK_STATE_NORMAL );
0189 
0190         //! returns true if is an Gnome applet
0191         bool gtk_widget_is_applet( GtkWidget* );
0192 
0193         //! print some widget information
0194         void gtk_widget_print_tree( GtkWidget* );
0195 
0196         //! returns true if widget supports rgba
0197         bool gtk_widget_has_rgba( GtkWidget* );
0198 
0199         //! returns true if default screen is composited
0200         bool gdk_default_screen_is_composited( void );
0201 
0202         //! returns true if window supports rgba
0203         bool gdk_window_has_rgba( GdkWindow* );
0204 
0205         //! true if visual supports rgba
0206         bool gdk_visual_has_rgba( GdkVisual* );
0207 
0208         //! returns true if window is a base window
0209         bool gdk_window_is_base( GdkWindow* );
0210 
0211         //! returns true if window is a base window that do not need painting
0212         bool gdk_window_nobackground( GdkWindow* );
0213 
0214         //! true if object match a given type
0215         bool g_object_is_a( const GObject*, const std::string& );
0216 
0217         //! trigger area update using GdkRectangle
0218         inline void gtk_widget_queue_draw( GtkWidget* widget, const GdkRectangle* rect = 0L )
0219         {
0220             if( !gdk_rectangle_is_valid( rect ) ) ::gtk_widget_queue_draw( widget );
0221             else ::gtk_widget_queue_draw_area( widget, rect->x, rect->y, rect->width, rect->height );
0222         }
0223 
0224         //!@name check parent type
0225         //@{
0226 
0227         //! returns widget path as a string
0228         std::string gtk_widget_path( GtkWidget* );
0229 
0230         //! return parent of given type if any
0231         GtkWidget* gtk_widget_find_parent( GtkWidget*, GType );
0232 
0233         //! return parent of given type
0234         inline GtkWidget* gtk_widget_find_parent( GtkWidget* widget, const std::string& typeName )
0235         {
0236             const GType tmp( g_type_from_name( typeName.c_str() ) );
0237             return tmp ? gtk_widget_find_parent( widget, tmp ): 0L;
0238         }
0239 
0240         //! return parent "group box" if any.
0241         GtkWidget* gtk_parent_groupbox( GtkWidget* widget );
0242 
0243         //! return parent button if any.
0244         inline GtkWidget* gtk_parent_button( GtkWidget* widget )
0245         { return gtk_widget_find_parent( widget, GTK_TYPE_BUTTON ); }
0246 
0247         //! return parent menu if any
0248         inline GtkWidget* gtk_parent_menubar( GtkWidget* widget )
0249         { return gtk_widget_find_parent( widget, GTK_TYPE_MENU_BAR ); }
0250 
0251         //! return parent menu if any
0252         inline GtkWidget* gtk_parent_menu( GtkWidget* widget )
0253         { return gtk_widget_find_parent( widget, GTK_TYPE_MENU ); }
0254 
0255         //! return parent treeview if any.
0256         inline GtkWidget* gtk_parent_tree_view( GtkWidget* widget )
0257         { return gtk_widget_find_parent( widget, GTK_TYPE_TREE_VIEW ); }
0258 
0259         //! return parent combobox if any.
0260         inline GtkWidget* gtk_parent_combo( GtkWidget* widget )
0261         { return gtk_widget_find_parent( widget, GTK_TYPE_COMBO ); }
0262 
0263         //! return parent combobox if any.
0264         inline GtkWidget* gtk_parent_combobox( GtkWidget* widget )
0265         { return gtk_widget_find_parent( widget, GTK_TYPE_COMBO_BOX ); }
0266 
0267         //! return parent combobox if any.
0268         inline GtkWidget* gtk_parent_combobox_entry( GtkWidget* widget )
0269         {
0270             // try get parent combobox entry
0271             GtkWidget* out(0L);
0272             if( ( out = gtk_widget_find_parent( widget, GTK_TYPE_COMBO_BOX_ENTRY ) ) ) return out;
0273 
0274             // if not found, get parent combobox and check if it has an entry
0275             if( !(out = gtk_widget_find_parent( widget, GTK_TYPE_COMBO_BOX ) ) ) return 0L;
0276 
0277             #if GTK_CHECK_VERSION(2, 24, 0)
0278             return gtk_combo_box_get_has_entry( GTK_COMBO_BOX( out ) ) ? out:0L;
0279             #else
0280             return GTK_IS_ENTRY( gtk_bin_get_child( GTK_BIN( out ) ) ) ? out:0L;
0281             #endif
0282 
0283         }
0284 
0285         //! return parent scrolled window if any.
0286         inline GtkWidget* gtk_parent_scrolled_window( GtkWidget* widget )
0287         { return gtk_widget_find_parent( widget, GTK_TYPE_SCROLLED_WINDOW ); }
0288 
0289         //! return parent statusbar if any.
0290         inline GtkWidget* gtk_parent_statusbar( GtkWidget* widget )
0291         { return gtk_widget_find_parent( widget, GTK_TYPE_STATUSBAR ); }
0292 
0293         //! return parent combobox if any.
0294         inline GtkWidget* gtk_parent_notebook( GtkWidget* widget )
0295         { return gtk_widget_find_parent( widget, GTK_TYPE_NOTEBOOK ); }
0296 
0297         //! returns true if potentialParent is (maybe indirect) parent of widget
0298         bool gtk_widget_is_parent( GtkWidget*, GtkWidget* potentialParent );
0299 
0300         //! returns true if one of the parent widgets has a sunken shadow
0301         bool gtk_parent_is_shadow_in( GtkWidget* );
0302 
0303         //@}
0304 
0305         //! true if a widget (orientable) is horizontal
0306         inline bool gtk_widget_is_horizontal( GtkWidget* widget )
0307         {
0308             if( !GTK_IS_ORIENTABLE( widget ) ) return true;
0309             return gtk_orientable_get_orientation( GTK_ORIENTABLE( widget ) ) == GTK_ORIENTATION_HORIZONTAL;
0310         }
0311 
0312 
0313         //! true if a widget (orientable) is vertical
0314         inline bool gtk_widget_is_vertical( GtkWidget* widget )
0315         {
0316             if( !GTK_IS_ORIENTABLE( widget ) ) return false;
0317             return gtk_orientable_get_orientation( GTK_ORIENTABLE( widget ) ) == GTK_ORIENTATION_VERTICAL;
0318         }
0319 
0320         //! true if scrolled window must be forced to have a sunken frame
0321         bool gtk_scrolled_window_force_sunken( GtkWidget* );
0322 
0323         //! returns true if widget is a tooltip, useful when GTK_IS_TOOLTIP() gives false for real tooltip
0324         bool gtk_is_tooltip( GtkWidget* widget );
0325 
0326         //!@name button utilities
0327         //@{
0328 
0329         //! true for 'flat' buttons (e.g. toolbuttons)
0330         bool gtk_button_is_flat( GtkWidget* );
0331 
0332         //! true for treeview headers and affiliated
0333         bool gtk_button_is_header( GtkWidget* );
0334 
0335         //! true for buttons in path bars
0336         bool gtk_button_is_in_path_bar( GtkWidget* widget );
0337 
0338         //! true if widget is last in path bar
0339         bool gtk_path_bar_button_is_last( GtkWidget* widget );
0340 
0341         //! returns an image on button-container
0342         GtkWidget* gtk_button_find_image( GtkWidget* );
0343 
0344         //! returns an image on button-container
0345         GtkWidget* gtk_button_find_label( GtkWidget* );
0346 
0347         //@}
0348 
0349         //!@name combobox utilities
0350         //@{
0351 
0352         //! returns true if combobox has frame
0353         bool gtk_combobox_has_frame( GtkWidget* );
0354 
0355         //! true if widget is the treeview of a combobox
0356         bool gtk_combobox_is_tree_view( GtkWidget* );
0357 
0358         //! true if widget is the scrolled window of a combobox
0359         bool gtk_combobox_is_scrolled_window( GtkWidget* );
0360 
0361         //! true if widget is the viewport of a combo
0362         bool gtk_combo_is_viewport( GtkWidget* );
0363 
0364         //! true if widget is the frame of a combo
0365         bool gtk_combo_is_frame( GtkWidget* );
0366 
0367         //! true if widget is the popup window of a combobox
0368         bool gtk_combobox_is_popup( GtkWidget* );
0369 
0370         //! true if widget is the popup window of a combo
0371         bool gtk_combo_is_popup( GtkWidget* );
0372 
0373         //! true if combobox must appear as list
0374         bool gtk_combobox_appears_as_list( GtkWidget* );
0375 
0376         //@}
0377 
0378         //!@name notebook utilities
0379         //@{
0380 
0381         //! returns true if position is in hovered tab
0382         //* this should move to OxygenTabWidgetData
0383         bool gtk_notebook_tab_contains( GtkWidget*, int tab, int x, int y );
0384 
0385         //! returns tab matching position or -1 if none
0386         int gtk_notebook_find_tab( GtkWidget*, int x, int y );
0387 
0388         //! returns index of first visible tab
0389         int gtk_notebook_find_first_tab( GtkWidget* );
0390 
0391         //! returns true if widget is one of the notebook's tab labels
0392         bool gtk_notebook_is_tab_label( GtkNotebook*, GtkWidget* );
0393 
0394         //! returns tabbar rect in notebook
0395         void gtk_notebook_get_tabbar_rect( GtkNotebook*, GdkRectangle* );
0396 
0397         //! returns true if notebook has visible scrollbar arrows
0398         /*! arrows are dimmed visible if at least one of the child tab_labels is unmapped */
0399         bool gtk_notebook_has_visible_arrows( GtkNotebook* );
0400 
0401         // make all the buttons on the tabs normal
0402         bool gtk_notebook_update_close_buttons( GtkNotebook*);
0403 
0404         //! returns true if widget is a notebook close button
0405         bool gtk_notebook_is_close_button( GtkWidget* );
0406 
0407         //@}
0408 
0409         //! calculates viewport offsets (between view window and bin window
0410         void gtk_viewport_get_position( GtkViewport*, gint*, gint* );
0411 
0412         //! returns a widget which has response_id as response id for dialog
0413         GtkWidget* gtk_dialog_find_button( GtkDialog*, gint );
0414 
0415         //! store quarks
0416         class Quarks
0417         {
0418             public:
0419 
0420             //! parent class
0421             inline static GQuark rcStyle( void )
0422             {
0423 
0424                 // try initialize
0425                 if( !_rcStyle )
0426                 { _rcStyle = g_quark_try_string( "gtk-rc-style" ); }
0427 
0428                 return _rcStyle;
0429 
0430             }
0431 
0432 
0433             private:
0434 
0435             //! RC style quark
0436             /*!
0437             used to check whether an RCStyle was installed on a given widget or not.
0438             See gtkwidet::gtk_widget_get_modifier_style()
0439             */
0440             static GQuark _rcStyle;
0441 
0442         };
0443 
0444         //! returns true if widget style color is modified
0445         inline bool gtk_widget_style_is_modified( GtkWidget* widget, GtkStateType state, GtkRcFlags flag )
0446         {
0447             const bool hasRCStyle( g_object_get_qdata (G_OBJECT (widget), Quarks::rcStyle() ) );
0448             return ( hasRCStyle && gtk_widget_get_modifier_style(widget)->color_flags[state]&flag );
0449         }
0450 
0451 
0452     }
0453 
0454 }
0455 #endif