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