1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
3 * Conky, a system monitor, based on torsmo
5 * Any original torsmo code is licensed under the BSD license
7 * All code written since the fork of torsmo is licensed under the GPL
9 * Please see COPYING for details
11 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12 * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
14 * All rights reserved.
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * vim: ts=4 sw=4 noet ai cindent syntax=c
33 #include "text_object.h"
48 #include <sys/param.h>
49 #ifdef HAVE_SYS_INOTIFY_H
50 #include <sys/inotify.h>
51 #endif /* HAVE_SYS_INOTIFY_H */
54 #include <X11/Xutil.h>
56 #include <X11/extensions/Xdamage.h>
57 #endif /* HAVE_XDAMAGE */
62 #include <sys/types.h>
64 #include <netinet/in.h>
72 #include <libxml/parser.h>
76 #include "obj_create.h"
77 #include "obj_display.h"
78 #include "obj_destroy.h"
92 #include "temphelper.h"
96 /* check for OS and include appropriate headers */
97 #if defined(__linux__)
99 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
101 #elif defined(__OpenBSD__)
105 #if defined(__FreeBSD_kernel__)
109 /* FIXME: apm_getinfo is unused here. maybe it's meant for common.c */
110 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
111 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
112 int apm_getinfo(int fd, apm_info_t aip);
113 char *get_apm_adapter(void);
114 char *get_apm_battery_life(void);
115 char *get_apm_battery_time(void);
119 #include "defconfig.h"
120 #include "conf_cookie.h"
124 #define S_ISSOCK(x) ((x & S_IFMT) == S_IFSOCK)
127 #define MAIL_FILE "$MAIL"
128 #define MAX_IF_BLOCK_DEPTH 5
130 //#define SIGNAL_BLOCKING
131 #undef SIGNAL_BLOCKING
133 /* debugging level, used by logging.h */
134 int global_debug_level = 0;
136 static volatile int g_signal_pending;
141 /* prototypes for internally used functions */
142 static void signal_handler(int);
143 static void print_version(void) __attribute__((noreturn));
144 static void reload_config(void);
146 static void print_version(void)
148 printf(PACKAGE_NAME" "VERSION" compiled "BUILD_DATE" for "BUILD_ARCH"\n");
150 printf("\nCompiled in features:\n\n"
151 "System config file: "SYSTEM_CONFIG_FILE"\n"
152 "Package library path: "PACKAGE_LIBDIR"\n\n"
156 " * Xdamage extension\n"
157 # endif /* HAVE_XDAMAGE */
159 " * XDBE (double buffer extension)\n"
160 # endif /* HAVE_XDBE */
165 "\n Music detection:\n"
168 #endif /* AUDACIOUS */
184 #endif /* HAVE_OPENMP */
191 #ifdef TCP_PORT_MONITOR
193 #endif /* TCP_PORT_MONITOR */
196 #endif /* HAVE_CURL */
201 " * Weather (METAR)\n"
203 " * Weather (XOAP)\n"
208 #endif /* HAVE_IWLIB */
210 " * support for IBM/Lenovo notebooks\n"
220 #endif /* CONFIG_OUTPUT */
225 " * ALSA mixer support\n"
226 #endif /* MIXER_IS_ALSA */
236 #ifdef HAVE_LUA_CAIRO
238 #endif /* HAVE_LUA_CAIRO */
239 #ifdef HAVE_LUA_IMLIB2
242 #endif /* HAVE_LUA */
248 #ifdef HAVE_SYS_INOTIFY_H
252 static void main_loop(conky_context *ctx)
255 #ifdef SIGNAL_BLOCKING
256 sigset_t newmask, oldmask;
259 #ifdef HAVE_SYS_INOTIFY_H
260 int inotify_config_wd = -1;
261 #define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
262 #define INOTIFY_BUF_LEN (20 * (INOTIFY_EVENT_SIZE + 16))
263 char inotify_buff[INOTIFY_BUF_LEN];
264 #endif /* HAVE_SYS_INOTIFY_H */
267 #ifdef SIGNAL_BLOCKING
268 sigemptyset(&newmask);
269 sigaddset(&newmask, SIGINT);
270 sigaddset(&newmask, SIGTERM);
271 sigaddset(&newmask, SIGUSR1);
274 ctx->next_update_time = get_time();
275 while (terminate == 0 && (ctx->total_run_times == 0 || ctx->info.looped < ctx->total_run_times)) {
276 if (ctx->update_interval_bat != NOBATTERY && ctx->update_interval_bat != ctx->update_interval_old) {
277 char buf[ctx->max_user_text];
279 get_battery_short_status(buf, ctx->max_user_text, "BAT0");
281 ctx->update_interval = ctx->update_interval_bat;
283 ctx->update_interval = ctx->update_interval_old;
288 #ifdef SIGNAL_BLOCKING
289 /* block signals. we will inspect for pending signals later */
290 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
291 CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
296 if (ctx->output_methods & TO_X) {
299 /* wait for X event or timeout */
301 if (!XPending(display)) {
305 t = ctx->next_update_time - get_time();
309 } else if (t > ctx->update_interval) {
310 t = ctx->update_interval;
313 tv.tv_sec = (long) t;
314 tv.tv_usec = (long) (t * 1000000) % 1000000;
316 FD_SET(ConnectionNumber(display), &fdsr);
318 s = select(ConnectionNumber(display) + 1, &fdsr, 0, 0, &tv);
320 if (errno != EINTR) {
321 NORM_ERR("can't select(): %s", strerror(errno));
331 if (ctx->need_to_update) {
333 int wx = ctx->window.x, wy = ctx->window.y;
336 ctx->need_to_update = 0;
337 ctx->selected_font = 0;
338 update_text_area(ctx);
340 if (ctx->own_window) {
343 /* resize ctx->window if it isn't right size */
345 && (ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2 != ctx->window.width
346 || ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2 != ctx->window.height)) {
347 ctx->window.width = ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
348 ctx->window.height = ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
349 draw_stuff(ctx); /* redraw everything in our newly sized ctx->window */
350 XResizeWindow(display, ctx->window.window, ctx->window.width,
351 ctx->window.height); /* resize ctx->window */
352 set_transparent_background(ctx->window.window);
360 /* update lua ctx->window globals */
361 llua_update_window_table(ctx->text_start_x, ctx->text_start_y, ctx->text_width, ctx->text_height);
362 #endif /* HAVE_LUA */
365 /* move ctx->window if it isn't in right position */
366 if (!ctx->fixed_pos && (ctx->window.x != wx || ctx->window.y != wy)) {
367 XMoveWindow(display, ctx->window.window, ctx->window.x, ctx->window.y);
372 if (changed && ctx->window.type == TYPE_PANEL) {
375 fprintf(stderr, PACKAGE_NAME": defining struts\n");
378 switch (ctx->text_alignment) {
416 r.x = ctx->text_start_x - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
417 r.y = ctx->text_start_y - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
418 r.width = ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
419 r.height = ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
420 XUnionRectWithRegion(&r, ctx->window.region, ctx->window.region);
425 /* handle X events */
426 while (XPending(display)) {
429 XNextEvent(display, &ev);
436 r.width = ev.xexpose.width;
437 r.height = ev.xexpose.height;
438 XUnionRectWithRegion(&r, ctx->window.region, ctx->window.region);
444 if ( ev.xproperty.state == PropertyNewValue ) {
445 get_x11_desktop_info( ev.xproperty.display, ev.xproperty.atom );
452 /* set background to ParentRelative for all parents */
453 if (ctx->own_window) {
454 set_transparent_background(ctx->window.window);
458 case ConfigureNotify:
459 if (ctx->own_window) {
460 /* if ctx->window size isn't what expected, set fixed size */
461 if (ev.xconfigure.width != ctx->window.width
462 || ev.xconfigure.height != ctx->window.height) {
463 if (ctx->window.width != 0 && ctx->window.height != 0) {
467 /* clear old stuff before screwing up
472 XWindowAttributes attrs;
473 if (XGetWindowAttributes(display,
474 ctx->window.window, &attrs)) {
475 ctx->window.width = attrs.width;
476 ctx->window.height = attrs.height;
480 ctx->text_width = ctx->window.width - ctx->window.border_inner_margin * 2 - ctx->window.border_outer_margin * 2 - ctx->window.border_width * 2;
481 ctx->text_height = ctx->window.height - ctx->window.border_inner_margin * 2 - ctx->window.border_outer_margin * 2 - ctx->window.border_width * 2;
482 if (ctx->text_width > ctx->maximum_width
483 && ctx->maximum_width > 0) {
484 ctx->text_width = ctx->maximum_width;
488 /* if position isn't what expected, set fixed pos
489 * total_updates avoids setting ctx->fixed_pos when ctx->window
490 * is set to weird locations when started */
492 if (total_updates >= 2 && !ctx->fixed_pos
493 && (ctx->window.x != ev.xconfigure.x
494 || ctx->window.y != ev.xconfigure.y)
495 && (ev.xconfigure.x != 0
496 || ev.xconfigure.y != 0)) {
503 if (ctx->own_window) {
504 /* if an ordinary ctx->window with decorations */
505 if ((ctx->window.type == TYPE_NORMAL &&
506 (!TEST_HINT(ctx->window.hints,
507 HINT_UNDECORATED))) ||
508 ctx->window.type == TYPE_DESKTOP) {
509 /* allow conky to hold input focus. */
512 /* forward the click to the desktop ctx->window */
513 XUngrabPointer(display, ev.xbutton.time);
514 ev.xbutton.window = ctx->window.desktop;
515 ev.xbutton.x = ev.xbutton.x_root;
516 ev.xbutton.y = ev.xbutton.y_root;
517 XSendEvent(display, ev.xbutton.window, False,
518 ButtonPressMask, &ev);
519 XSetInputFocus(display, ev.xbutton.window,
520 RevertToParent, ev.xbutton.time);
526 if (ctx->own_window) {
527 /* if an ordinary ctx->window with decorations */
528 if ((ctx->window.type == TYPE_NORMAL)
529 && (!TEST_HINT(ctx->window.hints,
530 HINT_UNDECORATED))) {
531 /* allow conky to hold input focus. */
534 /* forward the release to the desktop ctx->window */
535 ev.xbutton.window = ctx->window.desktop;
536 ev.xbutton.x = ev.xbutton.x_root;
537 ev.xbutton.y = ev.xbutton.y_root;
538 XSendEvent(display, ev.xbutton.window, False,
539 ButtonReleaseMask, &ev);
548 if (ev.type == ctx->window.event_base + XDamageNotify) {
549 XDamageNotifyEvent *dev = (XDamageNotifyEvent *) &ev;
551 XFixesSetRegion(display, ctx->window.part, &dev->area, 1);
552 XFixesUnionRegion(display, ctx->window.region2, ctx->window.region2, ctx->window.part);
554 #endif /* HAVE_XDAMAGE */
560 XDamageSubtract(display, ctx->window.damage, ctx->window.region2, None);
561 XFixesSetRegion(display, ctx->window.region2, 0, 0);
562 #endif /* HAVE_XDAMAGE */
564 /* XDBE doesn't seem to provide a way to clear the back buffer
565 * without interfering with the front buffer, other than passing
566 * XdbeBackground to XdbeSwapBuffers. That means that if we're
567 * using XDBE, we need to redraw the text even if it wasn't part of
568 * the exposed area. OTOH, if we're not going to call draw_stuff at
569 * all, then no swap happens and we can safely do nothing. */
571 if (!XEmptyRegion(ctx->window.region)) {
576 r.x = ctx->text_start_x - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
577 r.y = ctx->text_start_y - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
578 r.width = ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
579 r.height = ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
580 XUnionRectWithRegion(&r, ctx->window.region, ctx->window.region);
583 XSetRegion(display, ctx->window.gc, ctx->window.region);
586 XftDrawSetClip(ctx->window.xftdraw, ctx->window.region);
590 XDestroyRegion(ctx->window.region);
591 ctx->window.region = XCreateRegion();
595 t = (ctx->next_update_time - get_time()) * 1000000;
596 if(t > 0) usleep((useconds_t)t);
600 if(ctx->output_methods & TO_NCURSES) {
609 #ifdef SIGNAL_BLOCKING
610 /* unblock signals of interest and let handler fly */
611 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
612 CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
616 switch (g_signal_pending) {
619 NORM_ERR("received SIGHUP or SIGUSR1. reloading the config file.");
624 NORM_ERR("received SIGINT or SIGTERM to terminate. bye!");
627 if (ctx->output_methods & TO_X) {
628 XDestroyRegion(ctx->window.region);
629 ctx->window.region = NULL;
631 XDamageDestroy(display, ctx->window.damage);
632 XFixesDestroyRegion(display, ctx->window.region2);
633 XFixesDestroyRegion(display, ctx->window.part);
634 #endif /* HAVE_XDAMAGE */
640 if(ctx->overwrite_file) {
641 free(ctx->overwrite_file);
642 ctx->overwrite_file = 0;
644 if(ctx->append_file) {
645 free(ctx->append_file);
646 ctx->append_file = 0;
650 /* Reaching here means someone set a signal
651 * (SIGXXXX, signal_handler), but didn't write any code
653 * If you don't want to handle a signal, don't set a handler on
654 * it in the first place. */
655 if (g_signal_pending) {
656 NORM_ERR("ignoring signal (%d)", g_signal_pending);
660 #ifdef HAVE_SYS_INOTIFY_H
661 if (inotify_fd != -1 && inotify_config_wd == -1 && ctx->current_config != 0) {
662 inotify_config_wd = inotify_add_watch(inotify_fd,
666 if (inotify_fd != -1 && inotify_config_wd != -1 && ctx->current_config != 0) {
667 int len = 0, idx = 0;
669 struct timeval time_to_wait;
671 FD_ZERO(&descriptors);
672 FD_SET(inotify_fd, &descriptors);
674 time_to_wait.tv_sec = time_to_wait.tv_usec = 0;
676 select(inotify_fd + 1, &descriptors, NULL, NULL, &time_to_wait);
677 if (FD_ISSET(inotify_fd, &descriptors)) {
678 /* process inotify events */
679 len = read(inotify_fd, inotify_buff, INOTIFY_BUF_LEN);
680 while (len > 0 && idx < len) {
681 struct inotify_event *ev = (struct inotify_event *) &inotify_buff[idx];
682 if (ev->wd == inotify_config_wd && (ev->mask & IN_MODIFY || ev->mask & IN_IGNORED)) {
683 /* ctx->current_config should be reloaded */
684 NORM_ERR("'%s' modified, reloading...", ctx->current_config);
686 if (ev->mask & IN_IGNORED) {
687 /* for some reason we get IN_IGNORED here
688 * sometimes, so we need to re-add the watch */
689 inotify_config_wd = inotify_add_watch(inotify_fd,
696 llua_inotify_query(ev->wd, ev->mask);
698 #endif /* HAVE_LUA */
699 idx += INOTIFY_EVENT_SIZE + ev->len;
703 #endif /* HAVE_SYS_INOTIFY_H */
706 llua_update_info(ctx, ctx->update_interval);
707 #endif /* HAVE_LUA */
708 g_signal_pending = 0;
710 clean_up(NULL, NULL);
712 #ifdef HAVE_SYS_INOTIFY_H
713 if (inotify_fd != -1) {
714 inotify_rm_watch(inotify_fd, inotify_config_wd);
716 inotify_fd = inotify_config_wd = 0;
718 #endif /* HAVE_SYS_INOTIFY_H */
721 static void print_help(const char *prog_name) {
722 printf("Usage: %s [OPTION]...\n"
723 PACKAGE_NAME" is a system monitor that renders text on desktop or to own transparent\n"
724 "ctx->window. Command line options will override configurations defined in config\n"
726 " -v, --version version\n"
727 " -q, --quiet quiet mode\n"
728 " -D, --debug increase debugging output, ie. -DD for more debugging\n"
729 " -c, --config=FILE config file to load\n"
731 " -C, --print-config print the builtin default config to stdout\n"
732 " e.g. 'conky -C > ~/.conkyrc' will create a new default config\n"
734 " -d, --daemonize daemonize, fork to background\n"
737 " -a, --alignment=ALIGNMENT text alignment on screen, {top,bottom,middle}_{left,right,middle}\n"
738 " -f, --font=FONT font to use\n"
739 " -X, --display=DISPLAY X11 display to use\n"
741 " -o, --own-ctx->window create own ctx->window to draw\n"
744 " -b, --double-buffer double buffer (prevents flickering)\n"
746 " -w, --ctx->window-id=WIN_ID ctx->window id to draw\n"
750 " -t, --text=TEXT text to render, remember single quotes, like -t '$uptime'\n"
751 " -u, --interval=SECS update interval\n"
752 " -i COUNT number of times to update "PACKAGE_NAME" (and quit)\n",
757 /* : means that character before that takes an argument */
758 static const char *getopt_string = "vVqdDt:u:i:hc:"
773 static const struct option longopts[] = {
774 { "help", 0, NULL, 'h' },
775 { "version", 0, NULL, 'V' },
776 { "debug", 0, NULL, 'D' },
777 { "config", 1, NULL, 'c' },
779 { "print-config", 0, NULL, 'C' },
781 { "daemonize", 0, NULL, 'd' },
783 { "alignment", 1, NULL, 'a' },
784 { "font", 1, NULL, 'f' },
785 { "display", 1, NULL, 'X' },
787 { "own-ctx->window", 0, NULL, 'o' },
790 { "double-buffer", 0, NULL, 'b' },
792 { "ctx->window-id", 1, NULL, 'w' },
794 { "text", 1, NULL, 't' },
795 { "interval", 0, NULL, 'u' },
799 void initialisation(conky_context *ctx, int argc, char **argv)
801 struct sigaction act, oact;
803 set_default_configurations(ctx);
804 load_config_file(ctx, ctx->current_config);
805 currentconffile = conftree_add(currentconffile, ctx->current_config);
807 /* init specials array */
808 if ((specials = calloc(sizeof(struct special_t), max_specials)) == 0) {
809 NORM_ERR("failed to create specials array");
813 if (current_mail_spool == NULL) {
816 variable_substitute(MAIL_FILE, buf, 256);
818 if (buf[0] != '\0') {
819 current_mail_spool = strndup(buf, text_buffer_size);
824 /* handle other command line arguments */
826 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) \
827 || defined(__NetBSD__)
828 optind = optreset = 1;
833 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
834 if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY,
835 "kvm_open")) == NULL) {
836 CRIT_ERR(NULL, NULL, "cannot read kvm");
841 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
849 ctx->fork_to_background = 1;
852 global_debug_level++;
856 set_first_font(optarg);
859 ctx->text_alignment = string_to_alignment(optarg);
874 if (ctx->global_text) {
875 free(ctx->global_text);
876 ctx->global_text = 0;
878 ctx->global_text = strndup(optarg, ctx->max_user_text);
879 convert_escapes(ctx->global_text);
883 ctx->update_interval = strtod(optarg, 0);
884 ctx->update_interval_old = ctx->update_interval;
885 if (ctx->info.music_player_interval == 0) {
886 // default to ctx->update_interval
887 ctx->info.music_player_interval = ctx->update_interval;
892 ctx->total_run_times = strtod(optarg, 0);
896 ctx->gap_x = atoi(optarg);
900 ctx->gap_y = atoi(optarg);
911 if (ctx->output_methods & TO_X) {
912 load_config_file_x11(ctx, ctx->current_config);
916 /* generate text and get initial size */
917 extract_variable_text(ctx, ctx->global_text);
918 if (ctx->global_text) {
919 free(ctx->global_text);
920 ctx->global_text = 0;
922 ctx->global_text = NULL;
924 if (ctx->fork_to_background) {
929 NORM_ERR(PACKAGE_NAME": couldn't fork() to background: %s",
936 fprintf(stderr, "\n");
942 fprintf(stderr, PACKAGE_NAME": forked to background, pid is %d\n",
949 ctx->text_buffer = malloc(ctx->max_user_text);
950 memset(ctx->text_buffer, 0, ctx->max_user_text);
951 ctx->tmpstring1 = malloc(text_buffer_size);
952 memset(ctx->tmpstring1, 0, text_buffer_size);
953 ctx->tmpstring2 = malloc(text_buffer_size);
954 memset(ctx->tmpstring2, 0, text_buffer_size);
959 X11_create_window(ctx);
962 llua_setup_info(ctx, ctx->update_interval);
963 #endif /* HAVE_LUA */
968 /* Set signal handlers */
969 act.sa_handler = signal_handler;
970 sigemptyset(&act.sa_mask);
973 act.sa_flags |= SA_RESTART;
976 if ( sigaction(SIGINT, &act, &oact) < 0
977 || sigaction(SIGALRM, &act, &oact) < 0
978 || sigaction(SIGUSR1, &act, &oact) < 0
979 || sigaction(SIGHUP, &act, &oact) < 0
980 || sigaction(SIGTERM, &act, &oact) < 0) {
981 NORM_ERR("error setting signal handler: %s", strerror(errno));
986 #endif /* HAVE_LUA */
989 int main(int argc, char **argv)
991 /* Conky's main context struct */
993 conky_context *ctx = &mctx;
1002 g_signal_pending = 0;
1003 memset(ctx, 0, sizeof(conky_context));
1004 ctx->max_user_text = MAX_USER_TEXT_DEFAULT;
1007 #ifdef TCP_PORT_MONITOR
1008 /* set default connection limit */
1009 tcp_portmon_set_max_connections(0);
1012 /* handle command line parameters that don't change configs */
1014 if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
1015 || ((s = getenv("LANG")) && *s)) {
1016 temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
1018 NORM_ERR("malloc failed");
1020 for (x = 0; x < strlen(s); x++) {
1021 temp[x] = tolower(s[x]);
1024 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
1030 if (!setlocale(LC_CTYPE, "")) {
1031 NORM_ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
1035 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
1046 if (ctx->current_config) {
1047 free(ctx->current_config);
1049 ctx->current_config = strndup(optarg, ctx->max_user_text);
1052 freopen("/dev/null", "w", stderr);
1055 print_help(argv[0]);
1057 #ifdef CONFIG_OUTPUT
1064 ctx->window.window = strtol(optarg, 0, 0);
1069 ctx->disp = strdup(optarg);
1078 /* check if specified config file is valid */
1079 if (ctx->current_config) {
1081 if (stat(ctx->current_config, &sb) ||
1082 (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
1083 NORM_ERR("invalid configuration file '%s'\n", ctx->current_config);
1084 free(ctx->current_config);
1085 ctx->current_config = 0;
1089 /* load ctx->current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
1091 if (!ctx->current_config) {
1092 /* load default config file */
1093 char buf[DEFAULT_TEXT_BUFFER_SIZE];
1096 /* Try to use personal config file first */
1097 to_real_path(buf, CONFIG_FILE);
1098 if (buf[0] && (fp = fopen(buf, "r"))) {
1099 ctx->current_config = strndup(buf, ctx->max_user_text);
1103 /* Try to use system config file if personal config not readable */
1104 if (!ctx->current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
1105 ctx->current_config = strndup(SYSTEM_CONFIG_FILE, ctx->max_user_text);
1109 /* No readable config found */
1110 if (!ctx->current_config) {
1111 #ifdef CONFIG_OUTPUT
1112 ctx->current_config = strdup("==builtin==");
1113 NORM_ERR("no readable personal or system-wide config file found,"
1114 " using builtin default");
1116 CRIT_ERR(NULL, NULL, "no readable personal or system-wide config file found");
1117 #endif /* ! CONF_OUTPUT */
1122 /* Load xoap keys, if existing */
1126 #ifdef HAVE_SYS_INOTIFY_H
1127 inotify_fd = inotify_init();
1128 #endif /* HAVE_SYS_INOTIFY_H */
1130 initialisation(&mctx, argc, argv);
1134 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1142 static void signal_handler(int sig)
1144 /* signal handler is light as a feather, as it should be. we will poll
1145 * g_signal_pending with each loop of conky and do any signal processing
1146 * there, NOT here */
1147 g_signal_pending = sig;