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
);
498 atexit(called_at_exit
);
500 on_exit (called_at_exit
, 0);
503 ret_val
= _WinMain( argc
, argv
);
508 /***********************************************************************
509 * MessageBeep (USER.104)
511 void MessageBeep(WORD i
)
516 /***********************************************************************
517 * GetVersion (KERNEL.3)
519 LONG
GetVersion(void)
521 return( 0x03300a03 ); /* dos 3.30 & win 3.10 */
524 /***********************************************************************
525 * GetWinFlags (KERNEL.132)
527 LONG
GetWinFlags(void)
529 return (WF_STANDARD
| WF_CPU286
| WF_PMODE
| WF_80x87
);
532 /***********************************************************************
533 * SetEnvironment (GDI.132)
535 int SetEnvironment(LPSTR lpPortName
, LPSTR lpEnviron
, WORD nCount
)
538 LPENVENTRY lpEnv
= lpEnvList
;
539 printf("SetEnvironnement('%s', '%s', %d) !\n",
540 lpPortName
, lpEnviron
, nCount
);
541 if (lpPortName
== NULL
) return -1;
542 while (lpEnv
!= NULL
) {
543 if (lpEnv
->Name
!= NULL
&& strcmp(lpEnv
->Name
, lpPortName
) == 0) {
544 if (nCount
== 0 || lpEnviron
== NULL
) {
545 if (lpEnv
->Prev
!= NULL
) lpEnv
->Prev
->Next
= lpEnv
->Next
;
546 if (lpEnv
->Next
!= NULL
) lpEnv
->Next
->Prev
= lpEnv
->Prev
;
550 printf("SetEnvironnement() // entry deleted !\n");
554 lpEnv
->Value
= malloc(nCount
);
555 if (lpEnv
->Value
== NULL
) {
556 printf("SetEnvironment() // Error allocating entry value !\n");
559 memcpy(lpEnv
->Value
, lpEnviron
, nCount
);
560 lpEnv
->wSize
= nCount
;
561 printf("SetEnvironnement() // entry modified !\n");
564 if (lpEnv
->Next
== NULL
) break;
567 if (nCount
== 0 || lpEnviron
== NULL
) return -1;
568 printf("SetEnvironnement() // new entry !\n");
569 lpNewEnv
= malloc(sizeof(ENVENTRY
));
570 if (lpNewEnv
== NULL
) {
571 printf("SetEnvironment() // Error allocating new entry !\n");
574 if (lpEnvList
== NULL
) {
575 lpEnvList
= lpNewEnv
;
576 lpNewEnv
->Prev
= NULL
;
579 lpEnv
->Next
= lpNewEnv
;
580 lpNewEnv
->Prev
= lpEnv
;
582 lpNewEnv
->Next
= NULL
;
583 lpNewEnv
->Name
= malloc(strlen(lpPortName
) + 1);
584 if (lpNewEnv
->Name
== NULL
) {
585 printf("SetEnvironment() // Error allocating entry name !\n");
588 strcpy(lpNewEnv
->Name
, lpPortName
);
589 lpNewEnv
->Value
= malloc(nCount
);
590 if (lpNewEnv
->Value
== NULL
) {
591 printf("SetEnvironment() // Error allocating entry value !\n");
594 memcpy(lpNewEnv
->Value
, lpEnviron
, nCount
);
595 lpNewEnv
->wSize
= nCount
;
599 /***********************************************************************
600 * GetEnvironment (GDI.134)
602 int GetEnvironment(LPSTR lpPortName
, LPSTR lpEnviron
, WORD nMaxSiz
)
605 LPENVENTRY lpEnv
= lpEnvList
;
606 printf("GetEnvironnement('%s', '%s', %d) !\n",
607 lpPortName
, lpEnviron
, nMaxSiz
);
608 while (lpEnv
!= NULL
) {
609 if (lpEnv
->Name
!= NULL
&& strcmp(lpEnv
->Name
, lpPortName
) == 0) {
610 nCount
= min(nMaxSiz
, lpEnv
->wSize
);
611 memcpy(lpEnviron
, lpEnv
->Value
, nCount
);
612 printf("GetEnvironnement() // found '%s' !\n", lpEnviron
);
617 printf("GetEnvironnement() // not found !\n");
621 /***********************************************************************
622 * GetTimerResolution (USER.14)
624 LONG
GetTimerResolution(void)
629 /***********************************************************************
630 * SystemParametersInfo (USER.483)
632 BOOL
SystemParametersInfo (UINT uAction
, UINT uParam
, void FAR
*lpvParam
, UINT fuWinIni
)
636 XKeyboardState keyboard_state
;
637 XKeyboardControl keyboard_value
;
640 fprintf(stderr
, "SystemParametersInfo: action %d, param %x, flag %x\n",
641 uAction
, uParam
, fuWinIni
);
645 XGetKeyboardControl(display
, &keyboard_state
);
646 if (keyboard_state
.bell_percent
== 0)
647 *(BOOL
*) lpvParam
= FALSE
;
649 *(BOOL
*) lpvParam
= TRUE
;
653 *(INT
*) lpvParam
= 1;
656 case SPI_GETFASTTASKSWITCH
:
657 *(BOOL
*) lpvParam
= FALSE
;
660 case SPI_GETGRIDGRANULARITY
:
661 *(INT
*) lpvParam
= 1;
664 case SPI_GETICONTITLEWRAP
:
665 *(BOOL
*) lpvParam
= FALSE
;
668 case SPI_GETKEYBOARDDELAY
:
669 *(INT
*) lpvParam
= 1;
672 case SPI_GETKEYBOARDSPEED
:
673 *(WORD
*) lpvParam
= 30;
676 case SPI_GETMENUDROPALIGNMENT
:
677 *(BOOL
*) lpvParam
= FALSE
;
680 case SPI_GETSCREENSAVEACTIVE
:
681 *(BOOL
*) lpvParam
= FALSE
;
684 case SPI_GETSCREENSAVETIMEOUT
:
685 XGetScreenSaver(display
, &timeout
, &temp
,&temp
,&temp
);
686 *(INT
*) lpvParam
= timeout
* 1000;
689 case SPI_ICONHORIZONTALSPACING
:
690 if (lpvParam
== NULL
)
691 fprintf(stderr
, "SystemParametersInfo: Horizontal icon spacing set to %d\n.", uParam
);
693 *(INT
*) lpvParam
= 50;
696 case SPI_ICONVERTICALSPACING
:
697 if (lpvParam
== NULL
)
698 fprintf(stderr
, "SystemParametersInfo: Vertical icon spacing set to %d\n.", uParam
);
700 *(INT
*) lpvParam
= 50;
705 keyboard_value
.bell_percent
= -1;
707 keyboard_value
.bell_percent
= 0;
708 XChangeKeyboardControl(display
, KBBellPercent
,
712 case SPI_SETSCREENSAVEACTIVE
:
714 XActivateScreenSaver(display
);
716 XResetScreenSaver(display
);
719 case SPI_SETSCREENSAVETIMEOUT
:
720 XSetScreenSaver(display
, uParam
, 60, DefaultBlanking
,
724 case SPI_SETDESKWALLPAPER
:
725 return (SetDeskWallPaper((LPSTR
) lpvParam
));
728 case SPI_SETDESKPATTERN
:
729 if ((INT
) uParam
== -1) {
730 GetProfileString("Desktop", "Pattern",
731 "170 85 170 85 170 85 170 85",
732 buffer
, sizeof(buffer
) );
733 return (DESKTOP_SetPattern((LPSTR
) buffer
));
735 return (DESKTOP_SetPattern((LPSTR
) lpvParam
));
740 case SPI_SETDOUBLECLKHEIGHT
:
741 case SPI_SETDOUBLECLICKTIME
:
742 case SPI_SETDOUBLECLKWIDTH
:
743 case SPI_SETFASTTASKSWITCH
:
744 case SPI_SETKEYBOARDDELAY
:
745 case SPI_SETKEYBOARDSPEED
:
746 fprintf(stderr
, "SystemParametersInfo: option %d ignored.\n", uParam
);
750 fprintf(stderr
, "SystemParametersInfo: unknown option %d.\n", uParam
);
756 /***********************************************************************
757 * HMEMCPY (KERNEL.348)
759 void hmemcpy(void FAR
*hpvDest
, const void FAR
*hpvSource
, long cbCopy
)
761 memcpy(hpvDest
, hpvSource
, cbCopy
);
764 /***********************************************************************
767 void Copy(LPVOID lpSource
, LPVOID lpDest
, WORD nBytes
)
769 memcpy(lpDest
, lpSource
, nBytes
);
772 /***********************************************************************
773 * SWAPMOUSEBUTTON (USER.186)
775 BOOL
SwapMouseButton(BOOL fSwap
)
777 return 0; /* don't swap */
780 /***********************************************************************
781 * ISROMMODULE (KERNEL.323)
783 BOOL
IsRomModule(HANDLE x
)
785 /* I don't know the prototype, I assume that it returns true
786 if the dll is located in rom */
791 /***********************************************************************
792 * FileCDR (KERNEL.130)
794 void FileCDR(FARPROC x
)
796 printf("FileCDR(%8x)\n", (int) x
);