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