new wxMenu stuff and thread implementations
[wxWidgets.git] / src / os2 / utils.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: utils.cpp
3 // Purpose: Various utilities
4 // Author: David Webster
5 // Modified by:
6 // Created: 09/17/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/setup.h"
17 #include "wx/utils.h"
18 #include "wx/app.h"
19 #include "wx/cursor.h"
20 #endif //WX_PRECOMP
21
22 #include "wx/os2/private.h"
23 #include "wx/timer.h"
24 #include "wx/intl.h"
25
26 #include <ctype.h>
27 #include <direct.h>
28
29 #include "wx/log.h"
30
31 #include <io.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <stdarg.h>
38
39 #define INCL_DOS
40 #define INCL_PM
41 #define INCL_GPI
42 #include <os2.h>
43 #include<netdb.h>
44 #define PURE_32
45 #include <upm.h>
46 #include <netcons.h>
47 #include <netbios.h>
48
49 static const wxChar WX_SECTION[] = _T("wxWindows");
50 static const wxChar eHOSTNAME[] = _T("HostName");
51 static const wxChar eUSERID[] = _T("UserId");
52 static const wxChar eUSERNAME[] = _T("UserName");
53
54 // For the following functions we SHOULD fill in support
55 // for Windows-NT (which I don't know) as I assume it begin
56 // a POSIX Unix (so claims MS) that it has some special
57 // functions beyond those provided by WinSock
58
59 // Get full hostname (eg. DoDo.BSn-Germany.crg.de)
60 bool wxGetHostName(
61 wxChar* zBuf
62 , int nMaxSize
63 )
64 {
65 #if wxUSE_NET_API
66 char zServer[256];
67 char zComputer[256];
68 unsigned short nLevel = 0;
69 unsigned char* zBuffer;
70 unsigned short nBuffer;
71 unsigned short* pnTotalAvail;
72
73 NetBios32GetInfo( (const unsigned char*)zServer
74 ,(const unsigned char*)zComputer
75 ,nLevel
76 ,zBuffer
77 ,nBuffer
78 ,pnTotalAvail
79 );
80 strcpy(zBuf, zServer);
81 #else
82 wxChar* zSysname;
83 const wxChar* zDefaultHost = _T("noname");
84
85 if ((zSysname = wxGetenv(_T("SYSTEM_NAME"))) == NULL)
86 {
87 ULONG n = ::PrfQueryProfileString( HINI_PROFILE
88 ,(PSZ)WX_SECTION
89 ,(PSZ)eHOSTNAME
90 ,(PSZ)zDefaultHost
91 ,(void*)zBuf
92 ,(ULONG)nMaxSize - 1
93 );
94 }
95 else
96 wxStrncpy(zBuf, zSysname, nMaxSize - 1);
97 zBuf[nMaxSize] = _T('\0');
98 #endif
99 return *zBuf ? TRUE : FALSE;
100 }
101
102 // Get user ID e.g. jacs
103 bool wxGetUserId(
104 wxChar* zBuf
105 , int nType
106 )
107 {
108 long lrc;
109 // UPM procs return 0 on success
110 lrc = U32ELOCU((unsigned char*)zBuf, (unsigned long *)&nType);
111 if (lrc == 0) return TRUE;
112 return FALSE;
113 }
114
115 bool wxGetUserName(
116 wxChar* zBuf
117 , int nMaxSize
118 )
119 {
120 #ifdef USE_NET_API
121 wxGetUserId( zBuf
122 ,nMaxSize
123 );
124 #else
125 wxStrncpy(zBuf, _T("Unknown User"), nMaxSize);
126 #endif
127 return TRUE;
128 }
129
130 int wxKill(
131 long lPid
132 , int nSig
133 )
134 {
135 return((int)::DosKillProcess(0, (PID)lPid));
136 }
137
138 //
139 // Execute a program in an Interactive Shell
140 //
141 bool wxShell(
142 const wxString& rCommand
143 )
144 {
145 wxChar* zShell = _T("CMD.EXE");
146 wxString sInputs;
147 wxChar zTmp[255];
148 STARTDATA SData = {0};
149 PSZ PgmTitle = "Command Shell";
150 APIRET rc;
151 PID vPid = 0;
152 ULONG ulSessID = 0;
153 UCHAR achObjBuf[256] = {0}; //error data if DosStart fails
154 RESULTCODES vResult;
155
156 SData.Length = sizeof(STARTDATA);
157 SData.Related = SSF_RELATED_INDEPENDENT;
158 SData.FgBg = SSF_FGBG_FORE;
159 SData.TraceOpt = SSF_TRACEOPT_NONE;
160 SData.PgmTitle = PgmTitle;
161 SData.PgmName = zShell;
162
163 // sInputs = "/C " + rCommand;
164 SData.PgmInputs = NULL; //(BYTE*)sInputs.c_str();
165 SData.TermQ = 0;
166 SData.Environment = 0;
167 SData.InheritOpt = SSF_INHERTOPT_SHELL;
168 SData.SessionType = SSF_TYPE_WINDOWABLEVIO;
169 SData.IconFile = 0;
170 SData.PgmHandle = 0;
171 SData.PgmControl = SSF_CONTROL_VISIBLE | SSF_CONTROL_MAXIMIZE;
172 SData.InitXPos = 30;
173 SData.InitYPos = 40;
174 SData.InitXSize = 200;
175 SData.InitYSize = 140;
176 SData.Reserved = 0;
177 SData.ObjectBuffer = (char*)achObjBuf;
178 SData.ObjectBuffLen = (ULONG)sizeof(achObjBuf);
179
180 rc = ::DosStartSession(&SData, &ulSessID, &vPid);
181 if (rc == 0)
182 {
183 PTIB ptib;
184 PPIB ppib;
185
186 ::DosGetInfoBlocks(&ptib, &ppib);
187
188 ::DosWaitChild( DCWA_PROCESS
189 ,DCWW_WAIT
190 ,&vResult
191 ,&ppib->pib_ulpid
192 ,vPid
193 );
194 }
195 return (rc != 0);
196 }
197
198 // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
199 long wxGetFreeMemory(
200 void* pMemptr
201 )
202 {
203 ULONG lSize;
204 ULONG lMemFlags;
205 APIRET rc;
206
207 lMemFlags = PAG_FREE;
208 rc = ::DosQueryMem(pMemptr, &lSize, &lMemFlags);
209 if (rc != 0)
210 return -1L;
211 return (long)lSize;
212 }
213
214 // Sleep for nSecs seconds. Attempt a Windows implementation using timers.
215 static bool inTimer = FALSE;
216
217 class wxSleepTimer: public wxTimer
218 {
219 public:
220 inline void Notify()
221 {
222 inTimer = FALSE;
223 Stop();
224 }
225 };
226
227 static wxTimer* wxTheSleepTimer = NULL;
228
229 void wxUsleep(
230 unsigned long ulMilliseconds
231 )
232 {
233 ::DosSleep(ulMilliseconds);
234 }
235
236 void wxSleep(
237 int nSecs
238 )
239 {
240 ::DosSleep(1000 * nSecs);
241 }
242
243 // Consume all events until no more left
244 void wxFlushEvents()
245 {
246 // wxYield();
247 }
248
249 // Output a debug mess., in a system dependent fashion.
250 void wxDebugMsg(
251 const wxChar* zFmt ...
252 )
253 {
254 va_list vAp;
255 static wxChar zBuffer[512];
256
257 if (!wxTheApp->GetWantDebugOutput())
258 return ;
259 va_start(vAp, zFmt);
260 sprintf(zBuffer, zFmt, vAp) ;
261 va_end(vAp);
262 }
263
264 // Non-fatal error: pop up message box and (possibly) continue
265 void wxError(
266 const wxString& rMsg
267 , const wxString& rTitle
268 )
269 {
270 wxSprintf(wxBuffer, "%s\nContinue?", WXSTRINGCAST rMsg);
271 if (::WinMessageBox( HWND_DESKTOP
272 ,NULL
273 ,(PSZ)wxBuffer
274 ,(PSZ)WXSTRINGCAST rTitle
275 ,0
276 ,MB_ICONEXCLAMATION | MB_YESNO
277 ) == MBID_YES)
278 wxExit();
279 }
280
281 // Fatal error: pop up message box and abort
282 void wxFatalError(
283 const wxString& rMsg
284 , const wxString& rTitle
285 )
286 {
287 unsigned long ulRc;
288
289 ulRc = ::WinMessageBox( HWND_DESKTOP
290 ,NULL
291 ,WXSTRINGCAST rMsg
292 ,WXSTRINGCAST rTitle
293 ,0
294 ,MB_NOICON | MB_OK
295 );
296 DosExit(EXIT_PROCESS, ulRc);
297 }
298
299 // Emit a beeeeeep
300 void wxBell()
301 {
302 DosBeep(1000,1000); // 1kHz during 1 sec.
303 }
304
305 // Chris Breeze 27/5/98: revised WIN32 code to
306 // detect WindowsNT correctly
307 int wxGetOsVersion(
308 int* pMajorVsn
309 , int* pMinorVsn
310 )
311 {
312 ULONG ulSysInfo[QSV_MAX] = {0};
313
314 if (::DosQuerySysInfo( 1L
315 ,QSV_MAX
316 ,(PVOID)ulSysInfo
317 ,sizeof(ULONG) * QSV_MAX
318 ))
319 {
320 *pMajorVsn = ulSysInfo[QSV_VERSION_MAJOR];
321 *pMinorVsn = ulSysInfo[QSV_VERSION_MINOR];
322 return wxWINDOWS_OS2;
323 }
324 return wxWINDOWS; // error if we get here, return generic value
325 }
326
327 // Reading and writing resources (eg WIN.INI, .Xdefaults)
328 #if wxUSE_RESOURCES
329 bool wxWriteResource(
330 const wxString& rSection
331 , const wxString& rEntry
332 , const wxString& rValue
333 , const wxString& rFile
334 )
335 {
336 HAB hab;
337 HINI hIni;
338
339 if (rFile != "")
340 {
341 hIni = ::PrfOpenProfile(hab, (PSZ)WXSTRINGCAST rFile);
342 if (hIni != 0L)
343 {
344 return (::PrfWriteProfileString( hIni
345 ,(PSZ)WXSTRINGCAST rSection
346 ,(PSZ)WXSTRINGCAST rEntry
347 ,(PSZ)WXSTRINGCAST rValue
348 ));
349 }
350 }
351 else
352 return (::PrfWriteProfileString( HINI_PROFILE
353 ,(PSZ)WXSTRINGCAST rSection
354 ,(PSZ)WXSTRINGCAST rEntry
355 ,(PSZ)WXSTRINGCAST rValue
356 ));
357 return FALSE;
358 }
359
360 bool wxWriteResource(
361 const wxString& rSection
362 , const wxString& rEntry
363 , float fValue
364 , const wxString& rFile
365 )
366 {
367 wxChar zBuf[50];
368
369 wxSprintf(zBuf, "%.4f", fValue);
370 return wxWriteResource( rSection
371 ,rEntry
372 ,zBuf
373 ,rFile
374 );
375 }
376
377 bool wxWriteResource(
378 const wxString& rSection
379 , const wxString& rEntry
380 , long lValue
381 , const wxString& rFile
382 )
383 {
384 wxChar zBuf[50];
385
386 wxSprintf(zBuf, "%ld", lValue);
387 return wxWriteResource( rSection
388 ,rEntry
389 ,zBuf
390 ,rFile
391 );
392 }
393
394 bool wxWriteResource(
395 const wxString& rSection
396 , const wxString& rEntry
397 , int lValue
398 , const wxString& rFile
399 )
400 {
401 wxChar zBuf[50];
402
403 wxSprintf(zBuf, "%d", lValue);
404 return wxWriteResource( rSection
405 ,rEntry
406 ,zBuf
407 ,rFile
408 );
409 }
410
411 bool wxGetResource(
412 const wxString& rSection
413 , const wxString& rEntry
414 , wxChar** ppValue
415 , const wxString& rFile
416 )
417 {
418 HAB hab;
419 HINI hIni;
420 static const wxChar zDefunkt[] = _T("$$default");
421
422 if (rFile != "")
423 {
424 hIni = ::PrfOpenProfile(hab, (PSZ)WXSTRINGCAST rFile);
425 if (hIni != 0L)
426 {
427 ULONG n = ::PrfQueryProfileString( hIni
428 ,(PSZ)WXSTRINGCAST rSection
429 ,(PSZ)WXSTRINGCAST rEntry
430 ,(PSZ)zDefunkt
431 ,(void*)wxBuffer
432 ,1000
433 );
434 if (n == 0L || wxStrcmp(wxBuffer, zDefunkt) == 0)
435 return FALSE;
436 }
437 else
438 return FALSE;
439 }
440 else
441 {
442 ULONG n = ::PrfQueryProfileString( HINI_PROFILE
443 ,(PSZ)WXSTRINGCAST rSection
444 ,(PSZ)WXSTRINGCAST rEntry
445 ,(PSZ)zDefunkt
446 ,(void*)wxBuffer
447 ,1000
448 );
449 if (n == 0L || wxStrcmp(wxBuffer, zDefunkt) == 0)
450 return FALSE;
451 }
452 if (*ppValue)
453 delete[] (*ppValue);
454 *ppValue = copystring(wxBuffer);
455 return TRUE;
456 }
457
458 bool wxGetResource(
459 const wxString& rSection
460 , const wxString& rEntry
461 , float* pValue
462 , const wxString& rFile
463 )
464 {
465 wxChar* zStr = NULL;
466 bool bSucc = wxGetResource( rSection
467 ,rEntry
468 ,(wxChar **)&zStr
469 ,rFile
470 );
471
472 if (bSucc)
473 {
474 *pValue = (float)wxStrtod(zStr, NULL);
475 delete[] zStr;
476 return TRUE;
477 }
478 else return FALSE;
479 }
480
481 bool wxGetResource(
482 const wxString& rSection
483 , const wxString& rEntry
484 , long* pValue
485 , const wxString& rFile
486 )
487 {
488 wxChar* zStr = NULL;
489 bool bSucc = wxGetResource( rSection
490 ,rEntry
491 ,(wxChar **)&zStr
492 ,rFile
493 );
494
495 if (bSucc)
496 {
497 *pValue = wxStrtol(zStr, NULL, 10);
498 delete[] zStr;
499 return TRUE;
500 }
501 else return FALSE;
502 }
503
504 bool wxGetResource(
505 const wxString& rSection
506 , const wxString& rEntry
507 , int* pValue
508 , const wxString& rFile
509 )
510 {
511 wxChar* zStr = NULL;
512 bool bSucc = wxGetResource( rSection
513 ,rEntry
514 ,(wxChar **)&zStr
515 ,rFile
516 );
517
518 if (bSucc)
519 {
520 *pValue = (int)wxStrtol(zStr, NULL, 10);
521 delete[] zStr;
522 return TRUE;
523 }
524 else return FALSE;
525 }
526 #endif // wxUSE_RESOURCES
527
528 // ---------------------------------------------------------------------------
529 // helper functions for showing a "busy" cursor
530 // ---------------------------------------------------------------------------
531
532 HCURSOR gs_wxBusyCursor = 0; // new, busy cursor
533 HCURSOR gs_wxBusyCursorOld = 0; // old cursor
534 static int gs_wxBusyCursorCount = 0;
535
536 // Set the cursor to the busy cursor for all windows
537 void wxBeginBusyCursor(
538 wxCursor* pCursor
539 )
540 {
541 if ( gs_wxBusyCursorCount++ == 0 )
542 {
543 gs_wxBusyCursor = (HCURSOR)pCursor->GetHCURSOR();
544 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursor);
545 }
546 //else: nothing to do, already set
547 }
548
549 // Restore cursor to normal
550 void wxEndBusyCursor()
551 {
552 wxCHECK_RET( gs_wxBusyCursorCount > 0
553 ,_T("no matching wxBeginBusyCursor() for wxEndBusyCursor()")
554 );
555
556 if (--gs_wxBusyCursorCount == 0)
557 {
558 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursorOld);
559 gs_wxBusyCursorOld = 0;
560 }
561 }
562
563 // TRUE if we're between the above two calls
564 bool wxIsBusy()
565 {
566 return (gs_wxBusyCursorCount > 0);
567 }
568
569 // ---------------------------------------------------------------------------
570 const wxChar* wxGetHomeDir(
571 wxString* pStr
572 )
573 {
574 wxString& rStrDir = *pStr;
575
576 // OS/2 has no idea about home,
577 // so use the working directory instead?
578
579 // 256 was taken from os2def.h
580 #ifndef MAX_PATH
581 # define MAX_PATH 256
582 #endif
583
584 char zDirName[256];
585 ULONG ulDirLen;
586
587 ::DosQueryCurrentDir(0, zDirName, &ulDirLen);
588 rStrDir = zDirName;
589 return rStrDir.c_str();
590 }
591
592 // Hack for OS/2
593 wxChar* wxGetUserHome (
594 const wxString& rUser
595 )
596 {
597 wxChar* zHome;
598 wxString sUser1(rUser);
599
600 if (sUser1 != _T(""))
601 {
602 wxChar zTmp[64];
603
604 if (wxGetUserId( zTmp
605 ,sizeof(zTmp)/sizeof(char)
606 ))
607 {
608 // Guests belong in the temp dir
609 if (wxStricmp(zTmp, _T("annonymous")) == 0)
610 {
611 if ((zHome = wxGetenv(_T("TMP"))) != NULL ||
612 (zHome = wxGetenv(_T("TMPDIR"))) != NULL ||
613 (zHome = wxGetenv(_T("TEMP"))) != NULL)
614 return *zHome ? zHome : (wxChar*)_T("\\");
615 }
616 if (wxStricmp(zTmp, WXSTRINGCAST sUser1) == 0)
617 sUser1 = _T("");
618 }
619 }
620 if (sUser1 == _T(""))
621 if ((zHome = wxGetenv(_T("HOME"))) != NULL)
622 {
623 wxStrcpy(wxBuffer, zHome);
624 Unix2DosFilename(wxBuffer);
625 return wxBuffer;
626 }
627 return NULL; // No home known!
628 }
629
630 // Check whether this window wants to process messages, e.g. Stop button
631 // in long calculations.
632 bool wxCheckForInterrupt(
633 wxWindow* pWnd
634 )
635 {
636 if(pWnd)
637 {
638 QMSG vMsg;
639 HAB hab;
640 HWND hwndFilter;
641 HWND hwndWin= (HWND) pWnd->GetHWND();
642
643 while(::WinPeekMsg(hab, &vMsg, hwndFilter, 0, 0, PM_REMOVE))
644 {
645 ::WinDispatchMsg(hab, &vMsg);
646 }
647 return TRUE;//*** temporary?
648 }
649 else
650 {
651 wxFAIL_MSG(_T("pWnd==NULL !!!"));
652 return FALSE;//*** temporary?
653 }
654 }
655
656 void wxGetMousePosition(
657 int* pX
658 , int* pY
659 )
660 {
661 POINTL vPt;
662
663 ::WinQueryPointerPos(HWND_DESKTOP, &vPt);
664 *pX = vPt.x;
665 *pY = vPt.y;
666 };
667
668 // Return TRUE if we have a colour display
669 bool wxColourDisplay()
670 {
671 HPS hpsScreen;
672 HDC hdcScreen;
673 LONG lColors;
674
675 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
676 hdcScreen = ::GpiQueryDevice(hpsScreen);
677 ::DevQueryCaps(hdcScreen, CAPS_COLORS, 1L, &lColors);
678 return(lColors > 1L);
679 }
680
681 // Returns depth of screen
682 int wxDisplayDepth()
683 {
684 HPS hpsScreen;
685 HDC hdcScreen;
686 LONG lPlanes;
687 LONG lBitsPerPixel;
688 LONG nDepth;
689
690 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
691 hdcScreen = ::GpiQueryDevice(hpsScreen);
692 ::DevQueryCaps(hdcScreen, CAPS_COLOR_PLANES, 1L, &lPlanes);
693 ::DevQueryCaps(hdcScreen, CAPS_COLOR_BITCOUNT, 1L, &lBitsPerPixel);
694
695 nDepth = (int)(lPlanes * lBitsPerPixel);
696 DevCloseDC(hdcScreen);
697 return (nDepth);
698 }
699
700 // Get size of display
701 void wxDisplaySize(
702 int* pWidth
703 , int* pHeight
704 )
705 {
706 HPS hpsScreen;
707 HDC hdcScreen;
708
709 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
710 hdcScreen = ::GpiQueryDevice(hpsScreen);
711 ::DevQueryCaps(hdcScreen, CAPS_WIDTH, 1L, (PLONG)pWidth);
712 ::DevQueryCaps(hdcScreen, CAPS_HEIGHT, 1L, (PLONG)pHeight);
713 DevCloseDC(hdcScreen);
714 }
715
716 bool wxDirExists(
717 const wxString& rDir
718 )
719 {
720 return (::DosSetCurrentDir(WXSTRINGCAST rDir));
721 }
722
723 // ---------------------------------------------------------------------------
724 // window information functions
725 // ---------------------------------------------------------------------------
726
727 wxString WXDLLEXPORT wxGetWindowText(
728 WXHWND hWnd
729 )
730 {
731 wxString vStr;
732 long lLen = ::WinQueryWindowTextLength((HWND)hWnd) + 1;
733
734 ::WinQueryWindowText((HWND)hWnd, lLen, vStr.GetWriteBuf((int)lLen));
735 vStr.UngetWriteBuf();
736
737 return vStr;
738 }
739
740 wxString WXDLLEXPORT wxGetWindowClass(
741 WXHWND hWnd
742 )
743 {
744 wxString vStr;
745 int nLen = 256; // some starting value
746
747 for ( ;; )
748 {
749 int nCount = ::WinQueryClassName((HWND)hWnd, nLen, vStr.GetWriteBuf(nLen));
750
751 vStr.UngetWriteBuf();
752 if (nCount == nLen )
753 {
754 // the class name might have been truncated, retry with larger
755 // buffer
756 nLen *= 2;
757 }
758 else
759 {
760 break;
761 }
762 }
763 return vStr;
764 }
765
766 WXWORD WXDLLEXPORT wxGetWindowId(
767 WXHWND hWnd
768 )
769 {
770 return ::WinQueryWindowUShort((HWND)hWnd, QWS_ID);
771 }
772