1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* Copyright (C) 2002-2007 Imendio AB
4
* Copyright (C) 2007 Collabora Ltd.
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation; either version 2 of the
9
* License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public
17
* License along with this program; if not, write to the
18
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
* Boston, MA 02111-1307, USA.
21
* Authors: Mikael Hallendal <micke@imendio.com>
22
* Richard Hult <richard@imendio.com>
23
* Martyn Russell <martyn@imendio.com>
24
* Xavier Claessens <xclaesse@gmail.com>
26
* Part of this file is copied from GtkSourceView (gtksourceiter.c):
33
#include <glib/gi18n.h>
35
#include <glade/glade.h>
36
#include <libgnome/libgnome.h>
38
#include <libmissioncontrol/mc-profile.h>
40
#include <libempathy/gossip-paths.h>
41
#include <libempathy/gossip-debug.h>
43
#include "gossip-ui-utils.h"
44
#include "empathy-images.h"
46
#define DEBUG_DOMAIN "UiUtils"
51
gboolean preserve_aspect_ratio;
55
get_glade_file (const gchar *filename,
58
const gchar *first_required_widget,
64
GtkWidget **widget_ptr;
66
path = gossip_paths_get_glade_path (filename);
67
gui = glade_xml_new (path, root, domain);
71
g_warning ("Couldn't find necessary glade file '%s'", filename);
75
for (name = first_required_widget; name; name = va_arg (args, char *)) {
76
widget_ptr = va_arg (args, void *);
78
*widget_ptr = glade_xml_get_widget (gui, name);
81
g_warning ("Glade file '%s' is missing widget '%s'.",
91
gossip_glade_get_file_simple (const gchar *filename,
94
const gchar *first_required_widget, ...)
99
va_start (args, first_required_widget);
101
gui = get_glade_file (filename,
104
first_required_widget,
113
g_object_unref (gui);
117
gossip_glade_get_file (const gchar *filename,
120
const gchar *first_required_widget, ...)
125
va_start (args, first_required_widget);
127
gui = get_glade_file (filename,
130
first_required_widget,
143
gossip_glade_connect (GladeXML *gui,
145
gchar *first_widget, ...)
153
va_start (args, first_widget);
155
for (name = first_widget; name; name = va_arg (args, char *)) {
156
signal = va_arg (args, void *);
157
callback = va_arg (args, void *);
159
widget = glade_xml_get_widget (gui, name);
161
g_warning ("Glade file is missing widget '%s', aborting",
166
g_signal_connect (widget,
168
G_CALLBACK (callback),
176
gossip_glade_setup_size_group (GladeXML *gui,
177
GtkSizeGroupMode mode,
178
gchar *first_widget, ...)
182
GtkSizeGroup *size_group;
185
va_start (args, first_widget);
187
size_group = gtk_size_group_new (mode);
189
for (name = first_widget; name; name = va_arg (args, char *)) {
190
widget = glade_xml_get_widget (gui, name);
192
g_warning ("Glade file is missing widget '%s'", name);
196
gtk_size_group_add_widget (size_group, widget);
199
g_object_unref (size_group);
205
gossip_pixbuf_from_icon_name (const gchar *icon_name,
206
GtkIconSize icon_size)
209
GdkPixbuf *pixbuf = NULL;
210
GError *error = NULL;
214
theme = gtk_icon_theme_get_default ();
216
if (gtk_icon_size_lookup (icon_size, &w, &h)) {
220
pixbuf = gtk_icon_theme_load_icon (theme,
226
gossip_debug (DEBUG_DOMAIN, "Error loading icon: %s", error->message);
227
g_clear_error (&error);
234
gossip_pixbuf_from_smiley (GossipSmiley type,
235
GtkIconSize icon_size)
237
const gchar *icon_id;
240
case GOSSIP_SMILEY_NORMAL: /* :) */
241
icon_id = "stock_smiley-1";
243
case GOSSIP_SMILEY_WINK: /* ;) */
244
icon_id = "stock_smiley-3";
246
case GOSSIP_SMILEY_BIGEYE: /* =) */
247
icon_id = "stock_smiley-2";
249
case GOSSIP_SMILEY_NOSE: /* :-) */
250
icon_id = "stock_smiley-7";
252
case GOSSIP_SMILEY_CRY: /* :'( */
253
icon_id = "stock_smiley-11";
255
case GOSSIP_SMILEY_SAD: /* :( */
256
icon_id = "stock_smiley-4";
258
case GOSSIP_SMILEY_SCEPTICAL: /* :/ */
259
icon_id = "stock_smiley-9";
261
case GOSSIP_SMILEY_BIGSMILE: /* :D */
262
icon_id = "stock_smiley-6";
264
case GOSSIP_SMILEY_INDIFFERENT: /* :| */
265
icon_id = "stock_smiley-8";
267
case GOSSIP_SMILEY_TOUNGE: /* :p */
268
icon_id = "stock_smiley-10";
270
case GOSSIP_SMILEY_SHOCKED: /* :o */
271
icon_id = "stock_smiley-5";
273
case GOSSIP_SMILEY_COOL: /* 8) */
274
icon_id = "stock_smiley-15";
276
case GOSSIP_SMILEY_SORRY: /* *| */
277
icon_id = "stock_smiley-12";
279
case GOSSIP_SMILEY_KISS: /* :* */
280
icon_id = "stock_smiley-13";
282
case GOSSIP_SMILEY_SHUTUP: /* :# */
283
icon_id = "stock_smiley-14";
285
case GOSSIP_SMILEY_YAWN: /* |O */
288
case GOSSIP_SMILEY_CONFUSED: /* :$ */
289
icon_id = "stock_smiley-17";
291
case GOSSIP_SMILEY_ANGEL: /* O) */
292
icon_id = "stock_smiley-18";
294
case GOSSIP_SMILEY_OOOH: /* :x */
295
icon_id = "stock_smiley-19";
297
case GOSSIP_SMILEY_LOOKAWAY: /* *) */
298
icon_id = "stock_smiley-20";
300
case GOSSIP_SMILEY_BLUSH: /* *S */
301
icon_id = "stock_smiley-23";
303
case GOSSIP_SMILEY_COOLBIGSMILE: /* 8D */
304
icon_id = "stock_smiley-25";
306
case GOSSIP_SMILEY_ANGRY: /* :@ */
307
icon_id = "stock_smiley-16";
309
case GOSSIP_SMILEY_BOSS: /* @) */
310
icon_id = "stock_smiley-21";
312
case GOSSIP_SMILEY_MONKEY: /* #) */
313
icon_id = "stock_smiley-22";
315
case GOSSIP_SMILEY_SILLY: /* O) */
316
icon_id = "stock_smiley-24";
318
case GOSSIP_SMILEY_SICK: /* +o( */
319
icon_id = "stock_smiley-26";
323
g_assert_not_reached ();
328
return gossip_pixbuf_from_icon_name (icon_id, icon_size);
332
gossip_icon_name_from_account (McAccount *account)
336
profile = mc_account_get_profile (account);
338
return mc_profile_get_icon_name (profile);
342
gossip_icon_name_for_presence_state (McPresence state)
345
case MC_PRESENCE_AVAILABLE:
346
return EMPATHY_IMAGE_AVAILABLE;
347
case MC_PRESENCE_DO_NOT_DISTURB:
348
return EMPATHY_IMAGE_BUSY;
349
case MC_PRESENCE_AWAY:
350
return EMPATHY_IMAGE_AWAY;
351
case MC_PRESENCE_EXTENDED_AWAY:
352
return EMPATHY_IMAGE_EXT_AWAY;
353
case MC_PRESENCE_HIDDEN:
354
case MC_PRESENCE_OFFLINE:
355
case MC_PRESENCE_UNSET:
356
return EMPATHY_IMAGE_OFFLINE;
358
g_assert_not_reached ();
365
gossip_icon_name_for_presence (GossipPresence *presence)
369
g_return_val_if_fail (GOSSIP_IS_PRESENCE (presence),
370
EMPATHY_IMAGE_OFFLINE);
372
state = gossip_presence_get_state (presence);
374
return gossip_icon_name_for_presence_state (state);
378
gossip_icon_name_for_contact (GossipContact *contact)
380
GossipPresence *presence;
381
GossipSubscription subscription;
383
g_return_val_if_fail (GOSSIP_IS_CONTACT (contact),
384
EMPATHY_IMAGE_OFFLINE);
386
presence = gossip_contact_get_presence (contact);
389
return gossip_icon_name_for_presence (presence);
392
subscription = gossip_contact_get_subscription (contact);
394
if (subscription != GOSSIP_SUBSCRIPTION_BOTH &&
395
subscription != GOSSIP_SUBSCRIPTION_TO) {
396
return EMPATHY_IMAGE_PENDING;
399
return EMPATHY_IMAGE_OFFLINE;
403
gossip_pixbuf_avatar_from_contact (GossipContact *contact)
406
GdkPixbufLoader *loader;
407
GossipAvatar *avatar;
408
GError *error = NULL;
410
g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
412
avatar = gossip_contact_get_avatar (contact);
417
loader = gdk_pixbuf_loader_new ();
419
if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) {
420
g_warning ("Couldn't write avatar image:%p with "
421
"length:%" G_GSIZE_FORMAT " to pixbuf loader: %s",
422
avatar->data, avatar->len, error->message);
423
g_error_free (error);
427
gdk_pixbuf_loader_close (loader, NULL);
429
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
431
g_object_ref (pixbuf);
432
g_object_unref (loader);
438
pixbuf_from_avatar_size_prepared_cb (GdkPixbufLoader *loader,
441
struct SizeData *data)
443
g_return_if_fail (width > 0 && height > 0);
445
if (data->preserve_aspect_ratio && (data->width > 0 || data->height > 0)) {
446
if (width < data->width && height < data->height) {
451
if (data->width < 0) {
452
width = width * (double) data->height / (gdouble) height;
453
height = data->height;
454
} else if (data->height < 0) {
455
height = height * (double) data->width / (double) width;
457
} else if ((double) height * (double) data->width >
458
(double) width * (double) data->height) {
459
width = 0.5 + (double) width * (double) data->height / (double) height;
460
height = data->height;
462
height = 0.5 + (double) height * (double) data->width / (double) width;
466
if (data->width > 0) {
470
if (data->height > 0) {
471
height = data->height;
475
gdk_pixbuf_loader_set_size (loader, width, height);
479
gossip_pixbuf_from_avatar_scaled (GossipAvatar *avatar,
484
GdkPixbufLoader *loader;
485
struct SizeData data;
486
GError *error = NULL;
493
data.height = height;
494
data.preserve_aspect_ratio = TRUE;
496
loader = gdk_pixbuf_loader_new ();
498
g_signal_connect (loader, "size-prepared",
499
G_CALLBACK (pixbuf_from_avatar_size_prepared_cb),
502
if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) {
503
g_warning ("Couldn't write avatar image:%p with "
504
"length:%" G_GSIZE_FORMAT " to pixbuf loader: %s",
505
avatar->data, avatar->len, error->message);
506
g_error_free (error);
510
gdk_pixbuf_loader_close (loader, NULL);
512
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
514
g_object_ref (pixbuf);
515
g_object_unref (loader);
521
gossip_pixbuf_avatar_from_contact_scaled (GossipContact *contact,
525
GossipAvatar *avatar;
527
g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
529
avatar = gossip_contact_get_avatar (contact);
531
return gossip_pixbuf_from_avatar_scaled (avatar, width, height);
533
/* Stolen from GtkSourceView, hence the weird intendation. Please keep it like
534
* that to make it easier to apply changes from the original code.
536
#define GTK_TEXT_UNKNOWN_CHAR 0xFFFC
538
/* this function acts like g_utf8_offset_to_pointer() except that if it finds a
539
* decomposable character it consumes the decomposition length from the given
540
* offset. So it's useful when the offset was calculated for the normalized
541
* version of str, but we need a pointer to str itself. */
543
pointer_from_offset_skipping_decomp (const gchar *str, gint offset)
545
gchar *casefold, *normal;
551
q = g_utf8_next_char (p);
552
casefold = g_utf8_casefold (p, q - p);
553
normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
554
offset -= g_utf8_strlen (normal, -1);
563
g_utf8_strcasestr (const gchar *haystack, const gchar *needle)
567
const gchar *ret = NULL;
570
gchar *caseless_haystack;
573
g_return_val_if_fail (haystack != NULL, NULL);
574
g_return_val_if_fail (needle != NULL, NULL);
576
casefold = g_utf8_casefold (haystack, -1);
577
caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
580
needle_len = g_utf8_strlen (needle, -1);
581
haystack_len = g_utf8_strlen (caseless_haystack, -1);
585
ret = (gchar *)haystack;
589
if (haystack_len < needle_len)
595
p = (gchar*)caseless_haystack;
596
needle_len = strlen (needle);
601
if ((strncmp (p, needle, needle_len) == 0))
603
ret = pointer_from_offset_skipping_decomp (haystack, i);
607
p = g_utf8_next_char (p);
612
g_free (caseless_haystack);
618
g_utf8_caselessnmatch (const char *s1, const char *s2,
619
gssize n1, gssize n2)
622
gchar *normalized_s1;
623
gchar *normalized_s2;
626
gboolean ret = FALSE;
628
g_return_val_if_fail (s1 != NULL, FALSE);
629
g_return_val_if_fail (s2 != NULL, FALSE);
630
g_return_val_if_fail (n1 > 0, FALSE);
631
g_return_val_if_fail (n2 > 0, FALSE);
633
casefold = g_utf8_casefold (s1, n1);
634
normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
637
casefold = g_utf8_casefold (s2, n2);
638
normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
641
len_s1 = strlen (normalized_s1);
642
len_s2 = strlen (normalized_s2);
647
ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
650
g_free (normalized_s1);
651
g_free (normalized_s2);
657
forward_chars_with_skipping (GtkTextIter *iter,
659
gboolean skip_invisible,
660
gboolean skip_nontext,
661
gboolean skip_decomp)
665
g_return_if_fail (count >= 0);
671
gboolean ignored = FALSE;
673
/* minimal workaround to avoid the infinite loop of bug #168247.
674
* It doesn't fix the problemjust the symptom...
676
if (gtk_text_iter_is_end (iter))
679
if (skip_nontext && gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
682
if (!ignored && skip_invisible &&
683
/* _gtk_text_btree_char_is_invisible (iter)*/ FALSE)
686
if (!ignored && skip_decomp)
688
/* being UTF8 correct sucks; this accounts for extra
689
offsets coming from canonical decompositions of
690
UTF8 characters (e.g. accented characters) which
691
g_utf8_normalize() performs */
696
buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
697
normal = g_utf8_normalize (buffer, buffer_len, G_NORMALIZE_NFD);
698
i -= (g_utf8_strlen (normal, -1) - 1);
702
gtk_text_iter_forward_char (iter);
710
lines_match (const GtkTextIter *start,
712
gboolean visible_only,
714
GtkTextIter *match_start,
715
GtkTextIter *match_end)
722
if (*lines == NULL || **lines == '\0')
725
*match_start = *start;
732
gtk_text_iter_forward_line (&next);
734
/* No more text in buffer, but *lines is nonempty */
735
if (gtk_text_iter_equal (start, &next))
741
line_text = gtk_text_iter_get_visible_slice (start, &next);
743
line_text = gtk_text_iter_get_slice (start, &next);
748
line_text = gtk_text_iter_get_visible_text (start, &next);
750
line_text = gtk_text_iter_get_text (start, &next);
753
if (match_start) /* if this is the first line we're matching */
755
found = g_utf8_strcasestr (line_text, *lines);
759
/* If it's not the first line, we have to match from the
762
if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text),
775
/* Get offset to start of search string */
776
offset = g_utf8_strlen (line_text, found - line_text);
780
/* If match start needs to be returned, set it to the
781
* start of the search string.
783
forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE);
789
/* Go to end of search string */
790
forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE);
799
/* pass NULL for match_start, since we don't need to find the
802
return lines_match (&next, lines, visible_only, slice, NULL, match_end);
805
/* strsplit () that retains the delimiter as part of the string. */
807
strbreakup (const char *string,
808
const char *delimiter,
811
GSList *string_list = NULL, *slist;
812
gchar **str_array, *s, *casefold, *new_string;
815
g_return_val_if_fail (string != NULL, NULL);
816
g_return_val_if_fail (delimiter != NULL, NULL);
819
max_tokens = G_MAXINT;
821
s = strstr (string, delimiter);
824
guint delimiter_len = strlen (delimiter);
830
len = s - string + delimiter_len;
831
new_string = g_new (gchar, len + 1);
832
strncpy (new_string, string, len);
834
casefold = g_utf8_casefold (new_string, -1);
836
new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
838
string_list = g_slist_prepend (string_list, new_string);
840
string = s + delimiter_len;
841
s = strstr (string, delimiter);
842
} while (--max_tokens && s);
848
casefold = g_utf8_casefold (string, -1);
849
new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
851
string_list = g_slist_prepend (string_list, new_string);
854
str_array = g_new (gchar*, n);
858
str_array[i--] = NULL;
859
for (slist = string_list; slist; slist = slist->next)
860
str_array[i--] = slist->data;
862
g_slist_free (string_list);
868
gossip_text_iter_forward_search (const GtkTextIter *iter,
870
GtkTextIter *match_start,
871
GtkTextIter *match_end,
872
const GtkTextIter *limit)
874
gchar **lines = NULL;
876
gboolean retval = FALSE;
878
gboolean visible_only;
881
g_return_val_if_fail (iter != NULL, FALSE);
882
g_return_val_if_fail (str != NULL, FALSE);
884
if (limit && gtk_text_iter_compare (iter, limit) >= 0)
888
/* If we can move one char, return the empty string there */
891
if (gtk_text_iter_forward_char (&match)) {
892
if (limit && gtk_text_iter_equal (&match, limit)) {
897
*match_start = match;
911
/* locate all lines */
912
lines = strbreakup (str, "\n", -1);
917
/* This loop has an inefficient worst-case, where
918
* gtk_text_iter_get_text () is called repeatedly on
923
if (limit && gtk_text_iter_compare (&search, limit) >= 0) {
927
if (lines_match (&search, (const gchar**)lines,
928
visible_only, slice, &match, &end)) {
930
(limit && gtk_text_iter_compare (&end, limit) <= 0)) {
934
*match_start = match;
942
} while (gtk_text_iter_forward_line (&search));
944
g_strfreev ((gchar**)lines);
950
g_utf8_strrcasestr (const gchar *haystack, const gchar *needle)
954
const gchar *ret = NULL;
957
gchar *caseless_haystack;
960
g_return_val_if_fail (haystack != NULL, NULL);
961
g_return_val_if_fail (needle != NULL, NULL);
963
casefold = g_utf8_casefold (haystack, -1);
964
caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
967
needle_len = g_utf8_strlen (needle, -1);
968
haystack_len = g_utf8_strlen (caseless_haystack, -1);
972
ret = (gchar *)haystack;
976
if (haystack_len < needle_len)
982
i = haystack_len - needle_len;
983
p = g_utf8_offset_to_pointer (caseless_haystack, i);
984
needle_len = strlen (needle);
986
while (p >= caseless_haystack)
988
if (strncmp (p, needle, needle_len) == 0)
990
ret = pointer_from_offset_skipping_decomp (haystack, i);
994
p = g_utf8_prev_char (p);
999
g_free (caseless_haystack);
1005
backward_lines_match (const GtkTextIter *start,
1006
const gchar **lines,
1007
gboolean visible_only,
1009
GtkTextIter *match_start,
1010
GtkTextIter *match_end)
1012
GtkTextIter line, next;
1017
if (*lines == NULL || **lines == '\0')
1020
*match_start = *start;
1022
*match_end = *start;
1026
line = next = *start;
1027
if (gtk_text_iter_get_line_offset (&next) == 0)
1029
if (!gtk_text_iter_backward_line (&next))
1033
gtk_text_iter_set_line_offset (&next, 0);
1038
line_text = gtk_text_iter_get_visible_slice (&next, &line);
1040
line_text = gtk_text_iter_get_slice (&next, &line);
1045
line_text = gtk_text_iter_get_visible_text (&next, &line);
1047
line_text = gtk_text_iter_get_text (&next, &line);
1050
if (match_start) /* if this is the first line we're matching */
1052
found = g_utf8_strrcasestr (line_text, *lines);
1056
/* If it's not the first line, we have to match from the
1057
* start of the line.
1059
if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text),
1072
/* Get offset to start of search string */
1073
offset = g_utf8_strlen (line_text, found - line_text);
1075
forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE);
1077
/* If match start needs to be returned, set it to the
1078
* start of the search string.
1082
*match_start = next;
1085
/* Go to end of search string */
1086
forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE);
1095
/* try to match the rest of the lines forward, passing NULL
1096
* for match_start so lines_match will try to match the entire
1098
return lines_match (&next, lines, visible_only,
1099
slice, NULL, match_end);
1103
gossip_text_iter_backward_search (const GtkTextIter *iter,
1105
GtkTextIter *match_start,
1106
GtkTextIter *match_end,
1107
const GtkTextIter *limit)
1109
gchar **lines = NULL;
1111
gboolean retval = FALSE;
1113
gboolean visible_only;
1116
g_return_val_if_fail (iter != NULL, FALSE);
1117
g_return_val_if_fail (str != NULL, FALSE);
1119
if (limit && gtk_text_iter_compare (iter, limit) <= 0)
1124
/* If we can move one char, return the empty string there */
1127
if (gtk_text_iter_backward_char (&match))
1129
if (limit && gtk_text_iter_equal (&match, limit))
1133
*match_start = match;
1144
visible_only = TRUE;
1147
/* locate all lines */
1148
lines = strbreakup (str, "\n", -1);
1154
/* This loop has an inefficient worst-case, where
1155
* gtk_text_iter_get_text () is called repeatedly on
1160
if (limit && gtk_text_iter_compare (&search, limit) <= 0)
1163
if (backward_lines_match (&search, (const gchar**)lines,
1164
visible_only, slice, &match, &end))
1166
if (limit == NULL || (limit &&
1167
gtk_text_iter_compare (&end, limit) > 0))
1172
*match_start = match;
1179
if (gtk_text_iter_get_line_offset (&search) == 0)
1181
if (!gtk_text_iter_backward_line (&search))
1186
gtk_text_iter_set_line_offset (&search, 0);
1190
g_strfreev ((gchar**)lines);
1196
window_get_is_on_current_workspace (GtkWindow *window)
1198
GdkWindow *gdk_window;
1200
gdk_window = GTK_WIDGET (window)->window;
1202
return !(gdk_window_get_state (gdk_window) &
1203
GDK_WINDOW_STATE_ICONIFIED);
1209
/* Checks if the window is visible as in visible on the current workspace. */
1211
gossip_window_get_is_visible (GtkWindow *window)
1215
g_return_val_if_fail (window != NULL, FALSE);
1217
g_object_get (window,
1218
"visible", &visible,
1221
return visible && window_get_is_on_current_workspace (window);
1224
/* Takes care of moving the window to the current workspace. */
1226
gossip_window_present (GtkWindow *window,
1227
gboolean steal_focus)
1230
gboolean on_current;
1233
g_return_if_fail (window != NULL);
1235
/* There are three cases: hidden, visible, visible on another
1239
g_object_get (window,
1240
"visible", &visible,
1243
on_current = window_get_is_on_current_workspace (window);
1245
if (visible && !on_current) {
1246
/* Hide it so present brings it to the current workspace. */
1247
gtk_widget_hide (GTK_WIDGET (window));
1250
timestamp = gtk_get_current_event_time ();
1251
if (steal_focus && timestamp != GDK_CURRENT_TIME) {
1252
gtk_window_present_with_time (window, timestamp);
1254
gtk_window_present (window);
1258
/* The URL opening code can't handle schemeless strings, so we try to be
1259
* smart and add http if there is no scheme or doesn't look like a mail
1260
* address. This should work in most cases, and let us click on strings
1261
* like "www.gnome.org".
1264
fixup_url (const gchar *url)
1268
if (!g_str_has_prefix (url, "http://") &&
1269
!strstr (url, ":/") &&
1270
!strstr (url, "@")) {
1271
real_url = g_strdup_printf ("http://%s", url);
1273
real_url = g_strdup (url);
1280
gossip_url_show (const char *url)
1283
GError *error = NULL;
1285
real_url = fixup_url (url);
1286
gnome_url_show (real_url, &error);
1288
g_warning ("Couldn't show URL:'%s'", real_url);
1289
g_error_free (error);
1296
link_button_hook (GtkLinkButton *button,
1300
gossip_url_show (link);
1304
gossip_link_button_new (const gchar *url,
1307
static gboolean hook = FALSE;
1311
gtk_link_button_set_uri_hook (link_button_hook, NULL, NULL);
1314
return gtk_link_button_new_with_label (url, title);
1317
/* FIXME: Do this in a proper way at some point, probably in GTK+? */
1319
gossip_window_set_default_icon_name (const gchar *name)
1321
gtk_window_set_default_icon_name (name);
1325
gossip_toggle_button_set_state_quietly (GtkWidget *widget,
1330
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
1332
g_signal_handlers_block_by_func (widget, callback, user_data);
1333
g_object_set (widget, "active", active, NULL);
1334
g_signal_handlers_unblock_by_func (widget, callback, user_data);