]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
tiny fixes
[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 #if wxUSE_UNICODE
253 int mb_argc = 0;
254 char *mb_argv[WXEXECUTE_NARGS];
255
256 while (argv[mb_argc])
257 {
258 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
259 mb_argv[mb_argc] = strdup(mb_arg);
260 mb_argc++;
261 }
262 mb_argv[mb_argc] = (char *) NULL;
263
264 // this macro will free memory we used above
265 #define ARGS_CLEANUP \
266 for ( mb_argc = 0; mb_argb[mb_argc]; mb_argc++ ) \
267 free(mb_argv[mb_argc])
268 #else // ANSI
269 // no need for cleanup
270 #define ARGS_CLEANUP
271
272 wxChar **mb_argv = argv;
273 #endif // Unicode/ANSI
274
275 #if wxUSE_GUI
276 // create pipes
277 int end_proc_detect[2];
278 if (pipe(end_proc_detect) == -1)
279 {
280 wxLogSysError( _("Pipe creation failed") );
281
282 ARGS_CLEANUP;
283
284 return 0;
285 }
286 #endif // wxUSE_GUI
287
288 // fork the process
289 #if HAVE_VFORK
290 pid_t pid = vfork();
291 #else
292 pid_t pid = fork();
293 #endif
294 if (pid == -1)
295 {
296 wxLogSysError( _("Fork failed") );
297
298 ARGS_CLEANUP;
299
300 return 0;
301 }
302 else if (pid == 0)
303 {
304 #if wxUSE_GUI
305 // we're in child
306 close(end_proc_detect[0]); // close reading side
307 #endif // wxUSE_GUI
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
311 // one wants proper IO for the subprocess, the right thing to do is
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 {
318 #if wxUSE_GUI
319 if ( fd == end_proc_detect[1] )
320 continue;
321 #endif // wxUSE_GUI
322
323 if ( fd != STDERR_FILENO )
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
338 execvp (*mb_argv, mb_argv);
339
340 // there is no return after successful exec()
341 wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
342
343 _exit(-1);
344 }
345 else
346 {
347 #if wxUSE_GUI
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
354 ARGS_CLEANUP;
355
356 if ( sync )
357 {
358 wxASSERT_MSG( !process, T("wxProcess param ignored for sync exec") );
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 }
384 #else // !wxUSE_GUI
385 wxASSERT_MSG( sync, T("async execution not supported yet") );
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
395 }
396
397 #undef ARGS_CLEANUP
398 }
399
400 // ----------------------------------------------------------------------------
401 // file and directory functions
402 // ----------------------------------------------------------------------------
403
404 const wxChar* wxGetHomeDir( wxString *home )
405 {
406 *home = wxGetUserHome( wxString() );
407 if ( home->IsEmpty() )
408 *home = T("/");
409
410 return home->c_str();
411 }
412
413 #if wxUSE_UNICODE
414 const wxMB2WXbuf wxGetUserHome( const wxString &user )
415 #else // just for binary compatibility -- there is no 'const' here
416 char *wxGetUserHome( const wxString &user )
417 #endif
418 {
419 struct passwd *who = (struct passwd *) NULL;
420
421 if ( !user )
422 {
423 wxChar *ptr;
424
425 if ((ptr = wxGetenv(T("HOME"))) != NULL)
426 {
427 return ptr;
428 }
429 if ((ptr = wxGetenv(T("USER"))) != NULL || (ptr = wxGetenv(T("LOGNAME"))) != NULL)
430 {
431 who = getpwnam(wxConvertWX2MB(ptr));
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 {
442 who = getpwnam (user.mb_str());
443 }
444
445 return wxConvertMB2WX(who ? who->pw_dir : NULL);
446 }
447
448 // ----------------------------------------------------------------------------
449 // network and user id routines
450 // ----------------------------------------------------------------------------
451
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)
455 static bool wxGetHostNameInternal(wxChar *buf, int sz)
456 {
457 wxCHECK_MSG( buf, FALSE, T("NULL pointer in wxGetHostNameInternal") );
458
459 *buf = T('\0');
460
461 // we're using uname() which is POSIX instead of less standard sysinfo()
462 #if defined(HAVE_UNAME)
463 struct utsname uts;
464 bool ok = uname(&uts) != -1;
465 if ( ok )
466 {
467 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
468 buf[sz] = T('\0');
469 }
470 #elif defined(HAVE_GETHOSTNAME)
471 bool ok = gethostname(buf, sz) != -1;
472 #else // no uname, no gethostname
473 wxFAIL_MSG(T("don't know host name for this machine"));
474
475 bool ok = FALSE;
476 #endif // uname/gethostname
477
478 if ( !ok )
479 {
480 wxLogSysError(_("Cannot get the hostname"));
481 }
482
483 return ok;
484 }
485
486 bool wxGetHostName(wxChar *buf, int sz)
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)
494 wxChar *dot = wxStrchr(buf, T('.'));
495 if ( dot )
496 {
497 // nuke it
498 *dot = T('\0');
499 }
500 }
501
502 return ok;
503 }
504
505 bool wxGetFullHostName(wxChar *buf, int sz)
506 {
507 bool ok = wxGetHostNameInternal(buf, sz);
508
509 if ( ok )
510 {
511 if ( !wxStrchr(buf, T('.')) )
512 {
513 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
514 if ( !host )
515 {
516 wxLogSysError(_("Cannot get the official hostname"));
517
518 ok = FALSE;
519 }
520 else
521 {
522 // the canonical name
523 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
524 }
525 }
526 //else: it's already a FQDN (BSD behaves this way)
527 }
528
529 return ok;
530 }
531
532 bool wxGetUserId(wxChar *buf, int sz)
533 {
534 struct passwd *who;
535
536 *buf = T('\0');
537 if ((who = getpwuid(getuid ())) != NULL)
538 {
539 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
540 return TRUE;
541 }
542
543 return FALSE;
544 }
545
546 bool wxGetUserName(wxChar *buf, int sz)
547 {
548 struct passwd *who;
549 char *comma;
550
551 *buf = T('\0');
552 if ((who = getpwuid (getuid ())) != NULL) {
553 comma = strchr(who->pw_gecos, ',');
554 if (comma)
555 *comma = '\0'; // cut off non-name comment fields
556 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
557 return TRUE;
558 }
559
560 return FALSE;
561 }
562
563 #if wxUSE_GUI
564
565 // ----------------------------------------------------------------------------
566 // error and debug output routines (deprecated, use wxLog)
567 // ----------------------------------------------------------------------------
568
569 void 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
578 void wxError( const wxString &msg, const wxString &title )
579 {
580 wxFprintf( stderr, _("Error ") );
581 if (!title.IsNull()) wxFprintf( stderr, T("%s "), WXSTRINGCAST(title) );
582 if (!msg.IsNull()) wxFprintf( stderr, T(": %s"), WXSTRINGCAST(msg) );
583 wxFprintf( stderr, T(".\n") );
584 }
585
586 void wxFatalError( const wxString &msg, const wxString &title )
587 {
588 wxFprintf( stderr, _("Error ") );
589 if (!title.IsNull()) wxFprintf( stderr, T("%s "), WXSTRINGCAST(title) );
590 if (!msg.IsNull()) wxFprintf( stderr, T(": %s"), WXSTRINGCAST(msg) );
591 wxFprintf( stderr, T(".\n") );
592 exit(3); // the same exit code as for abort()
593 }
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__)
611
612 #include "gdk/gdk.h"
613
614 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
615 {
616 return gdk_font_load( wxConvertWX2MB(fontSpec) );
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
628 static 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()
644 static 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 {
655 case wxDECORATIVE: xfamily = T("lucida"); break;
656 case wxROMAN: xfamily = T("times"); break;
657 case wxMODERN: xfamily = T("courier"); break;
658 case wxSWISS: xfamily = T("helvetica"); break;
659 case wxTELETYPE: xfamily = T("lucidatypewriter"); break;
660 case wxSCRIPT: xfamily = T("utopia"); break;
661 default: xfamily = T("*");
662 }
663
664 wxString fontSpec;
665 if (!facename.IsEmpty())
666 {
667 fontSpec.Printf(T("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
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 {
680 case wxITALIC: xstyle = T("i"); break;
681 case wxSLANT: xstyle = T("o"); break;
682 case wxNORMAL: xstyle = T("r"); break;
683 default: xstyle = T("*"); break;
684 }
685
686 wxString xweight;
687 switch (weight)
688 {
689 case wxBOLD: xweight = T("bold"); break;
690 case wxLIGHT:
691 case wxNORMAL: xweight = T("medium"); break;
692 default: xweight = T("*"); break;
693 }
694
695 wxString xregistry, xencoding;
696 if ( encoding == wxFONTENCODING_DEFAULT )
697 {
698 // use the apps default
699 encoding = wxFont::GetDefaultEncoding();
700 }
701
702 bool test = TRUE; // should we test for availability of encoding?
703 switch ( encoding )
704 {
705 case wxFONTENCODING_ISO8859_1:
706 case wxFONTENCODING_ISO8859_2:
707 case wxFONTENCODING_ISO8859_3:
708 case wxFONTENCODING_ISO8859_4:
709 case wxFONTENCODING_ISO8859_5:
710 case wxFONTENCODING_ISO8859_6:
711 case wxFONTENCODING_ISO8859_7:
712 case wxFONTENCODING_ISO8859_8:
713 case wxFONTENCODING_ISO8859_9:
714 case wxFONTENCODING_ISO8859_10:
715 case wxFONTENCODING_ISO8859_11:
716 case wxFONTENCODING_ISO8859_13:
717 case wxFONTENCODING_ISO8859_14:
718 case wxFONTENCODING_ISO8859_15:
719 {
720 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
721 xregistry = T("iso8859");
722 xencoding.Printf(T("%d"), cp);
723 }
724 break;
725
726 case wxFONTENCODING_KOI8:
727 xregistry = T("koi8");
728 if ( wxTestFontSpec(T("-*-*-*-*-*-*-*-*-*-*-*-*-koi8-1")) )
729 {
730 xencoding = T("1");
731
732 // test passed, no need to do it once more
733 test = FALSE;
734 }
735 else
736 {
737 xencoding = T("*");
738 }
739 break;
740
741 case wxFONTENCODING_CP1250:
742 case wxFONTENCODING_CP1251:
743 case wxFONTENCODING_CP1252:
744 {
745 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
746 fontSpec.Printf(T("-*-*-*-*-*-*-*-*-*-*-*-*-microsoft-cp%d"),
747 cp);
748 if ( wxTestFontSpec(fontSpec) )
749 {
750 xregistry = T("microsoft");
751 xencoding.Printf(T("cp%d"), cp);
752
753 // test passed, no need to do it once more
754 test = FALSE;
755 }
756 else
757 {
758 // fall back to LatinX
759 xregistry = T("iso8859");
760 xencoding.Printf(T("%d"), cp - 1249);
761 }
762 }
763 break;
764
765 case wxFONTENCODING_SYSTEM:
766 default:
767 test = FALSE;
768 xregistry =
769 xencoding = T("*");
770 }
771
772 if ( test )
773 {
774 fontSpec.Printf(T("-*-*-*-*-*-*-*-*-*-*-*-*-%s-%s"),
775 xregistry.c_str(), xencoding.c_str());
776 if ( !wxTestFontSpec(fontSpec) )
777 {
778 // this encoding isn't available - what to do?
779 xregistry =
780 xencoding = T("*");
781 }
782 }
783
784 // construct the X font spec from our data
785 fontSpec.Printf(T("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
786 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
787 pointSize, xregistry.c_str(), xencoding.c_str());
788
789 return wxLoadFont(fontSpec);
790 }
791
792 wxNativeFont wxLoadQueryNearestFont(int pointSize,
793 int family,
794 int style,
795 int weight,
796 bool underlined,
797 const wxString &facename,
798 wxFontEncoding encoding)
799 {
800 wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
801 underlined, facename, encoding );
802
803 if (!font)
804 {
805 // search up and down by stepsize 10
806 int max_size = pointSize + 20 * (1 + (pointSize/180));
807 int min_size = pointSize - 20 * (1 + (pointSize/180));
808
809 int i;
810
811 // Search for smaller size (approx.)
812 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
813 {
814 font = wxLoadQueryFont(i, family, style, weight, underlined,
815 facename, encoding );
816 }
817
818 // Search for larger size (approx.)
819 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
820 {
821 font = wxLoadQueryFont( i, family, style, weight, underlined,
822 facename, encoding );
823 }
824
825 // Try default family
826 if ( !font && family != wxDEFAULT )
827 {
828 font = wxLoadQueryFont( pointSize, wxDEFAULT, style, weight,
829 underlined, facename, encoding );
830 }
831
832 // Bogus font
833 if ( !font )
834 {
835 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
836 underlined, facename, encoding );
837 }
838 }
839
840 return font;
841 }
842
843 #endif // wxUSE_GUI