gnome-shell-3.6.3.1/src/shell-util.c

No issues found

  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 
  3 #include "config.h"
  4 
  5 #include <sys/types.h>
  6 #include <sys/wait.h>
  7 
  8 #include "shell-util.h"
  9 #include <glib/gi18n-lib.h>
 10 #include <gtk/gtk.h>
 11 #include <gdk-pixbuf/gdk-pixbuf.h>
 12 
 13 #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
 14 #include <langinfo.h>
 15 #endif
 16 
 17 #ifdef WITH_SYSTEMD
 18 #include <systemd/sd-daemon.h>
 19 #include <systemd/sd-login.h>
 20 #endif
 21 
 22 static void
 23 stop_pick (ClutterActor       *actor,
 24            const ClutterColor *color)
 25 {
 26   g_signal_stop_emission_by_name (actor, "pick");
 27 }
 28 
 29 /**
 30  * shell_util_set_hidden_from_pick:
 31  * @actor: A #ClutterActor
 32  * @hidden: Whether @actor should be hidden from pick
 33  *
 34  * If @hidden is %TRUE, hide @actor from pick even with a mode of
 35  * %CLUTTER_PICK_ALL; if @hidden is %FALSE, unhide @actor.
 36  */
 37 void
 38 shell_util_set_hidden_from_pick (ClutterActor *actor,
 39                                  gboolean      hidden)
 40 {
 41   gpointer existing_handler_data;
 42 
 43   existing_handler_data = g_object_get_data (G_OBJECT (actor),
 44                                              "shell-stop-pick");
 45   if (hidden)
 46     {
 47       if (existing_handler_data != NULL)
 48         return;
 49       g_signal_connect (actor, "pick", G_CALLBACK (stop_pick), NULL);
 50       g_object_set_data (G_OBJECT (actor),
 51                          "shell-stop-pick", GUINT_TO_POINTER (1));
 52     }
 53   else
 54     {
 55       if (existing_handler_data == NULL)
 56         return;
 57       g_signal_handlers_disconnect_by_func (actor, stop_pick, NULL);
 58       g_object_set_data (G_OBJECT (actor), "shell-stop-pick", NULL);
 59     }
 60 }
 61 
 62 /**
 63  * shell_util_get_transformed_allocation:
 64  * @actor: a #ClutterActor
 65  * @box: (out): location to store returned box in stage coordinates
 66  *
 67  * This function is similar to a combination of clutter_actor_get_transformed_position(),
 68  * and clutter_actor_get_transformed_size(), but unlike
 69  * clutter_actor_get_transformed_size(), it always returns a transform
 70  * of the current allocation, while clutter_actor_get_transformed_size() returns
 71  * bad values (the transform of the requested size) if a relayout has been
 72  * queued.
 73  *
 74  * This function is more convenient to use than
 75  * clutter_actor_get_abs_allocation_vertices() if no transformation is in effect
 76  * and also works around limitations in the GJS binding of arrays.
 77  */
 78 void
 79 shell_util_get_transformed_allocation (ClutterActor    *actor,
 80                                        ClutterActorBox *box)
 81 {
 82   /* Code adapted from clutter-actor.c:
 83    * Copyright 2006, 2007, 2008 OpenedHand Ltd
 84    */
 85   ClutterVertex v[4];
 86   gfloat x_min, x_max, y_min, y_max;
 87   gint i;
 88 
 89   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
 90 
 91   clutter_actor_get_abs_allocation_vertices (actor, v);
 92 
 93   x_min = x_max = v[0].x;
 94   y_min = y_max = v[0].y;
 95 
 96   for (i = 1; i < G_N_ELEMENTS (v); ++i)
 97     {
 98       if (v[i].x < x_min)
 99 	x_min = v[i].x;
100 
101       if (v[i].x > x_max)
102 	x_max = v[i].x;
103 
104       if (v[i].y < y_min)
105 	y_min = v[i].y;
106 
107       if (v[i].y > y_max)
108 	y_max = v[i].y;
109     }
110 
111   box->x1 = x_min;
112   box->y1 = y_min;
113   box->x2 = x_max;
114   box->y2 = y_max;
115 }
116 
117 char *
118 shell_util_normalize_and_casefold (const char *str)
119 {
120   char *normalized, *result;
121 
122   if (str == NULL)
123     return NULL;
124 
125   normalized = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
126   result = g_utf8_casefold (normalized, -1);
127   g_free (normalized);
128   return result;
129 }
130 
131 /**
132  * shell_util_format_date:
133  * @format: a strftime-style string format, as parsed by
134  *   g_date_time_format()
135  * @time_ms: milliseconds since 1970-01-01 00:00:00 UTC; the
136  *   value returned by Date.getTime()
137  *
138  * Formats a date for the current locale. This should be
139  * used instead of the Spidermonkey Date.toLocaleFormat()
140  * extension because Date.toLocaleFormat() is buggy for
141  * Unicode format strings:
142  * https://bugzilla.mozilla.org/show_bug.cgi?id=508783
143  *
144  * Return value: the formatted date. If the date is
145  *  outside of the range of a GDateTime (which contains
146  *  any plausible dates we actually care about), will
147  *  return an empty string.
148  */
149 char *
150 shell_util_format_date (const char *format,
151                         gint64      time_ms)
152 {
153   GDateTime *datetime;
154   GTimeVal tv;
155   char *result;
156 
157   tv.tv_sec = time_ms / 1000;
158   tv.tv_usec = (time_ms % 1000) * 1000;
159 
160   datetime = g_date_time_new_from_timeval_local (&tv);
161   if (!datetime) /* time_ms is out of range of GDateTime */
162     return g_strdup ("");
163 
164   result = g_date_time_format (datetime, format);
165 
166   g_date_time_unref (datetime);
167   return result;
168 }
169 
170 /**
171  * shell_util_get_week_start:
172  *
173  * Gets the first week day for the current locale, expressed as a
174  * number in the range 0..6, representing week days from Sunday to
175  * Saturday.
176  *
177  * Returns: A number representing the first week day for the current
178  *          locale
179  */
180 /* Copied from gtkcalendar.c */
181 int
182 shell_util_get_week_start ()
183 {
184   int week_start;
185 #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
186   union { unsigned int word; char *string; } langinfo;
187   int week_1stday = 0;
188   int first_weekday = 1;
189   guint week_origin;
190 #else
191   char *gtk_week_start;
192 #endif
193 
194 #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
195   langinfo.string = nl_langinfo (_NL_TIME_FIRST_WEEKDAY);
196   first_weekday = langinfo.string[0];
197   langinfo.string = nl_langinfo (_NL_TIME_WEEK_1STDAY);
198   week_origin = langinfo.word;
199   if (week_origin == 19971130) /* Sunday */
200     week_1stday = 0;
201   else if (week_origin == 19971201) /* Monday */
202     week_1stday = 1;
203   else
204     g_warning ("Unknown value of _NL_TIME_WEEK_1STDAY.\n");
205 
206   week_start = (week_1stday + first_weekday - 1) % 7;
207 #else
208   /* Use a define to hide the string from xgettext */
209 # define GTK_WEEK_START "calendar:week_start:0"
210   gtk_week_start = dgettext ("gtk30", GTK_WEEK_START);
211 
212   if (strncmp (gtk_week_start, "calendar:week_start:", 20) == 0)
213     week_start = *(gtk_week_start + 20) - '0';
214   else
215     week_start = -1;
216 
217   if (week_start < 0 || week_start > 6)
218     {
219       g_warning ("Whoever translated calendar:week_start:0 for GTK+ "
220                  "did so wrongly.\n");
221       week_start = 0;
222     }
223 #endif
224 
225   return week_start;
226 }
227 
228 /**
229  * shell_write_string_to_stream:
230  * @stream: a #GOutputStream
231  * @str: a UTF-8 string to write to @stream
232  * @error: location to store GError
233  *
234  * Write a string to a GOutputStream as UTF-8. This is a workaround
235  * for not having binary buffers in GJS.
236  *
237  * Return value: %TRUE if write succeeded
238  */
239 gboolean
240 shell_write_string_to_stream (GOutputStream *stream,
241                               const char    *str,
242                               GError       **error)
243 {
244   return g_output_stream_write_all (stream, str, strlen (str),
245                                     NULL, NULL, error);
246 }
247 
248 /**
249  * shell_get_file_contents_utf8_sync:
250  * @path: UTF-8 encoded filename path
251  * @error: a #GError
252  *
253  * Synchronously load the contents of a file as a NUL terminated
254  * string, validating it as UTF-8.  Embedded NUL characters count as
255  * invalid content.
256  *
257  * Returns: (transfer full): File contents
258  */
259 char *
260 shell_get_file_contents_utf8_sync (const char *path,
261                                    GError    **error)
262 {
263   char *contents;
264   gsize len;
265   if (!g_file_get_contents (path, &contents, &len, error))
266     return NULL;
267   if (!g_utf8_validate (contents, len, NULL))
268     {
269       g_free (contents);
270       g_set_error (error,
271                    G_IO_ERROR,
272                    G_IO_ERROR_FAILED,
273                    "File %s contains invalid UTF-8",
274                    path);
275       return NULL;
276     }
277   return contents;
278 }
279 
280 /**
281  * shell_session_is_active_for_systemd:
282  *
283  * Checks whether the session we are running in is currently active,
284  * i.e. in the foreground and ready for user input.
285  *
286  * Returns: TRUE if session is active
287  */
288 gboolean
289 shell_session_is_active_for_systemd (void)
290 {
291   /* If this isn't systemd, let's assume the session is active. */
292 
293 #ifdef WITH_SYSTEMD
294   if (sd_booted () <= 0)
295     return TRUE;
296 
297   return sd_session_is_active (NULL) != 0;
298 #else
299   return TRUE;
300 #endif
301 }
302 
303 /**
304  * shell_util_wifexited:
305  * @status: the status returned by wait() or waitpid()
306  * @exit: (out): the actual exit status of the process
307  *
308  * Implements libc standard WIFEXITED, that cannot be used JS
309  * code.
310  * Returns: TRUE if the process exited normally, FALSE otherwise
311  */
312 gboolean
313 shell_util_wifexited (int  status,
314                       int *exit)
315 {
316   gboolean ret;
317 
318   ret = WIFEXITED(status);
319 
320   if (ret)
321     *exit = WEXITSTATUS(status);
322 
323   return ret;
324 }
325 
326 /**
327  * shell_util_create_pixbuf_from_data:
328  * @data: (array length=len) (element-type guint8) (transfer full):
329  * @len:
330  * @colorspace:
331  * @has_alpha:
332  * @bits_per_sample:
333  * @width:
334  * @height:
335  * @rowstride:
336  *
337  * Workaround for non-introspectability of gdk_pixbuf_from_data().
338  *
339  * Returns: (transfer full):
340  */
341 GdkPixbuf *
342 shell_util_create_pixbuf_from_data (const guchar      *data,
343                                     gsize              len,
344                                     GdkColorspace      colorspace,
345                                     gboolean           has_alpha,
346                                     int                bits_per_sample,
347                                     int                width,
348                                     int                height,
349                                     int                rowstride)
350 {
351   return gdk_pixbuf_new_from_data (data, colorspace, has_alpha,
352                                    bits_per_sample, width, height, rowstride,
353                                    (GdkPixbufDestroyNotify) g_free, NULL);
354 }