4 * Copyright 1994 Alexandre Julliard
6 static char Copyright[] = "Copyright Alexandre Julliard, 1994";
14 #include <X11/Xresource.h>
15 #include <X11/Xutil.h>
16 #include <X11/cursorfont.h>
26 #include "prototypes.h"
28 #define DEBUG_DEFINE_VARIABLES
32 extern ButtonTexts ButtonText
;
34 static const char people
[] = "Wine is available thanks to the work of "\
35 "Bob Amstadt, Dag Asheim, Martin Ayotte, Erik Bos, John Brezak, "\
36 "Andrew Bulhak, John Burton, Paul Falstad, Peter Galbavy, Jeffrey Hsu, "\
37 "Miguel de Icaza, Alexandre Julliard, Jon Konrath, Scott A. Laird, "\
38 "Martin von Loewis, Kenneth MacDonald, Peter MacDonald, David Metcalfe, "\
39 "Michael Patra, John Richardson, Johannes Ruscheinski, Yngvi Sigurjonsson, "\
40 "Rick Sladkey, William Smith, Jon Tombs, Linus Torvalds, Carl Williams, "\
41 "Karl Guenter Wuensch, and Eric Youngdale.";
43 #define WINE_CLASS "Wine" /* Class name for resources */
45 typedef struct tagENVENTRY
{
49 struct tagENVENTRY
*Prev
;
50 struct tagENVENTRY
*Next
;
52 typedef ENVENTRY
*LPENVENTRY
;
54 LPENVENTRY lpEnvList
= NULL
;
59 int screenWidth
= 0, screenHeight
= 0; /* Desktop window dimensions */
60 int screenDepth
= 0; /* Screen depth to use */
61 int desktopX
= 0, desktopY
= 0; /* Desktop window position (if any) */
63 struct options Options
=
64 { /* default options */
65 NULL
, /* spyFilename */
66 NULL
, /* desktopGeometry */
67 NULL
, /* programName */
68 FALSE
, /* usePrivateMap */
69 FALSE
, /* synchronous */
70 FALSE
, /* backing store */
71 SW_SHOWNORMAL
, /* cmdShow */
76 static XrmOptionDescRec optionsTable
[] =
78 { "-backingstore", ".backingstore", XrmoptionNoArg
, (caddr_t
)"on" },
79 { "-desktop", ".desktop", XrmoptionSepArg
, (caddr_t
)NULL
},
80 { "-depth", ".depth", XrmoptionSepArg
, (caddr_t
)NULL
},
81 { "-display", ".display", XrmoptionSepArg
, (caddr_t
)NULL
},
82 { "-iconic", ".iconic", XrmoptionNoArg
, (caddr_t
)"on" },
83 { "-name", ".name", XrmoptionSepArg
, (caddr_t
)NULL
},
84 { "-privatemap", ".privatemap", XrmoptionNoArg
, (caddr_t
)"on" },
85 { "-synchronous", ".synchronous", XrmoptionNoArg
, (caddr_t
)"on" },
86 { "-spy", ".spy", XrmoptionSepArg
, (caddr_t
)NULL
},
87 { "-debug", ".debug", XrmoptionNoArg
, (caddr_t
)"on" },
88 { "-debugmsg", ".debugmsg", XrmoptionSepArg
, (caddr_t
)NULL
}
91 #define NB_OPTIONS (sizeof(optionsTable) / sizeof(optionsTable[0]))
94 "Usage: %s [options] program_name [arguments]\n" \
97 " -depth n Change the depth to use for multiple-depth screens\n" \
98 " -desktop geom Use a desktop window of the given geometry\n" \
99 " -display name Use the specified display\n" \
100 " -iconic Start as an icon\n" \
101 " -debug Enter debugger before starting application\n" \
102 " -name name Set the application name\n" \
103 " -privatemap Use a private color map\n" \
104 " -synchronous Turn on synchronous display mode\n" \
105 " -backingstore Turn on backing store\n" \
106 " -spy file Turn on message spying to the specified file\n" \
107 " -relaydbg Obsolete. Use -debugmsg +relay instead\n" \
108 " -debugmsg name Turn debugging-messages on or off\n"
111 /***********************************************************************
114 static void MAIN_Usage( char *name
)
116 fprintf( stderr
, USAGE
, name
);
121 /***********************************************************************
122 * MAIN_GetProgramName
124 * Get the program name. The name is specified by (in order of precedence):
125 * - the option '-name'.
126 * - the environment variable 'WINE_NAME'.
127 * - the last component of argv[0].
129 static char *MAIN_GetProgramName( int argc
, char *argv
[] )
134 for (i
= 1; i
< argc
-1; i
++)
135 if (!strcmp( argv
[i
], "-name" )) return argv
[i
+1];
136 if ((p
= getenv( "WINE_NAME" )) != NULL
) return p
;
137 if ((p
= strrchr( argv
[0], '/' )) != NULL
) return p
+1;
142 /***********************************************************************
145 * Fetch the value of resource 'name' using the correct instance name.
146 * 'name' must begin with '.' or '*'
148 static int MAIN_GetResource( XrmDatabase db
, char *name
, XrmValue
*value
)
150 char *buff_instance
, *buff_class
;
154 buff_instance
= (char *)malloc(strlen(Options
.programName
)+strlen(name
)+1);
155 buff_class
= (char *)malloc( strlen(WINE_CLASS
) + strlen(name
) + 1 );
157 strcpy( buff_instance
, Options
.programName
);
158 strcat( buff_instance
, name
);
159 strcpy( buff_class
, WINE_CLASS
);
160 strcat( buff_class
, name
);
161 retval
= XrmGetResource( db
, buff_instance
, buff_class
, &dummy
, value
);
162 free( buff_instance
);
168 /***********************************************************************
171 * Fetch the value of resource 'name' using the correct instance name.
172 * 'name' must begin with '.' or '*'
174 * The address of the string got from the XResoure is stored in Button.Label.
175 * The corresponding hotkey is taken from this string.
178 static void MAIN_GetButtonText( XrmDatabase db
, char *name
, ButtonDesc
*Button
)
183 if (MAIN_GetResource( db
, name
, &value
))
185 Button
->Label
= value
.addr
;
186 i
= strchr(Button
->Label
,'&');
188 Button
->Hotkey
= '\0';
189 else if ( i
++ == '\0' )
190 Button
->Hotkey
= '\0';
194 Button
->Hotkey
= toupper(Button
->Hotkey
);
197 /***********************************************************************
198 * MAIN_GetAllButtonTexts
200 * Read all Button-labels from X11-resources if they exist.
203 static void MAIN_GetAllButtonTexts(XrmDatabase db
)
205 MAIN_GetButtonText(db
, ".YesLabel", &ButtonText
.Yes
);
206 MAIN_GetButtonText(db
, ".NoLabel", &ButtonText
.No
);
207 MAIN_GetButtonText(db
, ".OkLabel", &ButtonText
.Ok
);
208 MAIN_GetButtonText(db
, ".CancelLabel", &ButtonText
.Cancel
);
209 MAIN_GetButtonText(db
, ".AbortLabel", &ButtonText
.Abort
);
210 MAIN_GetButtonText(db
, ".RetryLabel", &ButtonText
.Retry
);
211 MAIN_GetButtonText(db
, ".IgnoreLabel", &ButtonText
.Ignore
);
212 MAIN_GetButtonText(db
, ".CancelLabel", &ButtonText
.Cancel
);
215 /***********************************************************************
218 * Turns specific debug messages on or off, according to "options".
219 * Returns TRUE if parsing was successfull
223 BOOL
ParseDebugOptions(char *options
)
226 if (strlen(options
)<3)
230 if ((*options
!='+')&&(*options
!='-'))
232 if (strchr(options
,','))
233 l
=strchr(options
,',')-options
;
236 if (!strncasecmp(options
+1,"all",l
-1))
239 for (i
=0;i
<sizeof(debug_msg_enabled
)/sizeof(short);i
++)
240 debug_msg_enabled
[i
]=(*options
=='+');
245 for (i
=0;i
<sizeof(debug_msg_enabled
)/sizeof(short);i
++)
246 if (debug_msg_name
&& (!strncasecmp(options
+1,debug_msg_name
[i
],l
-1)))
248 debug_msg_enabled
[i
]=(*options
=='+');
251 if (i
==sizeof(debug_msg_enabled
)/sizeof(short))
256 while((*options
==',')&&(*(++options
)));
265 /***********************************************************************
268 * Parse command line options and open display.
270 static void MAIN_ParseOptions( int *argc
, char *argv
[] )
274 XrmDatabase db
= XrmGetFileDatabase("/usr/lib/X11/app-defaults/Wine");
276 /* Parse command line */
277 Options
.programName
= MAIN_GetProgramName( *argc
, argv
);
278 XrmParseCommand( &db
, optionsTable
, NB_OPTIONS
,
279 Options
.programName
, argc
, argv
);
282 /* Need to assemble command line and pass it to WinMain */
284 if (*argc
< 2 || strcasecmp(argv
[1], "-h") == 0)
285 MAIN_Usage( argv
[0] );
290 if (MAIN_GetResource( db
, ".display", &value
)) display_name
= value
.addr
;
291 else display_name
= NULL
;
293 if (!(display
= XOpenDisplay( display_name
)))
295 fprintf( stderr
, "%s: Can't open display: %s\n",
296 argv
[0], display_name
? display_name
: "" );
300 /* Get all options */
301 if (MAIN_GetResource( db
, ".iconic", &value
))
302 Options
.cmdShow
= SW_SHOWMINIMIZED
;
303 if (MAIN_GetResource( db
, ".privatemap", &value
))
304 Options
.usePrivateMap
= TRUE
;
305 if (MAIN_GetResource( db
, ".synchronous", &value
))
306 Options
.synchronous
= TRUE
;
307 if (MAIN_GetResource( db
, ".backingstore", &value
))
308 Options
.backingstore
= TRUE
;
309 if (MAIN_GetResource( db
, ".debug", &value
))
310 Options
.debug
= TRUE
;
311 if (MAIN_GetResource( db
, ".spy", &value
))
312 Options
.spyFilename
= value
.addr
;
313 if (MAIN_GetResource( db
, ".depth", &value
))
314 screenDepth
= atoi( value
.addr
);
315 if (MAIN_GetResource( db
, ".desktop", &value
))
316 Options
.desktopGeometry
= value
.addr
;
318 if (MAIN_GetResource( db
, ".debugoptions", &value
))
319 ParseDebugOptions((char*)value
.addr
);
321 if (MAIN_GetResource( db
, ".debugmsg", &value
))
323 #ifndef DEBUG_RUNTIME
324 fprintf(stderr
,"%s: Option \"-debugmsg\" not implemented.\n" \
325 " Recompile with DEBUG_RUNTIME in include/stddebug.h defined.\n",
329 if (ParseDebugOptions((char*)value
.addr
)==FALSE
)
332 fprintf(stderr
,"%s: Syntax: -debugmsg +xxx,... or -debugmsg -xxx,...\n",argv
[0]);
333 fprintf(stderr
,"Example: -debugmsg +all,-heap turn on all messages except heap messages\n");
334 fprintf(stderr
,"Available message types:\n");
335 fprintf(stderr
,"%-9s ","all");
336 for(i
=0;i
<sizeof(debug_msg_enabled
)/sizeof(short);i
++)
337 if(debug_msg_name
[i
])
338 fprintf(stderr
,"%-9s%c",debug_msg_name
[i
],
339 (((i
+2)%8==0)?'\n':' '));
340 fprintf(stderr
,"\n\n");
346 /* MAIN_GetAllButtonTexts(db); */
351 /***********************************************************************
354 static void MAIN_CreateDesktop( int argc
, char *argv
[] )
357 unsigned int width
= 640, height
= 480; /* Default size = 640x480 */
358 char *name
= "Wine desktop";
359 XSizeHints
*size_hints
;
361 XClassHint
*class_hints
;
362 XSetWindowAttributes win_attr
;
363 XTextProperty window_name
;
365 flags
= XParseGeometry( Options
.desktopGeometry
,
366 &desktopX
, &desktopY
, &width
, &height
);
368 screenHeight
= height
;
372 win_attr
.event_mask
= ExposureMask
| KeyPressMask
| KeyReleaseMask
|
373 PointerMotionMask
| ButtonPressMask
|
374 ButtonReleaseMask
| EnterWindowMask
|
376 win_attr
.cursor
= XCreateFontCursor( display
, XC_top_left_arrow
);
378 rootWindow
= XCreateWindow( display
, DefaultRootWindow(display
),
379 desktopX
, desktopY
, width
, height
, 0,
380 CopyFromParent
, InputOutput
, CopyFromParent
,
381 CWEventMask
| CWCursor
, &win_attr
);
383 /* Set window manager properties */
385 size_hints
= XAllocSizeHints();
386 wm_hints
= XAllocWMHints();
387 class_hints
= XAllocClassHint();
388 if (!size_hints
|| !wm_hints
|| !class_hints
)
390 fprintf( stderr
, "Not enough memory for window manager hints.\n" );
393 size_hints
->min_width
= size_hints
->max_width
= width
;
394 size_hints
->min_height
= size_hints
->max_height
= height
;
395 size_hints
->flags
= PMinSize
| PMaxSize
;
396 if (flags
& (XValue
| YValue
)) size_hints
->flags
|= USPosition
;
397 if (flags
& (WidthValue
| HeightValue
)) size_hints
->flags
|= USSize
;
398 else size_hints
->flags
|= PSize
;
400 wm_hints
->flags
= InputHint
| StateHint
;
401 wm_hints
->input
= True
;
402 wm_hints
->initial_state
= NormalState
;
403 class_hints
->res_name
= argv
[0];
404 class_hints
->res_class
= "Wine";
406 XStringListToTextProperty( &name
, 1, &window_name
);
407 XSetWMProperties( display
, rootWindow
, &window_name
, &window_name
,
408 argv
, argc
, size_hints
, wm_hints
, class_hints
);
411 XFree( class_hints
);
415 XMapWindow( display
, rootWindow
);
419 XKeyboardState keyboard_state
;
421 /***********************************************************************
424 static void MAIN_SaveSetup(void)
426 XGetKeyboardControl(display
, &keyboard_state
);
429 /***********************************************************************
432 static void MAIN_RestoreSetup(void)
434 XKeyboardControl keyboard_value
;
436 keyboard_value
.key_click_percent
= keyboard_state
.key_click_percent
;
437 keyboard_value
.bell_percent
= keyboard_state
.bell_percent
;
438 keyboard_value
.bell_pitch
= keyboard_state
.bell_pitch
;
439 keyboard_value
.bell_duration
= keyboard_state
.bell_duration
;
440 keyboard_value
.auto_repeat_mode
= keyboard_state
.global_auto_repeat
;
442 XChangeKeyboardControl(display
, KBKeyClickPercent
| KBBellPercent
|
443 KBBellPitch
| KBBellDuration
| KBAutoRepeatMode
, &keyboard_value
);
446 static void called_at_exit(void)
455 /***********************************************************************
458 int main( int argc
, char *argv
[] )
464 setlocale(LC_CTYPE
,"");
468 MAIN_ParseOptions( &argc
, argv
);
470 screen
= DefaultScreenOfDisplay( display
);
471 screenWidth
= WidthOfScreen( screen
);
472 screenHeight
= HeightOfScreen( screen
);
473 if (screenDepth
) /* -depth option specified */
475 depth_list
= XListDepths(display
,DefaultScreen(display
),&depth_count
);
476 for (i
= 0; i
< depth_count
; i
++)
477 if (depth_list
[i
] == screenDepth
) break;
479 if (i
>= depth_count
)
481 fprintf( stderr
, "%s: Depth %d not supported on this screen.\n",
482 Options
.programName
, screenDepth
);
486 else screenDepth
= DefaultDepthOfScreen( screen
);
487 if (Options
.synchronous
) XSynchronize( display
, True
);
488 if (Options
.desktopGeometry
) MAIN_CreateDesktop( argc
, argv
);
489 else rootWindow
= DefaultRootWindow( display
);
499 atexit(called_at_exit
);
501 on_exit (called_at_exit
, 0);
504 ret_val
= _WinMain( argc
, argv
);
509 /***********************************************************************
510 * MessageBeep (USER.104)
512 void MessageBeep(WORD i
)
517 /***********************************************************************
518 * GetVersion (KERNEL.3)
520 LONG
GetVersion(void)
522 return( 0x03300a03 ); /* dos 3.30 & win 3.10 */
525 /***********************************************************************
526 * GetWinFlags (KERNEL.132)
528 LONG
GetWinFlags(void)
530 return (WF_STANDARD
| WF_CPU286
| WF_PMODE
| WF_80x87
);
533 /***********************************************************************
534 * SetEnvironment (GDI.132)
536 int SetEnvironment(LPSTR lpPortName
, LPSTR lpEnviron
, WORD nCount
)
539 LPENVENTRY lpEnv
= lpEnvList
;
540 printf("SetEnvironnement('%s', '%s', %d) !\n",
541 lpPortName
, lpEnviron
, nCount
);
542 if (lpPortName
== NULL
) return -1;
543 while (lpEnv
!= NULL
) {
544 if (lpEnv
->Name
!= NULL
&& strcmp(lpEnv
->Name
, lpPortName
) == 0) {
545 if (nCount
== 0 || lpEnviron
== NULL
) {
546 if (lpEnv
->Prev
!= NULL
) lpEnv
->Prev
->Next
= lpEnv
->Next
;
547 if (lpEnv
->Next
!= NULL
) lpEnv
->Next
->Prev
= lpEnv
->Prev
;
551 printf("SetEnvironnement() // entry deleted !\n");
555 lpEnv
->Value
= malloc(nCount
);
556 if (lpNewEnv
->Value
== NULL
) {
557 printf("SetEnvironment() // Error allocating entry value !\n");
560 memcpy(lpEnv
->Value
, lpEnviron
, nCount
);
561 lpEnv
->wSize
= nCount
;
562 printf("SetEnvironnement() // entry modified !\n");
565 if (lpEnv
->Next
== NULL
) break;
568 if (nCount
== 0 || lpEnviron
== NULL
) return -1;
569 printf("SetEnvironnement() // new entry !\n");
570 lpNewEnv
= malloc(sizeof(ENVENTRY
));
571 if (lpNewEnv
== NULL
) {
572 printf("SetEnvironment() // Error allocating new entry !\n");
575 if (lpEnvList
== NULL
) {
576 lpEnvList
= lpNewEnv
;
577 lpNewEnv
->Prev
= NULL
;
580 lpEnv
->Next
= lpNewEnv
;
581 lpNewEnv
->Prev
= lpEnv
;
583 lpNewEnv
->Next
= NULL
;
584 lpNewEnv
->Name
= malloc(strlen(lpPortName
) + 1);
585 if (lpNewEnv
->Name
== NULL
) {
586 printf("SetEnvironment() // Error allocating entry name !\n");
589 strcpy(lpNewEnv
->Name
, lpPortName
);
590 lpNewEnv
->Value
= malloc(nCount
);
591 if (lpNewEnv
->Value
== NULL
) {
592 printf("SetEnvironment() // Error allocating entry value !\n");
595 memcpy(lpNewEnv
->Value
, lpEnviron
, nCount
);
596 lpNewEnv
->wSize
= nCount
;
600 /***********************************************************************
601 * GetEnvironment (GDI.134)
603 int GetEnvironment(LPSTR lpPortName
, LPSTR lpEnviron
, WORD nMaxSiz
)
606 LPENVENTRY lpEnv
= lpEnvList
;
607 printf("GetEnvironnement('%s', '%s', %d) !\n",
608 lpPortName
, lpEnviron
, nMaxSiz
);
609 while (lpEnv
!= NULL
) {
610 if (lpEnv
->Name
!= NULL
&& strcmp(lpEnv
->Name
, lpPortName
) == 0) {
611 nCount
= min(nMaxSiz
, lpEnv
->wSize
);
612 memcpy(lpEnviron
, lpEnv
->Value
, nCount
);
613 printf("GetEnvironnement() // found '%s' !\n", lpEnviron
);
618 printf("GetEnvironnement() // not found !\n");
622 /***********************************************************************
623 * GetTimerResolution (USER.14)
625 LONG
GetTimerResolution(void)
630 /***********************************************************************
631 * SystemParametersInfo (USER.483)
633 BOOL
SystemParametersInfo (UINT uAction
, UINT uParam
, void FAR
*lpvParam
, UINT fuWinIni
)
637 XKeyboardState keyboard_state
;
638 XKeyboardControl keyboard_value
;
641 fprintf(stderr
, "SystemParametersInfo: action %d, param %x, flag %x\n",
642 uAction
, uParam
, fuWinIni
);
646 XGetKeyboardControl(display
, &keyboard_state
);
647 if (keyboard_state
.bell_percent
== 0)
648 *(BOOL
*) lpvParam
= FALSE
;
650 *(BOOL
*) lpvParam
= TRUE
;
654 *(INT
*) lpvParam
= 1;
657 case SPI_GETFASTTASKSWITCH
:
658 *(BOOL
*) lpvParam
= FALSE
;
661 case SPI_GETGRIDGRANULARITY
:
662 *(INT
*) lpvParam
= 1;
665 case SPI_GETICONTITLEWRAP
:
666 *(BOOL
*) lpvParam
= FALSE
;
669 case SPI_GETKEYBOARDDELAY
:
670 *(INT
*) lpvParam
= 1;
673 case SPI_GETKEYBOARDSPEED
:
674 *(WORD
*) lpvParam
= 30;
677 case SPI_GETMENUDROPALIGNMENT
:
678 *(BOOL
*) lpvParam
= FALSE
;
681 case SPI_GETSCREENSAVEACTIVE
:
682 *(BOOL
*) lpvParam
= FALSE
;
685 case SPI_GETSCREENSAVETIMEOUT
:
686 XGetScreenSaver(display
, &timeout
, &temp
,&temp
,&temp
);
687 *(INT
*) lpvParam
= timeout
* 1000;
690 case SPI_ICONHORIZONTALSPACING
:
691 if (lpvParam
== NULL
)
692 fprintf(stderr
, "SystemParametersInfo: Horizontal icon spacing set to %d\n.", uParam
);
694 *(INT
*) lpvParam
= 50;
697 case SPI_ICONVERTICALSPACING
:
698 if (lpvParam
== NULL
)
699 fprintf(stderr
, "SystemParametersInfo: Vertical icon spacing set to %d\n.", uParam
);
701 *(INT
*) lpvParam
= 50;
706 keyboard_value
.bell_percent
= -1;
708 keyboard_value
.bell_percent
= 0;
709 XChangeKeyboardControl(display
, KBBellPercent
,
713 case SPI_SETSCREENSAVEACTIVE
:
715 XActivateScreenSaver(display
);
717 XResetScreenSaver(display
);
720 case SPI_SETSCREENSAVETIMEOUT
:
721 XSetScreenSaver(display
, uParam
, 60, DefaultBlanking
,
725 case SPI_SETDESKWALLPAPER
:
726 return (SetDeskWallPaper((LPSTR
) lpvParam
));
729 case SPI_SETDESKPATTERN
:
730 if ((INT
) uParam
== -1) {
731 GetProfileString("Desktop", "Pattern",
732 "170 85 170 85 170 85 170 85",
733 buffer
, sizeof(buffer
) );
734 return (DESKTOP_SetPattern((LPSTR
) buffer
));
736 return (DESKTOP_SetPattern((LPSTR
) lpvParam
));
741 case SPI_SETDOUBLECLKHEIGHT
:
742 case SPI_SETDOUBLECLICKTIME
:
743 case SPI_SETDOUBLECLKWIDTH
:
744 case SPI_SETFASTTASKSWITCH
:
745 case SPI_SETKEYBOARDDELAY
:
746 case SPI_SETKEYBOARDSPEED
:
747 fprintf(stderr
, "SystemParametersInfo: option %d ignored.\n", uParam
);
751 fprintf(stderr
, "SystemParametersInfo: unknown option %d.\n", uParam
);
757 /***********************************************************************
758 * HMEMCPY (KERNEL.348)
760 void hmemcpy(void FAR
*hpvDest
, const void FAR
*hpvSource
, long cbCopy
)
762 memcpy(hpvDest
, hpvSource
, cbCopy
);
765 /***********************************************************************
768 void Copy(LPVOID lpSource
, LPVOID lpDest
, WORD nBytes
)
770 memcpy(lpDest
, lpSource
, nBytes
);
773 /***********************************************************************
774 * SWAPMOUSEBUTTON (USER.186)
776 BOOL
SwapMouseButton(BOOL fSwap
)
778 return 0; /* don't swap */
781 /***********************************************************************
782 * ISROMMODULE (KERNEL.323)
784 BOOL
IsRomModule(HANDLE x
)
786 /* I don't know the prototype, I assume that it returns true
787 if the dll is located in rom */
792 /***********************************************************************
793 * FileCDR (KERNEL.130)
795 void FileCDR(FARPROC x
)
797 printf("FileCDR(%8x)\n", (int) x
);