1 /*
2 * Copyright © 2005 Novell, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * Novell, Inc. not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior permission.
11 * Novell, Inc. makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *
15 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author: David Reveman <davidr@novell.com>
24 */
25
26 #ifdef HAVE_CONFIG_H
27 # include "../config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <signal.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sys/wait.h>
36
37 #include <compiz-core.h>
38
39 char *programName;
40 char **programArgv;
41 int programArgc;
42
43 char **initialPlugins = NULL;
44 int nInitialPlugins = 0;
45
46 char *backgroundImage = NULL;
47
48 REGION emptyRegion;
49 REGION infiniteRegion;
50 GLushort defaultColor[4] = { 0xffff, 0xffff, 0xffff, 0xffff };
51 Window currentRoot = 0;
52
53 int defaultRefreshRate = 50;
54 char *defaultTextureFilter = "Good";
55
56 Bool shutDown = FALSE;
57 Bool restartSignal = FALSE;
58 Bool coreInitialized = FALSE;
59
60 CompWindow *lastFoundWindow = 0;
61 CompWindow *lastDamagedWindow = 0;
62
63 Bool replaceCurrentWm = FALSE;
64 Bool indirectRendering = FALSE;
65 Bool strictBinding = TRUE;
66 Bool noDetection = FALSE;
67 Bool useDesktopHints = FALSE;
68 Bool onlyCurrentScreen = FALSE;
69 static Bool debugOutput = FALSE;
70
71 #ifdef USE_COW
72 Bool useCow = TRUE;
73 #endif
74
75 CompMetadata coreMetadata;
76
77 static void
usage(void)78 usage (void)
79 {
80 printf ("Usage: %s\n "
81 "[--display DISPLAY] "
82 "[--bg-image PNG] "
83 "[--refresh-rate RATE]\n "
84 "[--fast-filter] "
85 "[--indirect-rendering] "
86 "[--no-detection]\n "
87 "[--keep-desktop-hints] "
88 "[--loose-binding] "
89 "[--replace]\n "
90 "[--sm-disable] "
91 "[--sm-client-id ID] "
92 "[--only-current-screen]\n "
93
94 #ifdef USE_COW
95 " [--use-root-window] "
96 #endif
97
98 "[--debug] "
99 "[--version] "
100 "[--help] "
101 "[PLUGIN]...\n",
102 programName);
103 }
104
105 void
compLogMessage(const char * componentName,CompLogLevel level,const char * format,...)106 compLogMessage (const char *componentName,
107 CompLogLevel level,
108 const char *format,
109 ...)
110 {
111 va_list args;
112 char message[2048];
113
114 va_start (args, format);
115
116 vsnprintf (message, 2048, format, args);
117
118 if (coreInitialized)
119 (*core.logMessage) (componentName, level, message);
120 else
121 logMessage (componentName, level, message);
122
123 va_end (args);
124 }
125
126 void
logMessage(const char * componentName,CompLogLevel level,const char * message)127 logMessage (const char *componentName,
128 CompLogLevel level,
129 const char *message)
130 {
131 if (!debugOutput && level >= CompLogLevelDebug)
132 return;
133
134 fprintf (stderr, "%s (%s) - %s: %s\n",
135 programName, componentName,
136 logLevelToString (level), message);
137 }
138
139 const char *
logLevelToString(CompLogLevel level)140 logLevelToString (CompLogLevel level)
141 {
142 switch (level) {
143 case CompLogLevelFatal:
144 return "Fatal";
145 case CompLogLevelError:
146 return "Error";
147 case CompLogLevelWarn:
148 return "Warn";
149 case CompLogLevelInfo:
150 return "Info";
151 case CompLogLevelDebug:
152 return "Debug";
153 default:
154 break;
155 }
156
157 return "Unknown";
158 }
159
160 static void
signalHandler(int sig)161 signalHandler (int sig)
162 {
163 int status;
164
165 switch (sig) {
166 case SIGCHLD:
167 waitpid (-1, &status, WNOHANG | WUNTRACED);
168 break;
169 case SIGHUP:
170 restartSignal = TRUE;
171 break;
172 case SIGINT:
173 case SIGTERM:
174 shutDown = TRUE;
175 default:
176 break;
177 }
178 }
179
180 typedef struct _CompIOCtx {
181 int offset;
182 char *pluginData;
183 char *textureFilterData;
184 char *refreshRateData;
185 } CompIOCtx;
186
187 static int
readCoreXmlCallback(void * context,char * buffer,int length)188 readCoreXmlCallback (void *context,
189 char *buffer,
190 int length)
191 {
192 CompIOCtx *ctx = (CompIOCtx *) context;
193 int offset = ctx->offset;
194 int i, j;
195
196 i = compReadXmlChunk ("<compiz><core><display>", &offset, buffer, length);
197
198 for (j = 0; j < COMP_DISPLAY_OPTION_NUM; j++)
199 {
200 CompMetadataOptionInfo info = coreDisplayOptionInfo[j];
201
202 switch (j) {
203 case COMP_DISPLAY_OPTION_ACTIVE_PLUGINS:
204 if (ctx->pluginData)
205 info.data = ctx->pluginData;
206 break;
207 case COMP_DISPLAY_OPTION_TEXTURE_FILTER:
208 if (ctx->textureFilterData)
209 info.data = ctx->textureFilterData;
210 default:
211 break;
212 }
213
214 i += compReadXmlChunkFromMetadataOptionInfo (&info,
215 &offset,
216 buffer + i,
217 length - i);
218 }
219
220 i += compReadXmlChunk ("</display><screen>", &offset,
221 buffer + i, length - 1);
222
223 for (j = 0; j < COMP_SCREEN_OPTION_NUM; j++)
224 {
225 CompMetadataOptionInfo info = coreScreenOptionInfo[j];
226
227 switch (j) {
228 case COMP_SCREEN_OPTION_REFRESH_RATE:
229 if (ctx->refreshRateData)
230 info.data = ctx->refreshRateData;
231 default:
232 break;
233 }
234
235 i += compReadXmlChunkFromMetadataOptionInfo (&info,
236 &offset,
237 buffer + i,
238 length - i);
239 }
240
241 i += compReadXmlChunk ("</screen></core></compiz>", &offset, buffer + i,
242 length - i);
243
244 if (!offset && length > i)
245 buffer[i++] = '\0';
246
247 ctx->offset += i;
248
249 return i;
250 }
251
252 int
main(int argc,char ** argv)253 main (int argc, char **argv)
254 {
255 CompIOCtx ctx;
256 char *displayName = 0;
257 char *plugin[256];
258 int i, nPlugin = 0;
259 Bool disableSm = FALSE;
260 char *clientId = NULL;
261 char *refreshRateArg = NULL;
262
263 programName = argv[0];
264 programArgc = argc;
265 programArgv = argv;
266
267 signal (SIGHUP, signalHandler);
268 signal (SIGCHLD, signalHandler);
269 signal (SIGINT, signalHandler);
270 signal (SIGTERM, signalHandler);
271
272 emptyRegion.rects = &emptyRegion.extents;
273 emptyRegion.numRects = 0;
274 emptyRegion.extents.x1 = 0;
275 emptyRegion.extents.y1 = 0;
276 emptyRegion.extents.x2 = 0;
277 emptyRegion.extents.y2 = 0;
278 emptyRegion.size = 0;
279
280 infiniteRegion.rects = &infiniteRegion.extents;
281 infiniteRegion.numRects = 1;
282 infiniteRegion.extents.x1 = MINSHORT;
283 infiniteRegion.extents.y1 = MINSHORT;
284 infiniteRegion.extents.x2 = MAXSHORT;
285 infiniteRegion.extents.y2 = MAXSHORT;
286
287 memset (&ctx, 0, sizeof (ctx));
288
289 for (i = 1; i < argc; i++)
290 {
291 if (!strcmp (argv[i], "--help"))
292 {
293 usage ();
294 return 0;
295 }
296 else if (!strcmp (argv[i], "--version"))
297 {
298 printf (PACKAGE_STRING "\n");
299 return 0;
300 }
301 else if (!strcmp (argv[i], "--debug"))
302 {
303 debugOutput = TRUE;
304 }
305 else if (!strcmp (argv[i], "--display"))
306 {
307 if (i + 1 < argc)
308 displayName = argv[++i];
309 }
310 else if (!strcmp (argv[i], "--refresh-rate"))
311 {
312 if (i + 1 < argc)
313 {
314 refreshRateArg = programArgv[++i];
315 defaultRefreshRate = atoi (refreshRateArg);
316 defaultRefreshRate = RESTRICT_VALUE (defaultRefreshRate,
317 1, 1000);
318 }
319 }
320 else if (!strcmp (argv[i], "--fast-filter"))
321 {
322 ctx.textureFilterData = "<default>Fast</default>";
323 defaultTextureFilter = "Fast";
324 }
325 else if (!strcmp (argv[i], "--indirect-rendering"))
326 {
327 /* force Mesa libGL into indirect rendering mode, because
328 glXQueryExtensionsString is context-independant */
329 setenv ("LIBGL_ALWAYS_INDIRECT", "1", True);
330 indirectRendering = TRUE;
331 }
332 else if (!strcmp (argv[i], "--loose-binding"))
333 {
334 strictBinding = FALSE;
335 }
336 else if (!strcmp (argv[i], "--ignore-desktop-hints"))
337 {
338 /* keep command line parameter for backward compatibility */
339 useDesktopHints = FALSE;
340 }
341 else if (!strcmp (argv[i], "--keep-desktop-hints"))
342 {
343 useDesktopHints = TRUE;
344 }
345 else if (!strcmp (argv[i], "--only-current-screen"))
346 {
347 onlyCurrentScreen = TRUE;
348 }
349
350 #ifdef USE_COW
351 else if (!strcmp (argv[i], "--use-root-window"))
352 {
353 useCow = FALSE;
354 }
355 #endif
356
357 else if (!strcmp (argv[i], "--replace"))
358 {
359 replaceCurrentWm = TRUE;
360 }
361 else if (!strcmp (argv[i], "--sm-disable"))
362 {
363 disableSm = TRUE;
364 }
365 else if (!strcmp (argv[i], "--sm-client-id"))
366 {
367 if (i + 1 < argc)
368 clientId = argv[++i];
369 }
370 else if (!strcmp (argv[i], "--no-detection"))
371 {
372 noDetection = TRUE;
373 }
374 else if (!strcmp (argv[i], "--bg-image"))
375 {
376 if (i + 1 < argc)
377 backgroundImage = argv[++i];
378 }
379 else if (*argv[i] == '-')
380 {
381 compLogMessage ("core", CompLogLevelWarn,
382 "Unknown option '%s'\n", argv[i]);
383 }
384 else
385 {
386 if (nPlugin < 256)
387 plugin[nPlugin++] = argv[i];
388 }
389 }
390
391 if (refreshRateArg)
392 {
393 ctx.refreshRateData = malloc (strlen (refreshRateArg) + 256);
394 if (ctx.refreshRateData)
395 sprintf (ctx.refreshRateData,
396 "<min>1</min><default>%s</default>",
397 refreshRateArg);
398 }
399
400 if (nPlugin)
401 {
402 int size = 256;
403
404 for (i = 0; i < nPlugin; i++)
405 size += strlen (plugin[i]) + 16;
406
407 ctx.pluginData = malloc (size);
408 if (ctx.pluginData)
409 {
410 char *ptr = ctx.pluginData;
411
412 ptr += sprintf (ptr, "<type>string</type><default>");
413
414 for (i = 0; i < nPlugin; i++)
415 ptr += sprintf (ptr, "<value>%s</value>", plugin[i]);
416
417 ptr += sprintf (ptr, "</default>");
418 }
419
420 initialPlugins = malloc (nPlugin * sizeof (char *));
421 if (initialPlugins)
422 {
423 memcpy (initialPlugins, plugin, nPlugin * sizeof (char *));
424 nInitialPlugins = nPlugin;
425 }
426 else
427 {
428 nInitialPlugins = 0;
429 }
430 }
431
432 xmlInitParser ();
433
434 LIBXML_TEST_VERSION;
435
436 if (!compInitMetadata (&coreMetadata))
437 {
438 compLogMessage ("core", CompLogLevelFatal,
439 "Couldn't initialize core metadata");
440 return 1;
441 }
442
443 if (!compAddMetadataFromIO (&coreMetadata,
444 readCoreXmlCallback, NULL,
445 &ctx))
446 return 1;
447
448 if (ctx.refreshRateData)
449 free (ctx.refreshRateData);
450
451 if (ctx.pluginData)
452 free (ctx.pluginData);
453
454 compAddMetadataFromFile (&coreMetadata, "core");
455
456 if (!initCore ())
457 return 1;
458
459 coreInitialized = TRUE;
460
461 if (!disableSm)
462 initSession (clientId);
463
464 if (!addDisplay (displayName))
465 return 1;
466
467 eventLoop ();
468
469 if (!disableSm)
470 closeSession ();
471
472 coreInitialized = FALSE;
473
474 finiCore ();
475 compFiniMetadata (&coreMetadata);
476
477 xmlCleanupParser ();
478
479 if (initialPlugins)
480 free (initialPlugins);
481
482 if (restartSignal)
483 {
484 execvp (programName, programArgv);
485 return 1;
486 }
487
488 return 0;
489 }
490