source: trunk/gtk/util.c @ 1605

Last change on this file since 1605 was 1605, checked in by joshe, 15 years ago

Remove unused function.

  • Property svn:keywords set to Date Rev Author Id
File size: 12.7 KB
Line 
1/******************************************************************************
2 * $Id: util.c 1605 2007-03-29 19:53:40Z joshe $
3 *
4 * Copyright (c) 2005-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <errno.h>
28#include <signal.h>
29#include <stdarg.h>
30#include <string.h>
31#include <unistd.h>
32
33#include <gtk/gtk.h>
34#include <glib/gi18n.h>
35
36#include "tr_prefs.h"
37#include "tr_torrent.h"
38#include "util.h"
39
40#define BESTDECIMAL(d)          (10.0 > (d) ? 2 : (100.0 > (d) ? 1 : 0))
41
42static void
43errcb(GtkWidget *wind, int resp, gpointer data);
44
45gboolean
46strbool(const char *str) {
47  switch(str[0]) {
48    case 'y':
49    case 'Y':
50    case '1':
51    case 'j':
52    case 'e':
53      return TRUE;
54    default:
55      if(0 == g_ascii_strcasecmp("on", str))
56        return TRUE;
57      break;
58  }
59
60  return FALSE;
61}
62
63static const char *sizestrs[] = {
64  N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), N_("PiB"), N_("EiB"),
65};
66
67char *
68readablesize(guint64 size) {
69  int ii;
70  double small = size;
71
72  for(ii = 0; ii + 1 < ALEN(sizestrs) && 1024.0 <= small / 1024.0; ii++)
73    small /= 1024.0;
74
75  if(1024.0 <= small) {
76    small /= 1024.0;
77    ii++;
78  }
79
80  return g_strdup_printf("%.*f %s", BESTDECIMAL(small), small,
81                         gettext(sizestrs[ii]));
82}
83
84#define SECONDS(s)              ((s) % 60)
85#define MINUTES(s)              ((s) / 60 % 60)
86#define HOURS(s)                ((s) / 60 / 60 % 24)
87#define DAYS(s)                 ((s) / 60 / 60 / 24 % 7)
88#define WEEKS(s)                ((s) / 60 / 60 / 24 / 7)
89
90char *
91readabletime(int secs) {
92  if(60 > secs)
93    return g_strdup_printf(_("%i %s"),
94      SECONDS(secs), ngettext("second", "seconds", SECONDS(secs)));
95  else if(60 * 60 > secs)
96    return g_strdup_printf(_("%i %s %i %s"),
97      MINUTES(secs), ngettext("minute", "minutes", MINUTES(secs)),
98      SECONDS(secs), ngettext("second", "seconds", SECONDS(secs)));
99  else if(60 * 60 * 24 > secs)
100    return g_strdup_printf(_("%i %s %i %s"),
101      HOURS(secs),   ngettext("hour", "hours", HOURS(secs)),
102      MINUTES(secs), ngettext("minute", "minutes", MINUTES(secs)));
103  else if(60 * 60 * 24 * 7 > secs)
104    return g_strdup_printf(_("%i %s %i %s"),
105      DAYS(secs),    ngettext("day", "days", DAYS(secs)),
106      HOURS(secs),   ngettext("hour", "hours", HOURS(secs)));
107  else
108    return g_strdup_printf(_("%i %s %i %s"),
109      WEEKS(secs),   ngettext("week", "weeks", WEEKS(secs)),
110      DAYS(secs),    ngettext("hour", "hours", DAYS(secs)));
111}
112
113char *
114ratiostr(guint64 down, guint64 up) {
115  double ratio;
116
117  if(0 == up && 0 == down)
118    return g_strdup(_("N/A"));
119
120  if(0 == down)
121    /* this is a UTF-8 infinity symbol */
122    return g_strdup(_("\xE2\x88\x9E"));
123
124  ratio = (double)up / (double)down;
125
126  return g_strdup_printf("%.*f", BESTDECIMAL(ratio), ratio);
127}
128
129gboolean
130mkdir_p(const char *name, mode_t mode) {
131  struct stat sb;
132  char *parent;
133  gboolean ret;
134  int oerrno;
135
136  if(0 != stat(name, &sb)) {
137    if(ENOENT != errno)
138      return FALSE;
139    parent = g_path_get_dirname(name);
140    ret = mkdir_p(parent, mode);
141    oerrno = errno;
142    g_free(parent);
143    errno = oerrno;
144    return (ret ? (0 == mkdir(name, mode)) : FALSE);
145  }
146
147  if(!S_ISDIR(sb.st_mode)) {
148    errno = ENOTDIR;
149    return FALSE;
150  }
151
152  return TRUE;
153}
154
155GList *
156dupstrlist( GList * list )
157{
158    GList * ii, * ret;
159
160    ret = NULL;
161    for( ii = g_list_first( list ); NULL != ii; ii = ii->next )
162    {
163        ret = g_list_append( ret, g_strdup( ii->data ) );
164    }
165
166    return ret;
167}
168
169char *
170joinstrlist(GList *list, char *sep) {
171  GList *ii;
172  int len;
173  char *ret, *dest;
174
175  if(0 > (len = strlen(sep) * (g_list_length(list) - 1)))
176    return NULL;
177
178  for(ii = g_list_first(list); NULL != ii; ii = ii->next)
179    len += strlen(ii->data);
180
181  dest = ret = g_new(char, len + 1);
182
183  for(ii = g_list_first(list); NULL != ii; ii = ii->next) {
184    dest = g_stpcpy(dest, ii->data);
185    if(NULL != ii->next)
186      dest = g_stpcpy(dest, sep);
187  }
188
189  return ret;
190}
191
192void
193freestrlist(GList *list) {
194  GList *ii;
195
196  if(NULL != list) {
197    for(ii = g_list_first(list); NULL != ii; ii = ii->next)
198      g_free(ii->data);
199    g_list_free(list);
200  }
201}
202
203char *
204urldecode(const char *str, int len) {
205  int ii, jj;
206  char *ret;
207  char buf[3];
208
209  if(0 >= len)
210    len = strlen(str);
211
212  for(ii = jj = 0; ii < len; ii++, jj++)
213    if('%' == str[ii])
214      ii += 2;
215
216  ret = g_new(char, jj + 1);
217
218  buf[2] = '\0';
219  for(ii = jj = 0; ii < len; ii++, jj++) {
220    switch(str[ii]) {
221      case '%':
222        if(ii + 2 < len) {
223          buf[0] = str[ii+1];
224          buf[1] = str[ii+2];
225          ret[jj] = g_ascii_strtoull(buf, NULL, 16);
226        }
227        ii += 2;
228        break;
229      case '+':
230        ret[jj] = ' ';
231      default:
232        ret[jj] = str[ii];
233    }
234  }
235  ret[jj] = '\0';
236
237  return ret;
238}
239
240GList *
241checkfilenames(int argc, char **argv) {
242  char *pwd = g_get_current_dir();
243  int ii, cd;
244  char *dirstr, *filestr;
245  GList *ret = NULL;
246
247  for(ii = 0; ii < argc; ii++) {
248    dirstr = g_path_get_dirname(argv[ii]);
249    if(!g_path_is_absolute(argv[ii])) {
250      filestr = g_build_filename(pwd, dirstr, NULL);
251      g_free(dirstr);
252      dirstr = filestr;
253    }
254    cd = chdir(dirstr);
255    g_free(dirstr);
256    if(0 > cd)
257      continue;
258    dirstr = g_get_current_dir();
259    filestr = g_path_get_basename(argv[ii]);
260    ret = g_list_append(ret, g_build_filename(dirstr, filestr, NULL));
261    g_free(dirstr);
262    g_free(filestr);
263  }
264
265  chdir(pwd);
266  g_free(pwd);
267
268  return ret;
269}
270
271guint
272addactionflag(const char *action) {
273  if(NULL == action)
274    return TR_TORNEW_SAVE_COPY;
275  else if(0 == strcmp("copy", action))
276    return TR_TORNEW_SAVE_COPY;
277  else if(0 == strcmp("move", action))
278    return TR_TORNEW_SAVE_MOVE;
279  else
280    return 0;
281}
282
283const char *
284addactionname( guint flag )
285{
286    static char name[6];
287
288    snprintf( name, sizeof name, "%s",
289              ( TR_TORNEW_SAVE_COPY & flag ? "copy" :
290              ( TR_TORNEW_SAVE_MOVE & flag ? "move" :
291                                             "leave" ) ) );
292
293    return name;
294}
295
296const char *
297getdownloaddir( void )
298{
299    static char * wd = NULL;
300    const char  * dir;
301
302    dir = tr_prefs_get( PREF_ID_DIR );
303    if( NULL == dir )
304    {
305        if( NULL == wd )
306        {
307            wd = g_new( char, MAX_PATH_LENGTH + 1 );
308            if( NULL == getcwd( wd, MAX_PATH_LENGTH + 1 ) )
309            {
310                snprintf( wd, MAX_PATH_LENGTH + 1, "." );
311            }
312        }
313        dir = wd;
314    }
315
316    return dir;
317}
318
319void
320windowsizehack( GtkWidget * wind, GtkWidget * scroll, GtkWidget * view,
321                callbackfunc_t func, void * arg )
322{
323    GtkRequisition req;
324    gint           width, height;
325    GdkScreen    * screen;
326
327    gtk_widget_realize( wind );
328    gtk_widget_size_request( view, &req );
329    height = req.height;
330    gtk_widget_size_request( scroll, &req );
331    height -= req.height;
332    gtk_widget_size_request( wind, &req );
333    height += req.height;
334    screen  = gtk_widget_get_screen( wind );
335    width   = MIN( req.width, gdk_screen_get_width( screen  ) / 2 );
336    height  = MIN( height,    gdk_screen_get_height( screen ) / 5 * 4 );
337    if( height > req.width )
338    {
339        height = MIN( height, width * 8 / 5 );
340    }
341    else
342    {
343        height = MAX( height, width * 5 / 8 );
344    }
345    if( height > req.width )
346    {
347        height = MIN( height, width * 8 / 5 );
348    }
349    else
350    {
351        height = MAX( height, width * 5 / 8 );
352    }
353    if( NULL != func )
354    {
355        func( arg );
356    }
357    gtk_widget_show_now( wind  );
358    gtk_window_resize( GTK_WINDOW( wind ), width, height );
359    gtk_window_set_focus( GTK_WINDOW( wind ), NULL );
360}
361
362struct action *
363action_new( int id, int flags, const char * label, const char * stock )
364{
365    struct action * act;
366
367    act        = g_new0( struct action, 1 );
368    act->id    = id;
369    act->flags = flags;
370    act->label = g_strdup( label );
371    act->stock = g_strdup( stock );
372    act->tool  = NULL;
373    act->menu  = NULL;
374
375    return act;
376}
377
378void
379action_free( struct action * act )
380{
381    g_free( act->label );
382    g_free( act->stock );
383    g_free( act );
384}
385
386GtkWidget *
387action_maketool( struct action * act, const char * key,
388                 GCallback func, gpointer data )
389{
390    GtkToolItem * item;
391
392    item = gtk_tool_button_new_from_stock( act->stock );
393    if( NULL != act->label )
394    {
395        gtk_tool_button_set_label( GTK_TOOL_BUTTON( item ), act->label );
396    }
397    g_object_set_data( G_OBJECT( item ), key, act );
398    g_signal_connect( item, "clicked", func, data );
399    gtk_widget_show( GTK_WIDGET( item ) );
400
401    return GTK_WIDGET( item );
402}
403
404GtkWidget *
405action_makemenu( struct action * act, const char * actkey,
406                 GtkAccelGroup * accel, const char * path, guint keyval,
407                 GCallback func, gpointer data )
408{
409    GtkWidget  * item, * label;
410    GdkModifierType mod;
411    GtkStockItem stock;
412    const char * name;
413    char       * joined;
414
415    mod = GDK_CONTROL_MASK;
416    name = act->label;
417    if( NULL == act->stock )
418    {
419        item = gtk_menu_item_new_with_label( act->label );
420    }
421    else
422    {
423        item = gtk_image_menu_item_new_from_stock( act->stock, NULL );
424        if( NULL == act->label )
425        {
426            if( gtk_stock_lookup( act->stock, &stock ) )
427            {
428                name = stock.label;
429                if( 0 == keyval )
430                {
431                    keyval = stock.keyval;
432                    mod    = stock.modifier;
433                }
434            }
435        }
436        else
437        {
438            label = gtk_bin_get_child( GTK_BIN( item ) );
439            gtk_label_set_text( GTK_LABEL( label ), act->label );
440           
441        }
442    }
443
444    if( NULL != accel && 0 < keyval && NULL != name )
445    {
446        joined = g_strjoin( "/", path, name, NULL );
447        gtk_accel_map_add_entry( joined, keyval, mod );
448        gtk_widget_set_accel_path( item, joined, accel );
449        g_free( joined );
450    }
451    g_object_set_data( G_OBJECT( item ), actkey, act );
452    g_signal_connect( item, "activate", func, data );
453    gtk_widget_show( item );
454
455    return item;
456}
457
458void
459errmsg( GtkWindow * wind, const char * format, ... )
460{
461    GtkWidget * dialog;
462    va_list     ap;
463
464    va_start( ap, format );
465    dialog = verrmsg_full( wind, NULL, NULL, format, ap );
466    va_end( ap );
467
468    if( NULL != wind && !GTK_WIDGET_MAPPED( GTK_WIDGET( wind ) ) )
469    {
470        g_signal_connect_swapped( wind, "map",
471                                  G_CALLBACK( gtk_widget_show ), dialog );
472    }
473    else
474    {
475        gtk_widget_show( dialog );
476    }
477}
478
479GtkWidget *
480errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
481             const char * format, ... )
482{
483    GtkWidget * dialog;
484    va_list     ap;
485
486    va_start( ap, format );
487    dialog = verrmsg_full( wind, func, data, format, ap );
488    va_end( ap );
489
490    return dialog;
491}
492
493GtkWidget *
494verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
495              const char * format, va_list ap )
496{
497  GtkWidget *dialog;
498  char *msg;
499  GList *funcdata;
500
501  msg = g_strdup_vprintf(format, ap);
502
503  if(NULL == wind)
504    dialog = gtk_message_dialog_new(
505      NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
506  else
507    dialog = gtk_message_dialog_new(wind,
508      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
509      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
510
511  if(NULL == func)
512    funcdata = NULL;
513  else
514    funcdata = g_list_append(g_list_append(NULL, func), data);
515  g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
516  g_free(msg);
517
518  return dialog;
519}
520
521static void
522errcb(GtkWidget *widget, int resp SHUTUP, gpointer data) {
523  GList *funcdata;
524  callbackfunc_t func;
525
526  if(NULL != data) {
527    funcdata = g_list_first(data);
528    func = funcdata->data;
529    data = funcdata->next->data;
530    func(data);
531    g_list_free(funcdata);
532  }
533
534  gtk_widget_destroy(widget);
535}
Note: See TracBrowser for help on using the repository browser.