]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
If we used 10% less inline functions in useless occasions,
[wxWidgets.git] / src / unix / utilsunx.cpp
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()
42 #include <ctype.h> // isspace()
43
44 // JACS: needed for FD_SETSIZE
45 #include <sys/time.h>
46
47 #if HAVE_UNAME
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.
58 #if !defined(HAVE_USLEEP) && \
59 (defined(__SUN__) && !defined(__SunOs_5_6) && \
60 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
61 defined(__osf__) || defined(__EMX__)
62 extern "C"
63 {
64 #ifdef __SUN__
65 int usleep(unsigned int usec);
66 #else // !Sun
67 #ifdef __EMX
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 }
75 #else
76 void usleep(unsigned long usec);
77 #endif
78 #endif // Sun/EMX/Something else
79 };
80 #define HAVE_USLEEP 1
81 #endif // Unices without usleep()
82
83 // ============================================================================
84 // implementation
85 // ============================================================================
86
87 // ----------------------------------------------------------------------------
88 // sleeping
89 // ----------------------------------------------------------------------------
90
91 void wxSleep(int nSecs)
92 {
93 sleep(nSecs);
94 }
95
96 void wxUsleep(unsigned long milliseconds)
97 {
98 #if HAVE_NANOSLEEP
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);
105 #elif HAVE_USLEEP
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
110 #if defined(__SUN__) && wxUSE_THREADS
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
124 int wxKill(long pid, wxSignal sig)
125 {
126 return kill(pid, (int)sig);
127 }
128
129 #define WXEXECUTE_NARGS 127
130
131 long wxExecute( const wxString& command, bool sync, wxProcess *process )
132 {
133 wxCHECK_MSG( !command.IsEmpty(), 0, _T("can't exec empty command") );
134
135 int argc = 0;
136 wxChar *argv[WXEXECUTE_NARGS];
137 wxString argument;
138 const wxChar *cptr = command.c_str();
139 wxChar quotechar = _T('\0'); // is arg quoted?
140 bool escaped = FALSE;
141
142 // split the command line in arguments
143 do
144 {
145 argument=_T("");
146 quotechar = _T('\0');
147
148 // eat leading whitespace:
149 while ( wxIsspace(*cptr) )
150 cptr++;
151
152 if ( *cptr == _T('\'') || *cptr == _T('"') )
153 quotechar = *cptr++;
154
155 do
156 {
157 if ( *cptr == _T('\\') && ! escaped )
158 {
159 escaped = TRUE;
160 cptr++;
161 continue;
162 }
163
164 // all other characters:
165 argument += *cptr++;
166 escaped = FALSE;
167
168 // have we reached the end of the argument?
169 if ( (*cptr == quotechar && ! escaped)
170 || (quotechar == _T('\0') && wxIsspace(*cptr))
171 || *cptr == _T('\0') )
172 {
173 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
174 _T("too many arguments in wxExecute") );
175
176 argv[argc] = new wxChar[argument.length() + 1];
177 wxStrcpy(argv[argc], argument.c_str());
178 argc++;
179
180 // if not at end of buffer, swallow last character:
181 if(*cptr)
182 cptr++;
183
184 break; // done with this one, start over
185 }
186 } while(*cptr);
187 } while(*cptr);
188 argv[argc] = NULL;
189
190 // do execute the command
191 long lRc = wxExecute(argv, sync, process);
192
193 // clean up
194 argc = 0;
195 while( argv[argc] )
196 delete [] argv[argc++];
197
198 return lRc;
199 }
200
201 bool wxShell(const wxString& command)
202 {
203 wxString cmd;
204 if ( !!command )
205 cmd.Printf(_T("xterm -e %s"), command.c_str());
206 else
207 cmd = command;
208
209 return wxExecute(cmd) != 0;
210 }
211
212 void wxHandleProcessTermination(wxEndProcessData *proc_data)
213 {
214 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
215
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)
219 int status = 0;
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 }
233
234 // clean up
235 if ( proc_data->pid > 0 )
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
248 long wxExecute( wxChar **argv, bool sync, wxProcess *process )
249 {
250 wxCHECK_MSG( *argv, 0, _T("can't exec empty command") );
251
252 int end_proc_detect[2];
253 #if wxUSE_UNICODE
254 int mb_argc = 0;
255 char *mb_argv[WXEXECUTE_NARGS];
256
257 while (argv[mb_argc]) {
258 wxWX2MBbuf mb_arg = wxConvCurrent->cWX2MB(argv[mb_argc]);
259 mb_argv[mb_argc] = strdup(mb_arg);
260 mb_argc++;
261 }
262 mb_argv[mb_argc] = (char *) NULL;
263 #else
264 wxChar **mb_argv = argv;
265 #endif
266
267 // create pipes
268 if (pipe(end_proc_detect) == -1)
269 {
270 wxLogSysError( _("Pipe creation failed") );
271 #if wxUSE_UNICODE
272 mb_argc = 0;
273 while (mb_argv[mb_argc])
274 free(mb_argv[mb_argc++]);
275 #endif
276 return 0;
277 }
278
279 // fork the process
280 #if HAVE_VFORK
281 pid_t pid = vfork();
282 #else
283 pid_t pid = fork();
284 #endif
285 if (pid == -1)
286 {
287 wxLogSysError( _("Fork failed") );
288 #if wxUSE_UNICODE
289 mb_argc = 0;
290 while (mb_argv[mb_argc])
291 free(mb_argv[mb_argc++]);
292 #endif
293 return 0;
294 }
295 else if (pid == 0)
296 {
297 // we're in child
298 close(end_proc_detect[0]); // close reading side
299
300 // These three lines close the open file descriptors to to avoid any
301 // input/output which might block the process or irritate the user. If
302 // one wants proper IO for the subprocess, the right thing to do is
303 // to start an xterm executing it.
304 if (sync == 0)
305 {
306 // leave stderr opened, it won't do any hurm
307 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
308 {
309 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
310 close(fd);
311 }
312 }
313
314 #if 0
315 close(STDERR_FILENO);
316
317 // some programs complain about stderr not being open, so redirect
318 // them:
319 open("/dev/null", O_RDONLY); // stdin
320 open("/dev/null", O_WRONLY); // stdout
321 open("/dev/null", O_WRONLY); // stderr
322 #endif
323
324 execvp (*mb_argv, mb_argv);
325
326 // there is no return after successful exec()
327 wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
328
329 _exit(-1);
330 }
331 else
332 {
333 // we're in parent
334 close(end_proc_detect[1]); // close writing side
335
336 wxEndProcessData *data = new wxEndProcessData;
337 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
338
339 #if wxUSE_UNICODE
340 mb_argc = 0;
341 while (mb_argv[mb_argc])
342 free(mb_argv[mb_argc++]);
343 #endif
344
345 if ( sync )
346 {
347 wxASSERT_MSG( !process, _T("wxProcess param ignored for sync exec") );
348 data->process = NULL;
349
350 // sync execution: indicate it by negating the pid
351 data->pid = -pid;
352
353 // it will be set to 0 from GTK_EndProcessDetector
354 while (data->pid != 0)
355 wxYield();
356
357 int exitcode = data->exitcode;
358
359 delete data;
360
361 return exitcode;
362 }
363 else
364 {
365 // async execution, nothing special to do - caller will be
366 // notified about the process terminationif process != NULL, data
367 // will be deleted in GTK_EndProcessDetector
368 data->process = process;
369 data->pid = pid;
370
371 return pid;
372 }
373 }
374 }
375
376 // ----------------------------------------------------------------------------
377 // file and directory functions
378 // ----------------------------------------------------------------------------
379
380 const wxChar* wxGetHomeDir( wxString *home )
381 {
382 *home = wxGetUserHome( wxString() );
383 if ( home->IsEmpty() )
384 *home = _T("/");
385
386 return home->c_str();
387 }
388
389 #if wxUSE_UNICODE
390 const wxMB2WXbuf wxGetUserHome( const wxString &user )
391 #else // just for binary compatibility
392 char *wxGetUserHome( const wxString &user )
393 #endif
394 {
395 struct passwd *who = (struct passwd *) NULL;
396
397 if ( !user )
398 {
399 register wxChar *ptr;
400
401 if ((ptr = wxGetenv(_T("HOME"))) != NULL)
402 {
403 return ptr;
404 }
405 if ((ptr = wxGetenv(_T("USER"))) != NULL || (ptr = wxGetenv(_T("LOGNAME"))) != NULL)
406 {
407 who = getpwnam(wxConvCurrent->cWX2MB(ptr));
408 }
409
410 // We now make sure the the user exists!
411 if (who == NULL)
412 {
413 who = getpwuid(getuid());
414 }
415 }
416 else
417 {
418 who = getpwnam (user.mb_str());
419 }
420
421 #if wxUSE_UNICODE
422 return who ? wxConvCurrent->cMB2WX(who->pw_dir) : (wxMB2WXbuf)((wxChar*)NULL);
423 #else
424 return who ? who->pw_dir : ((char*)NULL);
425 #endif
426 }
427
428 // ----------------------------------------------------------------------------
429 // network and user id routines
430 // ----------------------------------------------------------------------------
431
432 // retrieve either the hostname or FQDN depending on platform (caller must
433 // check whether it's one or the other, this is why this function is for
434 // private use only)
435 static bool wxGetHostNameInternal(wxChar *buf, int sz)
436 {
437 wxCHECK_MSG( buf, FALSE, _T("NULL pointer in wxGetHostNameInternal") );
438
439 *buf = _T('\0');
440
441 // we're using uname() which is POSIX instead of less standard sysinfo()
442 #if defined(HAVE_UNAME)
443 struct utsname uts;
444 bool ok = uname(&uts) != -1;
445 if ( ok )
446 {
447 wxStrncpy(buf, wxConvCurrent->cMB2WX(uts.nodename), sz - 1);
448 buf[sz] = _T('\0');
449 }
450 #elif defined(HAVE_GETHOSTNAME)
451 bool ok = gethostname(buf, sz) != -1;
452 #else // no uname, no gethostname
453 wxFAIL_MSG(_T("don't know host name for this machine"));
454
455 bool ok = FALSE;
456 #endif // uname/gethostname
457
458 if ( !ok )
459 {
460 wxLogSysError(_("Cannot get the hostname"));
461 }
462
463 return ok;
464 }
465
466 bool wxGetHostName(wxChar *buf, int sz)
467 {
468 bool ok = wxGetHostNameInternal(buf, sz);
469
470 if ( ok )
471 {
472 // BSD systems return the FQDN, we only want the hostname, so extract
473 // it (we consider that dots are domain separators)
474 wxChar *dot = wxStrchr(buf, _T('.'));
475 if ( dot )
476 {
477 // nuke it
478 *dot = _T('\0');
479 }
480 }
481
482 return ok;
483 }
484
485 bool wxGetFullHostName(wxChar *buf, int sz)
486 {
487 bool ok = wxGetHostNameInternal(buf, sz);
488
489 if ( ok )
490 {
491 if ( !wxStrchr(buf, _T('.')) )
492 {
493 struct hostent *host = gethostbyname(wxConvCurrent->cWX2MB(buf));
494 if ( !host )
495 {
496 wxLogSysError(_("Cannot get the official hostname"));
497
498 ok = FALSE;
499 }
500 else
501 {
502 // the canonical name
503 wxStrncpy(buf, wxConvCurrent->cMB2WX(host->h_name), sz);
504 }
505 }
506 //else: it's already a FQDN (BSD behaves this way)
507 }
508
509 return ok;
510 }
511
512 bool wxGetUserId(wxChar *buf, int sz)
513 {
514 struct passwd *who;
515
516 *buf = _T('\0');
517 if ((who = getpwuid(getuid ())) != NULL)
518 {
519 wxStrncpy (buf, wxConvCurrent->cMB2WX(who->pw_name), sz - 1);
520 return TRUE;
521 }
522
523 return FALSE;
524 }
525
526 bool wxGetUserName(wxChar *buf, int sz)
527 {
528 struct passwd *who;
529 char *comma;
530
531 *buf = _T('\0');
532 if ((who = getpwuid (getuid ())) != NULL) {
533 comma = strchr(who->pw_gecos, ',');
534 if (comma)
535 *comma = '\0'; // cut off non-name comment fields
536 wxStrncpy (buf, wxConvCurrent->cMB2WX(who->pw_gecos), sz - 1);
537 return TRUE;
538 }
539
540 return FALSE;
541 }
542
543 // ----------------------------------------------------------------------------
544 // error and debug output routines (deprecated, use wxLog)
545 // ----------------------------------------------------------------------------
546
547 void wxDebugMsg( const char *format, ... )
548 {
549 va_list ap;
550 va_start( ap, format );
551 vfprintf( stderr, format, ap );
552 fflush( stderr );
553 va_end(ap);
554 }
555
556 void wxError( const wxString &msg, const wxString &title )
557 {
558 wxFprintf( stderr, _("Error ") );
559 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
560 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
561 wxFprintf( stderr, _T(".\n") );
562 }
563
564 void wxFatalError( const wxString &msg, const wxString &title )
565 {
566 wxFprintf( stderr, _("Error ") );
567 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
568 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
569 wxFprintf( stderr, _T(".\n") );
570 exit(3); // the same exit code as for abort()
571 }
572
573 // ----------------------------------------------------------------------------
574 // font-related functions
575 // ----------------------------------------------------------------------------
576
577 // define the functions to create and destroy native fonts for this toolkit
578 #ifdef __X__
579 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
580 {
581 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
582 }
583
584 static inline void wxFreeFont(wxNativeFont font)
585 {
586 XFreeFont((Display *)wxGetDisplay(), font);
587 }
588 #elif defined(__WXGTK__)
589
590 #include "gdk/gdk.h"
591
592 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
593 {
594 return gdk_font_load( wxConvCurrent->cWX2MB(fontSpec) );
595 }
596
597 static inline void wxFreeFont(wxNativeFont font)
598 {
599 gdk_font_unref(font);
600 }
601 #else
602 #error "Unknown GUI toolkit"
603 #endif
604
605 // returns TRUE if there are any fonts matching this font spec
606 static bool wxTestFontSpec(const wxString& fontspec)
607 {
608 wxNativeFont test = wxLoadFont(fontspec);
609 if ( test )
610 {
611 wxFreeFont(test);
612
613 return TRUE;
614 }
615 else
616 {
617 return FALSE;
618 }
619 }
620
621 // TODO encoding test logic should be moved to wxLoadQueryNearestFont()
622 static wxNativeFont wxLoadQueryFont(int pointSize,
623 int family,
624 int style,
625 int weight,
626 bool WXUNUSED(underlined),
627 const wxString &facename,
628 wxFontEncoding encoding )
629 {
630 wxString xfamily;
631 switch (family)
632 {
633 case wxDECORATIVE: xfamily = _T("lucida"); break;
634 case wxROMAN: xfamily = _T("times"); break;
635 case wxMODERN: xfamily = _T("courier"); break;
636 case wxSWISS: xfamily = _T("helvetica"); break;
637 case wxTELETYPE: xfamily = _T("lucidatypewriter"); break;
638 case wxSCRIPT: xfamily = _T("utopia"); break;
639 default: xfamily = _T("*");
640 }
641
642 wxString fontSpec;
643 if (!facename.IsEmpty())
644 {
645 fontSpec.Printf(_T("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
646 facename.c_str());
647
648 if ( wxTestFontSpec(fontSpec) )
649 {
650 xfamily = facename;
651 }
652 //else: no such family, use default one instead
653 }
654
655 wxString xstyle;
656 switch (style)
657 {
658 case wxITALIC: xstyle = _T("i"); break;
659 case wxSLANT: xstyle = _T("o"); break;
660 case wxNORMAL: xstyle = _T("r"); break;
661 default: xstyle = _T("*"); break;
662 }
663
664 wxString xweight;
665 switch (weight)
666 {
667 case wxBOLD: xweight = _T("bold"); break;
668 case wxLIGHT:
669 case wxNORMAL: xweight = _T("medium"); break;
670 default: xweight = _T("*"); break;
671 }
672
673 wxString xregistry, xencoding;
674 if ( encoding == wxFONTENCODING_DEFAULT )
675 {
676 // use the apps default
677 encoding = wxFont::GetDefaultEncoding();
678 }
679
680 bool test = TRUE; // should we test for availability of encoding?
681 switch ( encoding )
682 {
683 case wxFONTENCODING_ISO8859_1:
684 case wxFONTENCODING_ISO8859_2:
685 case wxFONTENCODING_ISO8859_3:
686 case wxFONTENCODING_ISO8859_4:
687 case wxFONTENCODING_ISO8859_5:
688 case wxFONTENCODING_ISO8859_6:
689 case wxFONTENCODING_ISO8859_7:
690 case wxFONTENCODING_ISO8859_8:
691 case wxFONTENCODING_ISO8859_9:
692 case wxFONTENCODING_ISO8859_10:
693 case wxFONTENCODING_ISO8859_11:
694 case wxFONTENCODING_ISO8859_13:
695 case wxFONTENCODING_ISO8859_14:
696 case wxFONTENCODING_ISO8859_15:
697 {
698 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
699 xregistry = _T("iso8859");
700 xencoding.Printf(_T("%d"), cp);
701 }
702 break;
703
704 case wxFONTENCODING_KOI8:
705 xregistry = _T("koi8");
706 if ( wxTestFontSpec(_T("-*-*-*-*-*-*-*-*-*-*-*-*-koi8-1")) )
707 {
708 xencoding = _T("1");
709
710 // test passed, no need to do it once more
711 test = FALSE;
712 }
713 else
714 {
715 xencoding = _T("*");
716 }
717 break;
718
719 case wxFONTENCODING_CP1250:
720 case wxFONTENCODING_CP1251:
721 case wxFONTENCODING_CP1252:
722 {
723 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
724 fontSpec.Printf(_T("-*-*-*-*-*-*-*-*-*-*-*-*-microsoft-cp%d"),
725 cp);
726 if ( wxTestFontSpec(fontSpec) )
727 {
728 xregistry = _T("microsoft");
729 xencoding.Printf(_T("cp%d"), cp);
730
731 // test passed, no need to do it once more
732 test = FALSE;
733 }
734 else
735 {
736 // fall back to LatinX
737 xregistry = _T("iso8859");
738 xencoding.Printf(_T("%d"), cp - 1249);
739 }
740 }
741 break;
742
743 case wxFONTENCODING_SYSTEM:
744 default:
745 test = FALSE;
746 xregistry =
747 xencoding = _T("*");
748 }
749
750 if ( test )
751 {
752 fontSpec.Printf(_T("-*-*-*-*-*-*-*-*-*-*-*-*-%s-%s"),
753 xregistry.c_str(), xencoding.c_str());
754 if ( !wxTestFontSpec(fontSpec) )
755 {
756 // this encoding isn't available - what to do?
757 xregistry =
758 xencoding = _T("*");
759 }
760 }
761
762 // construct the X font spec from our data
763 fontSpec.Printf(_T("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
764 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
765 pointSize, xregistry.c_str(), xencoding.c_str());
766
767 return wxLoadFont(fontSpec);
768 }
769
770 wxNativeFont wxLoadQueryNearestFont(int pointSize,
771 int family,
772 int style,
773 int weight,
774 bool underlined,
775 const wxString &facename,
776 wxFontEncoding encoding)
777 {
778 wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
779 underlined, facename, encoding );
780
781 if (!font)
782 {
783 // search up and down by stepsize 10
784 int max_size = pointSize + 20 * (1 + (pointSize/180));
785 int min_size = pointSize - 20 * (1 + (pointSize/180));
786
787 int i;
788
789 // Search for smaller size (approx.)
790 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
791 {
792 font = wxLoadQueryFont(i, family, style, weight, underlined,
793 facename, encoding );
794 }
795
796 // Search for larger size (approx.)
797 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
798 {
799 font = wxLoadQueryFont( i, family, style, weight, underlined,
800 facename, encoding );
801 }
802
803 // Try default family
804 if ( !font && family != wxDEFAULT )
805 {
806 font = wxLoadQueryFont( pointSize, wxDEFAULT, style, weight,
807 underlined, facename, encoding );
808 }
809
810 // Bogus font
811 if ( !font )
812 {
813 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
814 underlined, facename, encoding );
815 }
816 }
817
818 return font;
819 }
820