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