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