1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2  *
3  * main.c for ObConf, the configuration tool for Openbox
4  * Copyright (c) 2003-2008   Dana Jansens
5  * Copyright (c) 2003        Tim Riley
6  * Copyright (C) 2013        Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * See the COPYING file for a copy of the GNU General Public License.
19  */
20 
21 #include <glib.h>
22 
23 #include <QApplication>
24 #include <QTranslator>
25 #include <QLibraryInfo>
26 #include <QLocale>
27 #include <QX11Info>
28 #include <QMessageBox>
29 #include "maindialog.h"
30 #include <X11/Xlib.h>
31 #include <X11/Xatom.h>
32 
33 #include "obconf-qt.h"
34 #include "archive.h"
35 #include "preview_update.h"
36 #include <stdlib.h>
37 #include <iostream>
38 
39 using namespace Obconf;
40 
41 xmlDocPtr doc;
42 xmlNodePtr root;
43 RrInstance* rrinst;
44 gchar* obc_config_file = NULL;
45 ObtPaths* paths;
46 ObtXmlInst* parse_i;
47 
48 static gchar* obc_theme_install = NULL;
49 static gchar* obc_theme_archive = NULL;
50 
obconf_error(gchar * msg,gboolean modal)51 void obconf_error(gchar* msg, gboolean modal) {
52   // FIXME: we did not handle modal
53   QMessageBox::critical(NULL, QObject::tr("ObConf Error"), QString::fromUtf8(msg));
54 }
55 
print_version()56 static void print_version() {
57   // g_print("ObConf %s\n", PACKAGE_VERSION);
58   QString output = QObject::tr(
59     "Copyright (c) 2003-2008   Dana Jansens\n"
60     "Copyright (c) 2003        Tim Riley\n"
61     "Copyright (c) 2007        Javeed Shaikh\n"
62     "Copyright (c) 2013        Hong Jen Yee (PCMan)\n\n"
63     "This program comes with ABSOLUTELY NO WARRANTY.\n"
64     "This is free software, and you are welcome to redistribute it\n"
65     "under certain conditions. See the file COPYING for details.\n\n"
66   );
67   std::cout << output.toUtf8().constData();
68 
69   exit(EXIT_SUCCESS);
70 }
71 
print_help()72 static void print_help() {
73   QString output = QObject::tr(
74     "Syntax: obconf [options] [ARCHIVE.obt]\n"
75     "\nOptions:\n"
76     "  --help                Display this help and exit\n"
77     "  --version             Display the version and exit\n"
78     "  --install ARCHIVE.obt Install the given theme archive and select it\n"
79     "  --archive THEME       Create a theme archive from the given theme directory\n"
80     "  --config-file FILE    Specify the path to the config file to use\n"
81   );
82   std::cout << output.toUtf8().constData();
83 
84   exit(EXIT_SUCCESS);
85 }
86 
parse_args(int argc,char ** argv)87 static void parse_args(int argc, char** argv) {
88   int i;
89   for(i = 1; i < argc; ++i) {
90     if(!strcmp(argv[i], "--help"))
91       print_help();
92 
93     if(!strcmp(argv[i], "--version"))
94       print_version();
95     else if(!strcmp(argv[i], "--install")) {
96       if(i == argc - 1)  /* no args left */
97         std::cerr << QObject::tr("--install requires an argument\n").toUtf8().constData();
98       else
99         obc_theme_install = argv[++i];
100     }
101     else if(!strcmp(argv[i], "--archive")) {
102       if(i == argc - 1)  /* no args left */
103         std::cerr << QObject::tr("--archive requires an argument\n").toUtf8().constData();
104       else
105         obc_theme_archive = argv[++i];
106     }
107     else if(!strcmp(argv[i], "--config-file")) {
108       if(i == argc - 1)  /* no args left */
109         std::cerr << QObject::tr("--config-file requires an argument\n").toUtf8().constData();
110       else
111         obc_config_file = argv[++i];
112     }
113     else
114       obc_theme_install = argv[i];
115   }
116 }
117 
get_all(Window win,Atom prop,Atom type,gint size,guchar ** data,guint * num)118 static gboolean get_all(Window win, Atom prop, Atom type, gint size,
119                         guchar** data, guint* num) {
120   gboolean ret = FALSE;
121   gint res;
122   guchar* xdata = NULL;
123   Atom ret_type;
124   gint ret_size;
125   gulong ret_items, bytes_left;
126 
127   res = XGetWindowProperty(QX11Info::display(), win, prop, 0l, G_MAXLONG,
128                            FALSE, type, &ret_type, &ret_size,
129                            &ret_items, &bytes_left, &xdata);
130 
131   if(res == Success) {
132     if(ret_size == size && ret_items > 0) {
133       guint i;
134       *data = (guchar*)g_malloc(ret_items * (size / 8));
135 
136       for(i = 0; i < ret_items; ++i)
137         switch(size) {
138           case 8:
139             (*data)[i] = xdata[i];
140             break;
141           case 16:
142             ((guint16*)*data)[i] = ((gushort*)xdata)[i];
143             break;
144           case 32:
145             ((guint32*)*data)[i] = ((gulong*)xdata)[i];
146             break;
147           default:
148             g_assert_not_reached(); /* unhandled size */
149         }
150 
151       *num = ret_items;
152       ret = TRUE;
153     }
154 
155     XFree(xdata);
156   }
157 
158   return ret;
159 }
160 
prop_get_string_utf8(Window win,Atom prop,gchar ** ret)161 static gboolean prop_get_string_utf8(Window win, Atom prop, gchar** ret) {
162   gchar* raw;
163   gchar* str;
164   guint num;
165 
166   if(get_all(win, prop, XInternAtom(QX11Info::display(), "UTF8_STRING", 0), 8, (guchar**)&raw, &num)) {
167     str = g_strndup(raw, num); /* grab the first string from the list */
168     g_free(raw);
169 
170     if(g_utf8_validate(str, -1, NULL)) {
171       *ret = str;
172       return TRUE;
173     }
174 
175     g_free(str);
176   }
177 
178   return FALSE;
179 }
180 
main(int argc,char ** argv)181 int main(int argc, char** argv) {
182   QApplication app(argc, argv);
183   app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
184 
185   // load translations
186   QTranslator qtTranslator, translator;
187 
188   // install the translations built-into Qt itself
189   qtTranslator.load(QStringLiteral("qt_") + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
190   app.installTranslator(&qtTranslator);
191 
192   // install our own tranlations
193   translator.load(QStringLiteral("obconf-qt_") + QLocale::system().name(), QStringLiteral(PACKAGE_DATA_DIR) + QStringLiteral("/translations"));
194   app.installTranslator(&translator);
195 
196   // load configurations
197 
198   parse_args(argc, argv);
199 
200   if(obc_theme_archive) {
201     archive_create(obc_theme_archive);
202     return 0;
203   }
204 
205   paths = obt_paths_new();
206   parse_i = obt_xml_instance_new();
207   int screen = QX11Info::appScreen();
208   rrinst = RrInstanceNew(QX11Info::display(), screen);
209   if(!obc_config_file) {
210     gchar* p;
211     if(prop_get_string_utf8(QX11Info::appRootWindow(screen),
212                             XInternAtom(QX11Info::display(), "_OB_CONFIG_FILE", 0), &p)) {
213       obc_config_file = g_filename_from_utf8(p, -1, NULL, NULL, NULL);
214       g_free(p);
215     }
216   }
217   xmlIndentTreeOutput = 1;
218 
219   if(!((obc_config_file &&
220         obt_xml_load_file(parse_i, obc_config_file, "openbox_config")) ||
221        obt_xml_load_config_file(parse_i, "openbox", "rc.xml",
222                                 "openbox_config"))) {
223     QMessageBox::critical(NULL, QObject::tr("Error"),
224                           QObject::tr("Failed to load an rc.xml. You have probably failed to install Openbox properly."));
225   }
226   else {
227     doc = obt_xml_doc(parse_i);
228     root = obt_xml_root(parse_i);
229   }
230 
231   /* look for parsing errors */
232   {
233     xmlErrorPtr e = xmlGetLastError();
234 
235     if(e) {
236       QString message = QObject::tr("Error while parsing the Openbox configuration file.  Your configuration file is not valid XML.\n\nMessage: %1")
237         .arg(QString::fromUtf8(e->message));
238       QMessageBox::critical(NULL, QObject::tr("Error"), message);
239     }
240   }
241 
242   // build our GUI
243   MainDialog dlg;
244   if(obc_theme_install)
245     dlg.theme_install(obc_theme_install);
246   else
247     dlg.theme_load_all();
248   dlg.exec();
249 
250   /*
251   preview_update_set_active_font(NULL);
252   preview_update_set_inactive_font(NULL);
253   preview_update_set_menu_header_font(NULL);
254   preview_update_set_menu_item_font(NULL);
255   preview_update_set_osd_active_font(NULL);
256   preview_update_set_osd_inactive_font(NULL);
257   preview_update_set_title_layout(NULL);
258   */
259 
260   RrInstanceFree(rrinst);
261   obt_xml_instance_unref(parse_i);
262   obt_paths_unref(paths);
263   xmlFreeDoc(doc);
264 
265   return 0;
266 }
267