]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
end label edit patch from Ricky Gonzales <gonzales@pyramid3.net>
[wxWidgets.git] / src / unix / utilsunx.cpp
CommitLineData
518b5d2f
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: utilsunx.cpp
3// Purpose: generic Unix implementation of many wx functions
4// Author: Vadim Zeitlin
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/defs.h"
19#include "wx/string.h"
20
21#include "wx/intl.h"
22#include "wx/log.h"
23
24#include "wx/utils.h"
25#include "wx/process.h"
26
27#include "wx/unix/execute.h"
28
29#include <stdarg.h>
30#include <dirent.h>
31#include <string.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <unistd.h>
35#include <sys/wait.h>
36#include <pwd.h>
37#include <errno.h>
38#include <netdb.h>
39#include <signal.h>
40#include <fcntl.h> // for O_WRONLY and friends
41#include <time.h> // nanosleep() and/or usleep()
fad866f4 42#include <ctype.h> // isspace()
0ed9a934 43
7bcb11d3
JS
44// JACS: needed for FD_SETSIZE
45#include <sys/time.h>
46
47#if HAVE_UNAME
518b5d2f
VZ
48 #include <sys/utsname.h> // for uname()
49#endif // HAVE_UNAME
50
51// ----------------------------------------------------------------------------
52// conditional compilation
53// ----------------------------------------------------------------------------
54
55// many versions of Unices have this function, but it is not defined in system
56// headers - please add your system here if it is the case for your OS.
57// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
1363811b
VZ
58#if !defined(HAVE_USLEEP) && \
59 (defined(__SUN__) && !defined(__SunOs_5_6) && \
518b5d2f 60 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
fd9811b1 61 defined(__osf__) || defined(__EMX__)
518b5d2f
VZ
62 extern "C"
63 {
1363811b
VZ
64 #ifdef __SUN__
65 int usleep(unsigned int usec);
66 #else // !Sun
e90c1d2a 67 #ifdef __EMX
e6daf794
RR
68 /* I copied this from the XFree86 diffs. AV. */
69 #define INCL_DOSPROCESS
70 #include <os2.h>
71 void usleep(unsigned long delay)
72 {
73 DosSleep(delay ? (delay/1000l) : 1l);
74 }
e90c1d2a
VZ
75 #else
76 void usleep(unsigned long usec);
77 #endif
e6daf794 78 #endif // Sun/EMX/Something else
518b5d2f 79 };
e6daf794 80#define HAVE_USLEEP 1
518b5d2f
VZ
81#endif // Unices without usleep()
82
518b5d2f
VZ
83// ============================================================================
84// implementation
85// ============================================================================
86
87// ----------------------------------------------------------------------------
88// sleeping
89// ----------------------------------------------------------------------------
90
91void wxSleep(int nSecs)
92{
93 sleep(nSecs);
94}
95
96void wxUsleep(unsigned long milliseconds)
97{
7bcb11d3 98#if HAVE_NANOSLEEP
518b5d2f
VZ
99 timespec tmReq;
100 tmReq.tv_sec = milliseconds / 1000;
101 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
102
103 // we're not interested in remaining time nor in return value
104 (void)nanosleep(&tmReq, (timespec *)NULL);
7bcb11d3 105#elif HAVE_USLEEP
518b5d2f
VZ
106 // uncomment this if you feel brave or if you are sure that your version
107 // of Solaris has a safe usleep() function but please notice that usleep()
108 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
109 // documented as MT-Safe
ea18eed9 110 #if defined(__SUN__) && wxUSE_THREADS
518b5d2f
VZ
111 #error "usleep() cannot be used in MT programs under Solaris."
112 #endif // Sun
113
114 usleep(milliseconds * 1000); // usleep(3) wants microseconds
115#else // !sleep function
116 #error "usleep() or nanosleep() function required for wxUsleep"
117#endif // sleep function
118}
119
120// ----------------------------------------------------------------------------
121// process management
122// ----------------------------------------------------------------------------
123
0fb67cd1 124int wxKill(long pid, wxSignal sig)
518b5d2f 125{
0fb67cd1 126 return kill(pid, (int)sig);
518b5d2f
VZ
127}
128
fad866f4
KB
129#define WXEXECUTE_NARGS 127
130
518b5d2f
VZ
131long wxExecute( const wxString& command, bool sync, wxProcess *process )
132{
223d09f6 133 wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
518b5d2f
VZ
134
135 int argc = 0;
05079acc 136 wxChar *argv[WXEXECUTE_NARGS];
fad866f4 137 wxString argument;
05079acc 138 const wxChar *cptr = command.c_str();
223d09f6 139 wxChar quotechar = wxT('\0'); // is arg quoted?
fad866f4 140 bool escaped = FALSE;
518b5d2f 141
0ed9a934 142 // split the command line in arguments
fad866f4
KB
143 do
144 {
223d09f6
KB
145 argument=wxT("");
146 quotechar = wxT('\0');
0ed9a934 147
fad866f4 148 // eat leading whitespace:
05079acc 149 while ( wxIsspace(*cptr) )
fad866f4 150 cptr++;
0ed9a934 151
223d09f6 152 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
fad866f4 153 quotechar = *cptr++;
0ed9a934 154
fad866f4
KB
155 do
156 {
223d09f6 157 if ( *cptr == wxT('\\') && ! escaped )
fad866f4
KB
158 {
159 escaped = TRUE;
160 cptr++;
161 continue;
162 }
0ed9a934 163
fad866f4 164 // all other characters:
0ed9a934 165 argument += *cptr++;
fad866f4 166 escaped = FALSE;
0ed9a934
VZ
167
168 // have we reached the end of the argument?
169 if ( (*cptr == quotechar && ! escaped)
223d09f6
KB
170 || (quotechar == wxT('\0') && wxIsspace(*cptr))
171 || *cptr == wxT('\0') )
fad866f4 172 {
0ed9a934 173 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
223d09f6 174 wxT("too many arguments in wxExecute") );
0ed9a934 175
05079acc
OK
176 argv[argc] = new wxChar[argument.length() + 1];
177 wxStrcpy(argv[argc], argument.c_str());
fad866f4 178 argc++;
0ed9a934 179
fad866f4 180 // if not at end of buffer, swallow last character:
0ed9a934
VZ
181 if(*cptr)
182 cptr++;
183
fad866f4
KB
184 break; // done with this one, start over
185 }
0ed9a934
VZ
186 } while(*cptr);
187 } while(*cptr);
fad866f4 188 argv[argc] = NULL;
0ed9a934
VZ
189
190 // do execute the command
518b5d2f
VZ
191 long lRc = wxExecute(argv, sync, process);
192
0ed9a934 193 // clean up
fad866f4 194 argc = 0;
0ed9a934 195 while( argv[argc] )
fad866f4 196 delete [] argv[argc++];
518b5d2f
VZ
197
198 return lRc;
199}
200
201bool wxShell(const wxString& command)
202{
203 wxString cmd;
204 if ( !!command )
223d09f6 205 cmd.Printf(wxT("xterm -e %s"), command.c_str());
518b5d2f
VZ
206 else
207 cmd = command;
208
209 return wxExecute(cmd) != 0;
210}
211
212void wxHandleProcessTermination(wxEndProcessData *proc_data)
213{
214 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
215
0ed9a934
VZ
216 // waitpid is POSIX so should be available everywhere, however on older
217 // systems wait() might be used instead in a loop (until the right pid
218 // terminates)
518b5d2f 219 int status = 0;
0ed9a934
VZ
220 if ( waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) )
221 {
222 wxLogSysError(_("Waiting for subprocess termination failed"));
223 }
224 else
225 {
226 // notify user about termination if required
227 if (proc_data->process)
228 {
229 proc_data->process->OnTerminate(proc_data->pid,
230 WEXITSTATUS(status));
231 }
232 }
518b5d2f 233
0ed9a934
VZ
234 // clean up
235 if ( proc_data->pid > 0 )
518b5d2f
VZ
236 {
237 delete proc_data;
238 }
239 else
240 {
241 // wxExecute() will know about it
242 proc_data->exitcode = status;
243
244 proc_data->pid = 0;
245 }
246}
247
05079acc 248long wxExecute( wxChar **argv, bool sync, wxProcess *process )
518b5d2f 249{
223d09f6 250 wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
518b5d2f 251
05079acc
OK
252#if wxUSE_UNICODE
253 int mb_argc = 0;
254 char *mb_argv[WXEXECUTE_NARGS];
255
e90c1d2a
VZ
256 while (argv[mb_argc])
257 {
258 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
05079acc
OK
259 mb_argv[mb_argc] = strdup(mb_arg);
260 mb_argc++;
261 }
262 mb_argv[mb_argc] = (char *) NULL;
e90c1d2a
VZ
263
264 // this macro will free memory we used above
265 #define ARGS_CLEANUP \
345b0247 266 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
e90c1d2a
VZ
267 free(mb_argv[mb_argc])
268#else // ANSI
269 // no need for cleanup
270 #define ARGS_CLEANUP
271
05079acc 272 wxChar **mb_argv = argv;
e90c1d2a 273#endif // Unicode/ANSI
518b5d2f 274
e90c1d2a 275#if wxUSE_GUI
518b5d2f 276 // create pipes
e90c1d2a 277 int end_proc_detect[2];
518b5d2f
VZ
278 if (pipe(end_proc_detect) == -1)
279 {
280 wxLogSysError( _("Pipe creation failed") );
e90c1d2a
VZ
281
282 ARGS_CLEANUP;
283
518b5d2f
VZ
284 return 0;
285 }
e90c1d2a 286#endif // wxUSE_GUI
518b5d2f
VZ
287
288 // fork the process
01bc089c 289#if HAVE_VFORK
518b5d2f
VZ
290 pid_t pid = vfork();
291#else
292 pid_t pid = fork();
293#endif
294 if (pid == -1)
295 {
296 wxLogSysError( _("Fork failed") );
e90c1d2a
VZ
297
298 ARGS_CLEANUP;
299
518b5d2f
VZ
300 return 0;
301 }
302 else if (pid == 0)
303 {
e90c1d2a 304#if wxUSE_GUI
518b5d2f
VZ
305 // we're in child
306 close(end_proc_detect[0]); // close reading side
e90c1d2a 307#endif // wxUSE_GUI
518b5d2f
VZ
308
309 // These three lines close the open file descriptors to to avoid any
310 // input/output which might block the process or irritate the user. If
d6086ea6 311 // one wants proper IO for the subprocess, the right thing to do is
518b5d2f
VZ
312 // to start an xterm executing it.
313 if (sync == 0)
314 {
315 // leave stderr opened, it won't do any hurm
316 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
317 {
e90c1d2a
VZ
318#if wxUSE_GUI
319 if ( fd == end_proc_detect[1] )
320 continue;
321#endif // wxUSE_GUI
322
323 if ( fd != STDERR_FILENO )
518b5d2f
VZ
324 close(fd);
325 }
326 }
327
328#if 0
329 close(STDERR_FILENO);
330
331 // some programs complain about stderr not being open, so redirect
332 // them:
333 open("/dev/null", O_RDONLY); // stdin
334 open("/dev/null", O_WRONLY); // stdout
335 open("/dev/null", O_WRONLY); // stderr
336#endif
337
05079acc 338 execvp (*mb_argv, mb_argv);
518b5d2f
VZ
339
340 // there is no return after successful exec()
05079acc 341 wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
518b5d2f
VZ
342
343 _exit(-1);
344 }
345 else
346 {
e90c1d2a 347#if wxUSE_GUI
518b5d2f
VZ
348 // we're in parent
349 close(end_proc_detect[1]); // close writing side
350
351 wxEndProcessData *data = new wxEndProcessData;
352 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
353
e90c1d2a 354 ARGS_CLEANUP;
05079acc 355
518b5d2f
VZ
356 if ( sync )
357 {
223d09f6 358 wxASSERT_MSG( !process, wxT("wxProcess param ignored for sync exec") );
518b5d2f
VZ
359 data->process = NULL;
360
361 // sync execution: indicate it by negating the pid
362 data->pid = -pid;
363
364 // it will be set to 0 from GTK_EndProcessDetector
365 while (data->pid != 0)
366 wxYield();
367
368 int exitcode = data->exitcode;
369
370 delete data;
371
372 return exitcode;
373 }
374 else
375 {
376 // async execution, nothing special to do - caller will be
377 // notified about the process terminationif process != NULL, data
378 // will be deleted in GTK_EndProcessDetector
379 data->process = process;
380 data->pid = pid;
381
382 return pid;
383 }
e90c1d2a 384#else // !wxUSE_GUI
223d09f6 385 wxASSERT_MSG( sync, wxT("async execution not supported yet") );
e90c1d2a
VZ
386
387 int exitcode = 0;
388 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
389 {
390 wxLogSysError(_("Waiting for subprocess termination failed"));
391 }
392
393 return exitcode;
394#endif // wxUSE_GUI
518b5d2f 395 }
e90c1d2a
VZ
396
397 #undef ARGS_CLEANUP
518b5d2f
VZ
398}
399
400// ----------------------------------------------------------------------------
401// file and directory functions
402// ----------------------------------------------------------------------------
403
05079acc 404const wxChar* wxGetHomeDir( wxString *home )
518b5d2f
VZ
405{
406 *home = wxGetUserHome( wxString() );
407 if ( home->IsEmpty() )
223d09f6 408 *home = wxT("/");
518b5d2f
VZ
409
410 return home->c_str();
411}
412
05079acc
OK
413#if wxUSE_UNICODE
414const wxMB2WXbuf wxGetUserHome( const wxString &user )
e90c1d2a 415#else // just for binary compatibility -- there is no 'const' here
518b5d2f 416char *wxGetUserHome( const wxString &user )
05079acc 417#endif
518b5d2f
VZ
418{
419 struct passwd *who = (struct passwd *) NULL;
420
0fb67cd1 421 if ( !user )
518b5d2f 422 {
e90c1d2a 423 wxChar *ptr;
518b5d2f 424
223d09f6 425 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
518b5d2f
VZ
426 {
427 return ptr;
428 }
223d09f6 429 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
518b5d2f 430 {
e90c1d2a 431 who = getpwnam(wxConvertWX2MB(ptr));
518b5d2f
VZ
432 }
433
434 // We now make sure the the user exists!
435 if (who == NULL)
436 {
437 who = getpwuid(getuid());
438 }
439 }
440 else
441 {
05079acc 442 who = getpwnam (user.mb_str());
518b5d2f
VZ
443 }
444
af111fc3 445 return wxConvertMB2WX(who ? who->pw_dir : 0);
518b5d2f
VZ
446}
447
448// ----------------------------------------------------------------------------
0fb67cd1 449// network and user id routines
518b5d2f
VZ
450// ----------------------------------------------------------------------------
451
0fb67cd1
VZ
452// retrieve either the hostname or FQDN depending on platform (caller must
453// check whether it's one or the other, this is why this function is for
454// private use only)
05079acc 455static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 456{
223d09f6 457 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
518b5d2f 458
223d09f6 459 *buf = wxT('\0');
518b5d2f
VZ
460
461 // we're using uname() which is POSIX instead of less standard sysinfo()
462#if defined(HAVE_UNAME)
cc743a6f 463 struct utsname uts;
518b5d2f
VZ
464 bool ok = uname(&uts) != -1;
465 if ( ok )
466 {
e90c1d2a 467 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
223d09f6 468 buf[sz] = wxT('\0');
518b5d2f
VZ
469 }
470#elif defined(HAVE_GETHOSTNAME)
471 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 472#else // no uname, no gethostname
223d09f6 473 wxFAIL_MSG(wxT("don't know host name for this machine"));
518b5d2f
VZ
474
475 bool ok = FALSE;
0fb67cd1 476#endif // uname/gethostname
518b5d2f
VZ
477
478 if ( !ok )
479 {
480 wxLogSysError(_("Cannot get the hostname"));
481 }
482
483 return ok;
484}
485
05079acc 486bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
487{
488 bool ok = wxGetHostNameInternal(buf, sz);
489
490 if ( ok )
491 {
492 // BSD systems return the FQDN, we only want the hostname, so extract
493 // it (we consider that dots are domain separators)
223d09f6 494 wxChar *dot = wxStrchr(buf, wxT('.'));
0fb67cd1
VZ
495 if ( dot )
496 {
497 // nuke it
223d09f6 498 *dot = wxT('\0');
0fb67cd1
VZ
499 }
500 }
501
502 return ok;
503}
504
05079acc 505bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
506{
507 bool ok = wxGetHostNameInternal(buf, sz);
508
509 if ( ok )
510 {
223d09f6 511 if ( !wxStrchr(buf, wxT('.')) )
0fb67cd1 512 {
e90c1d2a 513 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
0fb67cd1
VZ
514 if ( !host )
515 {
516 wxLogSysError(_("Cannot get the official hostname"));
517
518 ok = FALSE;
519 }
520 else
521 {
522 // the canonical name
e90c1d2a 523 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
0fb67cd1
VZ
524 }
525 }
526 //else: it's already a FQDN (BSD behaves this way)
527 }
528
529 return ok;
530}
531
05079acc 532bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
533{
534 struct passwd *who;
535
223d09f6 536 *buf = wxT('\0');
518b5d2f
VZ
537 if ((who = getpwuid(getuid ())) != NULL)
538 {
e90c1d2a 539 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
518b5d2f
VZ
540 return TRUE;
541 }
542
543 return FALSE;
544}
545
05079acc 546bool wxGetUserName(wxChar *buf, int sz)
518b5d2f
VZ
547{
548 struct passwd *who;
549 char *comma;
550
223d09f6 551 *buf = wxT('\0');
518b5d2f
VZ
552 if ((who = getpwuid (getuid ())) != NULL) {
553 comma = strchr(who->pw_gecos, ',');
554 if (comma)
555 *comma = '\0'; // cut off non-name comment fields
e90c1d2a 556 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
518b5d2f
VZ
557 return TRUE;
558 }
559
560 return FALSE;
561}
562
e90c1d2a
VZ
563#if wxUSE_GUI
564
518b5d2f
VZ
565// ----------------------------------------------------------------------------
566// error and debug output routines (deprecated, use wxLog)
567// ----------------------------------------------------------------------------
568
569void wxDebugMsg( const char *format, ... )
570{
571 va_list ap;
572 va_start( ap, format );
573 vfprintf( stderr, format, ap );
574 fflush( stderr );
575 va_end(ap);
576}
577
578void wxError( const wxString &msg, const wxString &title )
579{
05079acc 580 wxFprintf( stderr, _("Error ") );
223d09f6
KB
581 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
582 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
583 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
584}
585
586void wxFatalError( const wxString &msg, const wxString &title )
587{
05079acc 588 wxFprintf( stderr, _("Error ") );
223d09f6
KB
589 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
590 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
591 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
592 exit(3); // the same exit code as for abort()
593}
93ccaed8
VZ
594
595// ----------------------------------------------------------------------------
596// font-related functions
597// ----------------------------------------------------------------------------
598
599// define the functions to create and destroy native fonts for this toolkit
600#ifdef __X__
601 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
602 {
603 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
604 }
605
606 static inline void wxFreeFont(wxNativeFont font)
607 {
608 XFreeFont((Display *)wxGetDisplay(), font);
609 }
610#elif defined(__WXGTK__)
e8b04eb3
RR
611
612 #include "gdk/gdk.h"
613
93ccaed8
VZ
614 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
615 {
e90c1d2a 616 return gdk_font_load( wxConvertWX2MB(fontSpec) );
93ccaed8
VZ
617 }
618
619 static inline void wxFreeFont(wxNativeFont font)
620 {
621 gdk_font_unref(font);
622 }
623#else
624 #error "Unknown GUI toolkit"
625#endif
626
627// returns TRUE if there are any fonts matching this font spec
628static bool wxTestFontSpec(const wxString& fontspec)
629{
630 wxNativeFont test = wxLoadFont(fontspec);
631 if ( test )
632 {
633 wxFreeFont(test);
634
635 return TRUE;
636 }
637 else
638 {
639 return FALSE;
640 }
641}
642
643// TODO encoding test logic should be moved to wxLoadQueryNearestFont()
644static wxNativeFont wxLoadQueryFont(int pointSize,
645 int family,
646 int style,
647 int weight,
648 bool WXUNUSED(underlined),
649 const wxString &facename,
650 wxFontEncoding encoding )
651{
652 wxString xfamily;
653 switch (family)
654 {
223d09f6
KB
655 case wxDECORATIVE: xfamily = wxT("lucida"); break;
656 case wxROMAN: xfamily = wxT("times"); break;
657 case wxMODERN: xfamily = wxT("courier"); break;
658 case wxSWISS: xfamily = wxT("helvetica"); break;
659 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
660 case wxSCRIPT: xfamily = wxT("utopia"); break;
661 default: xfamily = wxT("*");
93ccaed8
VZ
662 }
663
664 wxString fontSpec;
665 if (!facename.IsEmpty())
666 {
223d09f6 667 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
93ccaed8
VZ
668 facename.c_str());
669
670 if ( wxTestFontSpec(fontSpec) )
671 {
672 xfamily = facename;
673 }
674 //else: no such family, use default one instead
675 }
676
677 wxString xstyle;
678 switch (style)
679 {
223d09f6
KB
680 case wxITALIC: xstyle = wxT("i"); break;
681 case wxSLANT: xstyle = wxT("o"); break;
682 case wxNORMAL: xstyle = wxT("r"); break;
683 default: xstyle = wxT("*"); break;
93ccaed8
VZ
684 }
685
686 wxString xweight;
687 switch (weight)
688 {
30760ce7
RR
689 case wxBOLD:
690 {
691 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
692 xfamily.c_str());
693 if ( wxTestFontSpec(fontSpec) )
694 {
695 xweight = wxT("bold");
696 break;
697 }
698 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
699 xfamily.c_str());
700 if ( wxTestFontSpec(fontSpec) )
701 {
702 xweight = wxT("heavy");
703 break;
704 }
705 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
706 xfamily.c_str());
707 if ( wxTestFontSpec(fontSpec) )
708 {
709 xweight = wxT("extrabold");
710 break;
711 }
712 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
713 xfamily.c_str());
714 if ( wxTestFontSpec(fontSpec) )
715 {
716 xweight = wxT("demibold");
717 break;
718 }
719 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
720 xfamily.c_str());
721 if ( wxTestFontSpec(fontSpec) )
722 {
723 xweight = wxT("black");
724 break;
725 }
726 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
727 xfamily.c_str());
728 if ( wxTestFontSpec(fontSpec) )
729 {
730 xweight = wxT("ultrablack");
731 break;
732 }
733 }
734 break;
93ccaed8 735 case wxLIGHT:
30760ce7
RR
736 {
737 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
738 xfamily.c_str());
739 if ( wxTestFontSpec(fontSpec) )
740 {
741 xweight = wxT("light");
742 break;
743 }
744 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
745 xfamily.c_str());
746 if ( wxTestFontSpec(fontSpec) )
747 {
748 xweight = wxT("thin");
749 break;
750 }
751 }
752 break;
753 case wxNORMAL:
754 {
755 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
756 xfamily.c_str());
757 if ( wxTestFontSpec(fontSpec) )
758 {
759 xweight = wxT("medium");
760 break;
761 }
762 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
763 xfamily.c_str());
764 if ( wxTestFontSpec(fontSpec) )
765 {
766 xweight = wxT("normal");
767 break;
768 }
769 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
770 xfamily.c_str());
771 if ( wxTestFontSpec(fontSpec) )
772 {
773 xweight = wxT("regular");
774 break;
775 }
776 xweight = wxT("*");
777 }
778 break;
223d09f6 779 default: xweight = wxT("*"); break;
93ccaed8
VZ
780 }
781
782 wxString xregistry, xencoding;
36f210c8
VZ
783 if ( !wxGetXFontEncoding(encoding, &xregistry, &xencoding) )
784 {
785 fontSpec.Printf(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-%s-%s"),
786 xregistry.c_str(), xencoding.c_str());
787 if ( !wxTestFontSpec(fontSpec) )
788 {
789 // this encoding isn't available - what to do?
790 xregistry =
791 xencoding = wxT("*");
792 }
793 }
794
795 // construct the X font spec from our data
796 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
797 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
798 pointSize, xregistry.c_str(), xencoding.c_str());
799
800 return wxLoadFont(fontSpec);
801}
802
803bool wxGetXFontEncoding(wxFontEncoding encoding,
804 wxString *pregistry, wxString *pencoding)
805{
806 wxCHECK_MSG( pencoding && pregistry, FALSE, wxT("bad pointer") );
807
808 wxString& xencoding = *pencoding;
809 wxString& xregistry = *pregistry;
810
93ccaed8
VZ
811 if ( encoding == wxFONTENCODING_DEFAULT )
812 {
813 // use the apps default
814 encoding = wxFont::GetDefaultEncoding();
815 }
816
817 bool test = TRUE; // should we test for availability of encoding?
818 switch ( encoding )
819 {
820 case wxFONTENCODING_ISO8859_1:
821 case wxFONTENCODING_ISO8859_2:
822 case wxFONTENCODING_ISO8859_3:
823 case wxFONTENCODING_ISO8859_4:
824 case wxFONTENCODING_ISO8859_5:
825 case wxFONTENCODING_ISO8859_6:
826 case wxFONTENCODING_ISO8859_7:
827 case wxFONTENCODING_ISO8859_8:
828 case wxFONTENCODING_ISO8859_9:
829 case wxFONTENCODING_ISO8859_10:
830 case wxFONTENCODING_ISO8859_11:
831 case wxFONTENCODING_ISO8859_13:
832 case wxFONTENCODING_ISO8859_14:
833 case wxFONTENCODING_ISO8859_15:
834 {
835 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
223d09f6
KB
836 xregistry = wxT("iso8859");
837 xencoding.Printf(wxT("%d"), cp);
93ccaed8
VZ
838 }
839 break;
840
841 case wxFONTENCODING_KOI8:
223d09f6
KB
842 xregistry = wxT("koi8");
843 if ( wxTestFontSpec(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-koi8-1")) )
93ccaed8 844 {
223d09f6 845 xencoding = wxT("1");
93ccaed8
VZ
846
847 // test passed, no need to do it once more
848 test = FALSE;
849 }
850 else
851 {
223d09f6 852 xencoding = wxT("*");
93ccaed8
VZ
853 }
854 break;
855
856 case wxFONTENCODING_CP1250:
857 case wxFONTENCODING_CP1251:
858 case wxFONTENCODING_CP1252:
859 {
860 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
36f210c8 861 wxString fontSpec;
223d09f6 862 fontSpec.Printf(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-microsoft-cp%d"),
93ccaed8
VZ
863 cp);
864 if ( wxTestFontSpec(fontSpec) )
865 {
223d09f6
KB
866 xregistry = wxT("microsoft");
867 xencoding.Printf(wxT("cp%d"), cp);
93ccaed8
VZ
868
869 // test passed, no need to do it once more
870 test = FALSE;
871 }
872 else
873 {
874 // fall back to LatinX
223d09f6
KB
875 xregistry = wxT("iso8859");
876 xencoding.Printf(wxT("%d"), cp - 1249);
93ccaed8
VZ
877 }
878 }
879 break;
880
881 case wxFONTENCODING_SYSTEM:
882 default:
883 test = FALSE;
884 xregistry =
223d09f6 885 xencoding = wxT("*");
93ccaed8
VZ
886 }
887
36f210c8 888 return !test;
93ccaed8
VZ
889}
890
891wxNativeFont wxLoadQueryNearestFont(int pointSize,
892 int family,
893 int style,
894 int weight,
895 bool underlined,
896 const wxString &facename,
897 wxFontEncoding encoding)
898{
899 wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
900 underlined, facename, encoding );
901
902 if (!font)
903 {
904 // search up and down by stepsize 10
905 int max_size = pointSize + 20 * (1 + (pointSize/180));
906 int min_size = pointSize - 20 * (1 + (pointSize/180));
907
908 int i;
909
910 // Search for smaller size (approx.)
911 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
912 {
913 font = wxLoadQueryFont(i, family, style, weight, underlined,
914 facename, encoding );
915 }
916
917 // Search for larger size (approx.)
918 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
919 {
920 font = wxLoadQueryFont( i, family, style, weight, underlined,
921 facename, encoding );
922 }
923
924 // Try default family
925 if ( !font && family != wxDEFAULT )
926 {
927 font = wxLoadQueryFont( pointSize, wxDEFAULT, style, weight,
928 underlined, facename, encoding );
929 }
930
30760ce7 931 // Bogus font I
93ccaed8
VZ
932 if ( !font )
933 {
934 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
935 underlined, facename, encoding );
936 }
30760ce7
RR
937
938 // Bogus font II
939 if ( !font )
940 {
941 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
942 underlined, wxEmptyString, encoding );
943 }
93ccaed8
VZ
944 }
945
946 return font;
947}
948
e90c1d2a 949#endif // wxUSE_GUI