1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/hyperlink.cpp
3 // Purpose:     Hyperlink control
4 // Author:      Francesco Montorsi
5 // Created:     14/2/2007
6 // Copyright:   (c) 2007 Francesco Montorsi
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 // ============================================================================
11 // declarations
12 // ============================================================================
13 
14 // --------------------------------------------------------------------------
15 // headers
16 // --------------------------------------------------------------------------
17 
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20 
21 
22 #if wxUSE_HYPERLINKCTRL && defined(__WXGTK210__) && !defined(__WXUNIVERSAL__)
23 
24 #include "wx/hyperlink.h"
25 
26 #ifndef WX_PRECOMP
27     #include "wx/settings.h"
28 #endif
29 
30 #include "wx/gtk/private.h"
31 
32 // ----------------------------------------------------------------------------
33 // local functions
34 // ----------------------------------------------------------------------------
35 
UseNative()36 static inline bool UseNative()
37 {
38     // native gtk_link_button widget is only available in GTK+ 2.10 and later
39     return wx_is_at_least_gtk2(10);
40 }
41 
42 // ============================================================================
43 // implementation
44 // ============================================================================
45 
46 // ----------------------------------------------------------------------------
47 // "clicked"
48 // ----------------------------------------------------------------------------
49 
50 #ifdef __WXGTK3__
51 extern "C" {
activate_link(GtkWidget *,wxHyperlinkCtrl * win)52 static gboolean activate_link(GtkWidget*, wxHyperlinkCtrl* win)
53 {
54     win->SetVisited(true);
55     win->SendEvent();
56     return true;
57 }
58 }
59 #else
60 static GSList* gs_hyperlinkctrl_list;
61 extern "C" {
clicked_hook(GtkLinkButton * button,const char *,void *)62 static void clicked_hook(GtkLinkButton* button, const char*, void*)
63 {
64     for (GSList* p = gs_hyperlinkctrl_list; p; p = p->next)
65     {
66         wxHyperlinkCtrl* win = static_cast<wxHyperlinkCtrl*>(p->data);
67         if (win->m_widget == (GtkWidget*)button)
68         {
69             win->SetVisited(true);
70             win->SendEvent();
71             return;
72         }
73     }
74     gtk_link_button_set_uri_hook(NULL, NULL, NULL);
75     GTK_BUTTON_GET_CLASS(button)->clicked(GTK_BUTTON(button));
76     gtk_link_button_set_uri_hook(clicked_hook, NULL, NULL);
77 }
78 }
79 #endif
80 
81 // ----------------------------------------------------------------------------
82 // wxHyperlinkCtrl
83 // ----------------------------------------------------------------------------
84 
wxHyperlinkCtrl()85 wxHyperlinkCtrl::wxHyperlinkCtrl()
86 {
87 }
88 
wxHyperlinkCtrl(wxWindow * parent,wxWindowID id,const wxString & label,const wxString & url,const wxPoint & pos,const wxSize & size,long style,const wxString & name)89 wxHyperlinkCtrl::wxHyperlinkCtrl(wxWindow *parent,
90                                  wxWindowID id,
91                                  const wxString& label,
92                                  const wxString& url,
93                                  const wxPoint& pos,
94                                  const wxSize& size,
95                                  long style,
96                                  const wxString& name)
97 {
98     (void)Create(parent, id, label, url, pos, size, style, name);
99 }
100 
~wxHyperlinkCtrl()101 wxHyperlinkCtrl::~wxHyperlinkCtrl()
102 {
103 #ifndef __WXGTK3__
104     gs_hyperlinkctrl_list = g_slist_remove(gs_hyperlinkctrl_list, this);
105 #endif
106 }
107 
Create(wxWindow * parent,wxWindowID id,const wxString & label,const wxString & url,const wxPoint & pos,const wxSize & size,long style,const wxString & name)108 bool wxHyperlinkCtrl::Create(wxWindow *parent, wxWindowID id,
109     const wxString& label, const wxString& url, const wxPoint& pos,
110     const wxSize& size, long style, const wxString& name)
111 {
112     if ( UseNative() )
113     {
114         // do validation checks:
115         CheckParams(label, url, style);
116 
117         if (!PreCreation( parent, pos, size ) ||
118             !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
119         {
120             wxFAIL_MSG( wxT("wxHyperlinkCtrl creation failed") );
121             return false;
122         }
123 
124         m_widget = gtk_link_button_new("asdfsaf asdfdsaf asdfdsa");
125         g_object_ref(m_widget);
126 
127         // alignment
128         float x_alignment = 0.5f;
129         if (HasFlag(wxHL_ALIGN_LEFT))
130             x_alignment = 0;
131         else if (HasFlag(wxHL_ALIGN_RIGHT))
132             x_alignment = 1;
133 
134         wxGCC_WARNING_SUPPRESS(deprecated-declarations)
135         gtk_button_set_alignment(GTK_BUTTON(m_widget), x_alignment, 0.5f);
136         wxGCC_WARNING_RESTORE()
137 
138         // set to non empty strings both the url and the label
139         SetURL(url.empty() ? label : url);
140         SetLabel(label.empty() ? url : label);
141 
142 #ifdef __WXGTK3__
143         g_signal_connect(m_widget, "activate_link", G_CALLBACK(activate_link), this);
144 #else
145         gs_hyperlinkctrl_list = g_slist_prepend(gs_hyperlinkctrl_list, this);
146         gtk_link_button_set_uri_hook(clicked_hook, NULL, NULL);
147 #endif
148 
149         m_parent->DoAddChild( this );
150 
151         PostCreation(size);
152 
153         // wxWindowGTK will connect to the enter_notify and leave_notify GTK+ signals
154         // thus overriding GTK+'s internal signal handlers which set the cursor of
155         // the widget - thus we need to manually set it here:
156         SetCursor(wxCursor(wxCURSOR_HAND));
157     }
158     else
159         return wxGenericHyperlinkCtrl::Create(parent, id, label, url, pos, size, style, name);
160 
161     return true;
162 }
163 
DoGetBestSize() const164 wxSize wxHyperlinkCtrl::DoGetBestSize() const
165 {
166     if ( UseNative() )
167         return wxControl::DoGetBestSize();
168     return wxGenericHyperlinkCtrl::DoGetBestSize();
169 }
170 
DoGetBestClientSize() const171 wxSize wxHyperlinkCtrl::DoGetBestClientSize() const
172 {
173     if ( UseNative() )
174         return wxControl::DoGetBestClientSize();
175     return wxGenericHyperlinkCtrl::DoGetBestClientSize();
176 }
177 
SetLabel(const wxString & label)178 void wxHyperlinkCtrl::SetLabel(const wxString &label)
179 {
180     if ( UseNative() )
181     {
182         wxControl::SetLabel(label);
183         const wxString labelGTK = GTKConvertMnemonics(label);
184         gtk_button_set_label(GTK_BUTTON(m_widget), wxGTK_CONV(labelGTK));
185     }
186     else
187         wxGenericHyperlinkCtrl::SetLabel(label);
188 }
189 
SetURL(const wxString & uri)190 void wxHyperlinkCtrl::SetURL(const wxString &uri)
191 {
192     if ( UseNative() )
193         gtk_link_button_set_uri(GTK_LINK_BUTTON(m_widget), wxGTK_CONV(uri));
194     else
195         wxGenericHyperlinkCtrl::SetURL(uri);
196 }
197 
GetURL() const198 wxString wxHyperlinkCtrl::GetURL() const
199 {
200     if ( UseNative() )
201     {
202         const gchar *str = gtk_link_button_get_uri(GTK_LINK_BUTTON(m_widget));
203         return wxString::FromUTF8(str);
204     }
205 
206     return wxGenericHyperlinkCtrl::GetURL();
207 }
208 
SetNormalColour(const wxColour & colour)209 void wxHyperlinkCtrl::SetNormalColour(const wxColour &colour)
210 {
211     if ( UseNative() )
212     {
213         // simply do nothing: GTK+ does not allow us to change it :(
214     }
215     else
216         wxGenericHyperlinkCtrl::SetNormalColour(colour);
217 }
218 
GetNormalColour() const219 wxColour wxHyperlinkCtrl::GetNormalColour() const
220 {
221     return UseNative()
222         ? wxSystemSettings::GetColour(wxSYS_COLOUR_HOTLIGHT)
223         : wxGenericHyperlinkCtrl::GetNormalColour();
224 }
225 
SetVisitedColour(const wxColour & colour)226 void wxHyperlinkCtrl::SetVisitedColour(const wxColour &colour)
227 {
228     if ( UseNative() )
229     {
230         // simply do nothing: GTK+ does not allow us to change it :(
231     }
232     else
233         wxGenericHyperlinkCtrl::SetVisitedColour(colour);
234 }
235 
GetVisitedColour() const236 wxColour wxHyperlinkCtrl::GetVisitedColour() const
237 {
238     wxColour ret;
239     if ( UseNative() )
240     {
241         GdkColor* link_color;
242         GdkColor color = { 0, 0x5555, 0x1a1a, 0x8b8b };
243 
244         GtkWidget* widget = gtk_bin_get_child(GTK_BIN(m_widget));
245         wxGCC_WARNING_SUPPRESS(deprecated-declarations)
246         gtk_widget_ensure_style(widget);
247         gtk_widget_style_get(widget, "visited-link-color", &link_color, NULL);
248         if (link_color)
249         {
250             color = *link_color;
251             gdk_color_free(link_color);
252         }
253         wxGCC_WARNING_RESTORE()
254         ret = wxColour(color);
255     }
256     else
257         ret = base_type::GetVisitedColour();
258 
259     return ret;
260 }
261 
SetVisited(bool visited)262 void wxHyperlinkCtrl::SetVisited(bool visited)
263 {
264     base_type::SetVisited(visited);
265 #if GTK_CHECK_VERSION(2,14,0)
266     if (wx_is_at_least_gtk2(14))
267     {
268         gtk_link_button_set_visited(GTK_LINK_BUTTON(m_widget), visited);
269     }
270 #endif
271 }
272 
GetVisited() const273 bool wxHyperlinkCtrl::GetVisited() const
274 {
275 #if GTK_CHECK_VERSION(2,14,0)
276     if (wx_is_at_least_gtk2(14))
277     {
278         return gtk_link_button_get_visited(GTK_LINK_BUTTON(m_widget)) != 0;
279     }
280 #endif
281     return base_type::GetVisited();
282 }
283 
SetHoverColour(const wxColour & colour)284 void wxHyperlinkCtrl::SetHoverColour(const wxColour &colour)
285 {
286     if ( UseNative() )
287     {
288         // simply do nothing: GTK+ does not allow us to change it :(
289     }
290     else
291         wxGenericHyperlinkCtrl::SetHoverColour(colour);
292 }
293 
GetHoverColour() const294 wxColour wxHyperlinkCtrl::GetHoverColour() const
295 {
296     if ( UseNative() )
297     {
298         // hover colour == normal colour for native GTK+ widget
299         return GetNormalColour();
300     }
301 
302     return wxGenericHyperlinkCtrl::GetHoverColour();
303 }
304 
GTKGetWindow(wxArrayGdkWindows & windows) const305 GdkWindow *wxHyperlinkCtrl::GTKGetWindow(wxArrayGdkWindows& windows) const
306 {
307     return UseNative() ? gtk_button_get_event_window(GTK_BUTTON(m_widget))
308                        : wxGenericHyperlinkCtrl::GTKGetWindow(windows);
309 }
310 
311 #endif // wxUSE_HYPERLINKCTRL && GTK+ 2.10+
312