1/* 2 * Copyright 2001 Red Hat Inc., Durham, North Carolina. 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation on the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS 22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 */ 27 28/* 29 * Authors: 30 * Rickard E. (Rik) Faith <faith@redhat.com> 31 * 32 */ 33 34/** \file 35 * This file encapsulated all of the logging functions that are used by 36 * DMX for informational, warning, and error messages. */ 37 38#ifdef HAVE_DMX_CONFIG_H 39#include <dmx-config.h> 40#endif 41 42#include "dmx.h" 43#include "dmxlog.h" 44#include "dmxinput.h" 45#include <X11/extensions/XI.h> 46#include <X11/extensions/XIproto.h> 47 48static dmxLogLevel dmxCurrentLogLevel = dmxDebug; 49 50/** Set the default level for logging to #dmxLogLevel. Returns the 51 * previous log level. */ 52dmxLogLevel dmxSetLogLevel(dmxLogLevel newLevel) 53{ 54 dmxLogLevel oldLevel = dmxCurrentLogLevel; 55 if (newLevel > dmxFatal) newLevel = dmxFatal; 56 dmxCurrentLogLevel = newLevel; 57 return oldLevel; 58} 59 60/** Returns the log level set by #dmxLogLevel. */ 61dmxLogLevel dmxGetLogLevel(void) 62{ 63 return dmxCurrentLogLevel; 64} 65 66#ifdef DMX_LOG_STANDALONE 67/* When using this file as part of a stand-alone (i.e., non-X-Server 68 * program, then the ultimate output routines have to be defined. */ 69 70/** Provide an ErrorF function when used stand-alone. */ 71void ErrorF(const char *format, ...) 72{ 73 va_list args; 74 75 va_start(args, format); 76 vfprintf(stderr, format, args); /* RATS: We assume the format string 77 * is trusted, since it is always 78 * from a log message in our code. */ 79 va_end(args); 80} 81 82/** Provide an VFatalError function when used stand-alone. */ 83static void VFatalError(const char *format, va_list args) 84{ 85 vfprintf(stderr, format, args); /* RATS: We assume the format string 86 * is trusted, since it is always 87 * from a log message in our code. */ 88 exit(1); 89} 90 91/** Provide an VErrorF function when used stand-alone. */ 92void VErrorF(const char *format, va_list args) 93{ 94 vfprintf(stderr, format, args); /* RATS: We assume the format string 95 * is trusted, since it is always 96 * from a log message in our code. */ 97} 98#else 99/** This function was removed between XFree86 4.3.0 and XFree86 4.4.0. */ 100extern void AbortServer(void); 101static void VFatalError(const char *format, va_list args) 102{ 103 VErrorF(format, args); 104 ErrorF("\n"); 105#ifdef DDXOSFATALERROR 106 OsVendorFatalError(); 107#endif 108 AbortServer(); 109 /*NOTREACHED*/ 110} 111#endif 112 113/* Prints a consistent header for each line. */ 114static void dmxHeader(dmxLogLevel logLevel, DMXInputInfo *dmxInput, 115 DMXScreenInfo *dmxScreen) 116{ 117 const char *type = "??"; 118 119 switch (logLevel) { 120 case dmxDebug: type = ".."; break; 121 case dmxInfo: type = "II"; break; 122 case dmxWarning: type = "**"; break; 123 case dmxError: type = "!!"; break; 124 case dmxFatal: type = "Fatal Error"; break; 125 } 126 127 if (dmxInput && dmxScreen) { 128 ErrorF("(%s) dmx[i%d/%s;o%d/%s]: ", type, 129 dmxInput->inputIdx, dmxInput->name, 130 dmxScreen->index, dmxScreen->name); 131 } else if (dmxScreen) { 132 ErrorF("(%s) dmx[o%d/%s]: ", type, 133 dmxScreen->index, dmxScreen->name); 134 } else if (dmxInput) { 135 const char *pt = strchr(dmxInput->name, ','); 136 int len = (pt 137 ? (size_t)(pt-dmxInput->name) 138 : strlen(dmxInput->name)); 139 140 ErrorF("(%s) dmx[i%d/%*.*s]: ", type, 141 dmxInput->inputIdx, len, len, dmxInput->name); 142 } else { 143 ErrorF("(%s) dmx: ", type); 144 } 145} 146 147/* Prints the error message with the appropriate low-level X output 148 * routine. */ 149static void dmxMessage(dmxLogLevel logLevel, const char *format, va_list args) 150{ 151 if (logLevel == dmxFatal || logLevel >= dmxCurrentLogLevel) { 152 if (logLevel == dmxFatal) VFatalError(format, args); 153 else VErrorF(format, args); 154 } 155} 156 157/** Log the specified message at the specified \a logLevel. \a format 158 * can be a printf-like format expression. */ 159void dmxLog(dmxLogLevel logLevel, const char *format, ...) 160{ 161 va_list args; 162 163 dmxHeader(logLevel, NULL, NULL); 164 va_start(args, format); 165 dmxMessage(logLevel, format, args); 166 va_end(args); 167} 168 169/** Continue a log message without printing the message prefix. */ 170void dmxLogCont(dmxLogLevel logLevel, const char *format, ...) 171{ 172 va_list args; 173 174 va_start(args, format); 175 dmxMessage(logLevel, format, args); 176 va_end(args); 177} 178 179#ifndef DMX_LOG_STANDALONE 180/** Log an informational message (at level #dmxInfo) related to ouput. 181 * The message prefix will contain backend information from \a 182 * dmxScreen. */ 183void dmxLogOutput(DMXScreenInfo *dmxScreen, const char *format, ...) 184{ 185 va_list args; 186 187 dmxHeader(dmxInfo, NULL, dmxScreen); 188 va_start(args, format); 189 dmxMessage(dmxInfo, format, args); 190 va_end(args); 191} 192 193/** Continue a message related to output without printing the message 194 * prefix. */ 195void dmxLogOutputCont(DMXScreenInfo *dmxScreen, const char *format, ...) 196{ 197 va_list args; 198 199 va_start(args, format); 200 dmxMessage(dmxInfo, format, args); 201 va_end(args); 202} 203 204/** Log a warning message (at level #dmxWarning) related to output. 205 * The message prefix will contain backend information from \a 206 * dmxScreen. */ 207void dmxLogOutputWarning(DMXScreenInfo *dmxScreen, const char *format, ...) 208{ 209 va_list args; 210 211 dmxHeader(dmxWarning, NULL, dmxScreen); 212 va_start(args, format); 213 dmxMessage(dmxWarning, format, args); 214 va_end(args); 215} 216 217/** Log an informational message (at level #dmxInfo) related to input. 218 * The message prefix will contain information from \a dmxInput. */ 219void dmxLogInput(DMXInputInfo *dmxInput, const char *format, ...) 220{ 221 va_list args; 222 223 dmxHeader(dmxInfo, dmxInput, NULL); 224 va_start(args, format); 225 dmxMessage(dmxInfo, format, args); 226 va_end(args); 227} 228 229/** Continue a message related to input without printing the message 230 * prefix. */ 231void dmxLogInputCont(DMXInputInfo *dmxInput, const char *format, ...) 232{ 233 va_list args; 234 235 va_start(args, format); 236 dmxMessage(dmxInfo, format, args); 237 va_end(args); 238} 239 240/** Print \a argc messages, each describing an element in \a argv. This 241 * is maingly for debugging purposes. */ 242void dmxLogArgs(dmxLogLevel logLevel, int argc, char **argv) 243{ 244 int i; 245 for (i = 0; i < argc; i++) 246 dmxLog(logLevel, " Arg[%d] = \"%s\"\n", i, argv[i]); 247} 248 249/** Print messages at level #dmxInfo describing the visuals in \a vi. */ 250void dmxLogVisual(DMXScreenInfo *dmxScreen, XVisualInfo *vi, int defaultVisual) 251{ 252 const char *class = "Unknown"; 253 254 switch (vi->class) { 255 case StaticGray: class = "StaticGray "; break; 256 case GrayScale: class = "GrayScale "; break; 257 case StaticColor: class = "StaticColor"; break; 258 case PseudoColor: class = "PseudoColor"; break; 259 case TrueColor: class = "TrueColor "; break; 260 case DirectColor: class = "DirectColor"; break; 261 } 262 263 if (dmxScreen) { 264 dmxLogOutput(dmxScreen, 265 "0x%02x %s %2db %db/rgb %3d 0x%04x 0x%04x 0x%04x%s\n", 266 vi->visualid, class, vi->depth, vi->bits_per_rgb, 267 vi->colormap_size, 268 vi->red_mask, vi->green_mask, vi->blue_mask, 269 defaultVisual ? " *" : ""); 270 } else { 271 dmxLog(dmxInfo, 272 " 0x%02x %s %2db %db/rgb %3d 0x%04x 0x%04x 0x%04x%s\n", 273 vi->visualid, class, vi->depth, vi->bits_per_rgb, 274 vi->colormap_size, 275 vi->red_mask, vi->green_mask, vi->blue_mask, 276 defaultVisual ? " *" : ""); 277 } 278} 279 280/** Translate a (normalized) XInput event \a type into a human-readable 281 * string. */ 282const char *dmxXInputEventName(int type) 283{ 284 switch (type) { 285 case XI_DeviceValuator: return "XI_DeviceValuator"; 286 case XI_DeviceKeyPress: return "XI_DeviceKeyPress"; 287 case XI_DeviceKeyRelease: return "XI_DeviceKeyRelease"; 288 case XI_DeviceButtonPress: return "XI_DeviceButtonPress"; 289 case XI_DeviceButtonRelease: return "XI_DeviceButtonRelease"; 290 case XI_DeviceMotionNotify: return "XI_DeviceMotionNotify"; 291 case XI_DeviceFocusIn: return "XI_DeviceFocusIn"; 292 case XI_DeviceFocusOut: return "XI_DeviceFocusOut"; 293 case XI_ProximityIn: return "XI_ProximityIn"; 294 case XI_ProximityOut: return "XI_ProximityOut"; 295 case XI_DeviceStateNotify: return "XI_DeviceStateNotify"; 296 case XI_DeviceMappingNotify: return "XI_DeviceMappingNotify"; 297 case XI_ChangeDeviceNotify: return "XI_ChangeDeviceNotify"; 298 case XI_DeviceKeystateNotify: return "XI_DeviceKeystateNotify"; 299 case XI_DeviceButtonstateNotify: return "XI_DeviceButtonstateNotify"; 300 default: return "unknown"; 301 } 302} 303 304#endif 305 306/** Translate an event \a type into a human-readable string. */ 307const char *dmxEventName(int type) 308{ 309 switch (type) { 310 case KeyPress: return "KeyPress"; 311 case KeyRelease: return "KeyRelease"; 312 case ButtonPress: return "ButtonPress"; 313 case ButtonRelease: return "ButtonRelease"; 314 case MotionNotify: return "MotionNotify"; 315 case EnterNotify: return "EnterNotify"; 316 case LeaveNotify: return "LeaveNotify"; 317 case FocusIn: return "FocusIn"; 318 case FocusOut: return "FocusOut"; 319 case KeymapNotify: return "KeymapNotify"; 320 case Expose: return "Expose"; 321 case GraphicsExpose: return "GraphicsExpose"; 322 case NoExpose: return "NoExpose"; 323 case VisibilityNotify: return "VisibilityNotify"; 324 case CreateNotify: return "CreateNotify"; 325 case DestroyNotify: return "DestroyNotify"; 326 case UnmapNotify: return "UnmapNotify"; 327 case MapNotify: return "MapNotify"; 328 case MapRequest: return "MapRequest"; 329 case ReparentNotify: return "ReparentNotify"; 330 case ConfigureNotify: return "ConfigureNotify"; 331 case ConfigureRequest: return "ConfigureRequest"; 332 case GravityNotify: return "GravityNotify"; 333 case ResizeRequest: return "ResizeRequest"; 334 case CirculateNotify: return "CirculateNotify"; 335 case CirculateRequest: return "CirculateRequest"; 336 case PropertyNotify: return "PropertyNotify"; 337 case SelectionClear: return "SelectionClear"; 338 case SelectionRequest: return "SelectionRequest"; 339 case SelectionNotify: return "SelectionNotify"; 340 case ColormapNotify: return "ColormapNotify"; 341 case ClientMessage: return "ClientMessage"; 342 case MappingNotify: return "MappingNotify"; 343 default: return "<unknown>"; 344 } 345} 346 347