don't use annoying and unneeded in C++ casts of NULL to "T *" in all other files...
[wxWidgets.git] / src / motif / utils.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/utils.cpp
3 // Purpose: Various utilities
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #include "wx/utils.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/app.h"
27 #include "wx/dcmemory.h"
28 #include "wx/bitmap.h"
29 #endif
30
31 #include "wx/apptrait.h"
32 #include "wx/evtloop.h"
33 #include "wx/motif/private/timer.h"
34
35 #include <string.h>
36
37 #if (defined(__SUNCC__) || defined(__CLCC__))
38 #include <sysent.h>
39 #endif
40
41 #ifdef __VMS__
42 #pragma message disable nosimpint
43 #endif
44
45 #include "wx/unix/execute.h"
46
47 #include <Xm/Xm.h>
48 #include <Xm/Frame.h>
49
50 #include "wx/motif/private.h"
51
52 #include "X11/Xutil.h"
53
54 #ifdef __VMS__
55 #pragma message enable nosimpint
56 #endif
57
58
59 // ============================================================================
60 // implementation
61 // ============================================================================
62
63 // ----------------------------------------------------------------------------
64 // async event processing
65 // ----------------------------------------------------------------------------
66
67 // Consume all events until no more left
68 void wxFlushEvents(WXDisplay* wxdisplay)
69 {
70 Display *display = (Display*)wxdisplay;
71 wxEventLoop evtLoop;
72
73 XSync (display, False);
74
75 while (evtLoop.Pending())
76 {
77 XFlush (display);
78 evtLoop.Dispatch();
79 }
80 }
81
82 // ----------------------------------------------------------------------------
83 // wxExecute stuff
84 // ----------------------------------------------------------------------------
85
86 static void xt_notify_end_process(XtPointer data, int *WXUNUSED(fid),
87 XtInputId *id)
88 {
89 wxEndProcessData *proc_data = (wxEndProcessData *)data;
90
91 wxHandleProcessTermination(proc_data);
92
93 // VZ: I think they should be the same...
94 wxASSERT( (int)*id == proc_data->tag );
95
96 XtRemoveInput(*id);
97 }
98
99 int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd)
100 {
101 XtInputId id = XtAppAddInput((XtAppContext) wxTheApp->GetAppContext(),
102 fd,
103 (XtPointer *) XtInputReadMask,
104 (XtInputCallbackProc) xt_notify_end_process,
105 (XtPointer) proc_data);
106
107 return (int)id;
108 }
109
110 // ----------------------------------------------------------------------------
111 // misc
112 // ----------------------------------------------------------------------------
113
114 // Emit a beeeeeep
115 #ifndef __EMX__
116 // on OS/2, we use the wxBell from wxBase library (src/os2/utils.cpp)
117 void wxBell()
118 {
119 // Use current setting for the bell
120 XBell (wxGlobalDisplay(), 0);
121 }
122 #endif
123
124 wxPortId wxGUIAppTraits::GetToolkitVersion(int *verMaj, int *verMin) const
125 {
126 // XmVERSION and XmREVISION are defined in Xm/Xm.h
127 if ( verMaj )
128 *verMaj = XmVERSION;
129 if ( verMin )
130 *verMin = XmREVISION;
131
132 return wxPORT_MOTIF;
133 }
134
135 wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
136 {
137 return new wxEventLoop;
138 }
139
140 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer* timer)
141 {
142 return new wxMotifTimerImpl(timer);
143 }
144
145 // ----------------------------------------------------------------------------
146 // display info
147 // ----------------------------------------------------------------------------
148
149 void wxGetMousePosition( int* x, int* y )
150 {
151 #if wxUSE_NANOX
152 // TODO
153 *x = 0;
154 *y = 0;
155 #else
156 XMotionEvent xev;
157 Window root, child;
158 XQueryPointer(wxGlobalDisplay(),
159 DefaultRootWindow(wxGlobalDisplay()),
160 &root, &child,
161 &(xev.x_root), &(xev.y_root),
162 &(xev.x), &(xev.y),
163 &(xev.state));
164 *x = xev.x_root;
165 *y = xev.y_root;
166 #endif
167 }
168
169 // Return true if we have a colour display
170 bool wxColourDisplay()
171 {
172 return wxDisplayDepth() > 1;
173 }
174
175 // Returns depth of screen
176 int wxDisplayDepth()
177 {
178 Display *dpy = wxGlobalDisplay();
179
180 return DefaultDepth (dpy, DefaultScreen (dpy));
181 }
182
183 // Get size of display
184 void wxDisplaySize(int *width, int *height)
185 {
186 Display *dpy = wxGlobalDisplay();
187
188 if ( width )
189 *width = DisplayWidth (dpy, DefaultScreen (dpy));
190 if ( height )
191 *height = DisplayHeight (dpy, DefaultScreen (dpy));
192 }
193
194 void wxDisplaySizeMM(int *width, int *height)
195 {
196 Display *dpy = wxGlobalDisplay();
197
198 if ( width )
199 *width = DisplayWidthMM(dpy, DefaultScreen (dpy));
200 if ( height )
201 *height = DisplayHeightMM(dpy, DefaultScreen (dpy));
202 }
203
204 // Configurable display in wxX11 and wxMotif
205 static WXDisplay *gs_currentDisplay = NULL;
206 static wxString gs_displayName;
207
208 WXDisplay *wxGetDisplay()
209 {
210 if (gs_currentDisplay)
211 return gs_currentDisplay;
212 else if (wxTheApp)
213 return wxTheApp->GetInitialDisplay();
214 return NULL;
215 }
216
217 bool wxSetDisplay(const wxString& display_name)
218 {
219 gs_displayName = display_name;
220
221 if ( display_name.empty() )
222 {
223 gs_currentDisplay = NULL;
224
225 return true;
226 }
227 else
228 {
229 Cardinal argc = 0;
230
231 Display *display = XtOpenDisplay((XtAppContext) wxTheApp->GetAppContext(),
232 display_name.c_str(),
233 wxTheApp->GetAppName().c_str(),
234 wxTheApp->GetClassName().c_str(),
235 NULL,
236 #if XtSpecificationRelease < 5
237 0, &argc,
238 #else
239 0, (int *)&argc,
240 #endif
241 NULL);
242
243 if (display)
244 {
245 gs_currentDisplay = (WXDisplay*) display;
246 return true;
247 }
248 else
249 return false;
250 }
251 }
252
253 wxString wxGetDisplayName()
254 {
255 return gs_displayName;
256 }
257
258 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
259 {
260 return wxGenericFindWindowAtPoint(pt);
261 }
262
263 // ----------------------------------------------------------------------------
264 // Some colour manipulation routines
265 // ----------------------------------------------------------------------------
266
267 void wxHSVToXColor(wxHSV *hsv,XColor *rgb)
268 {
269 int h = hsv->h;
270 int s = hsv->s;
271 int v = hsv->v;
272 int r = 0, g = 0, b = 0;
273 int i, f;
274 int p, q, t;
275 s = (s * wxMAX_RGB) / wxMAX_SV;
276 v = (v * wxMAX_RGB) / wxMAX_SV;
277 if (h == 360) h = 0;
278 if (s == 0) { h = 0; r = g = b = v; }
279 i = h / 60;
280 f = h % 60;
281 p = v * (wxMAX_RGB - s) / wxMAX_RGB;
282 q = v * (wxMAX_RGB - s * f / 60) / wxMAX_RGB;
283 t = v * (wxMAX_RGB - s * (60 - f) / 60) / wxMAX_RGB;
284 switch (i)
285 {
286 case 0: r = v, g = t, b = p; break;
287 case 1: r = q, g = v, b = p; break;
288 case 2: r = p, g = v, b = t; break;
289 case 3: r = p, g = q, b = v; break;
290 case 4: r = t, g = p, b = v; break;
291 case 5: r = v, g = p, b = q; break;
292 }
293 rgb->red = (unsigned short)(r << 8);
294 rgb->green = (unsigned short)(g << 8);
295 rgb->blue = (unsigned short)(b << 8);
296 }
297
298 void wxXColorToHSV(wxHSV *hsv,XColor *rgb)
299 {
300 int r = rgb->red >> 8;
301 int g = rgb->green >> 8;
302 int b = rgb->blue >> 8;
303 int maxv = wxMax3(r, g, b);
304 int minv = wxMin3(r, g, b);
305 int h = 0, s, v;
306 v = maxv;
307 if (maxv) s = (maxv - minv) * wxMAX_RGB / maxv;
308 else s = 0;
309 if (s == 0) h = 0;
310 else
311 {
312 int rc, gc, bc, hex = 0;
313 rc = (maxv - r) * wxMAX_RGB / (maxv - minv);
314 gc = (maxv - g) * wxMAX_RGB / (maxv - minv);
315 bc = (maxv - b) * wxMAX_RGB / (maxv - minv);
316 if (r == maxv) { h = bc - gc, hex = 0; }
317 else if (g == maxv) { h = rc - bc, hex = 2; }
318 else if (b == maxv) { h = gc - rc, hex = 4; }
319 h = hex * 60 + (h * 60 / wxMAX_RGB);
320 if (h < 0) h += 360;
321 }
322 hsv->h = h;
323 hsv->s = (s * wxMAX_SV) / wxMAX_RGB;
324 hsv->v = (v * wxMAX_SV) / wxMAX_RGB;
325 }
326
327 void wxAllocNearestColor(Display *d,Colormap cmp,XColor *xc)
328 {
329 #if !wxUSE_NANOX
330 int llp;
331
332 int screen = DefaultScreen(d);
333 int num_colors = DisplayCells(d,screen);
334
335 XColor *color_defs = new XColor[num_colors];
336 for(llp = 0;llp < num_colors;llp++) color_defs[llp].pixel = llp;
337 XQueryColors(d,cmp,color_defs,num_colors);
338
339 wxHSV hsv_defs, hsv;
340 wxXColorToHSV(&hsv,xc);
341
342 int diff, min_diff = 0, pixel = 0;
343
344 for(llp = 0;llp < num_colors;llp++)
345 {
346 wxXColorToHSV(&hsv_defs,&color_defs[llp]);
347 diff = wxSIGN(wxH_WEIGHT * (hsv.h - hsv_defs.h)) +
348 wxSIGN(wxS_WEIGHT * (hsv.s - hsv_defs.s)) +
349 wxSIGN(wxV_WEIGHT * (hsv.v - hsv_defs.v));
350 if (llp == 0) min_diff = diff;
351 if (min_diff > diff) { min_diff = diff; pixel = llp; }
352 if (min_diff == 0) break;
353 }
354
355 xc -> red = color_defs[pixel].red;
356 xc -> green = color_defs[pixel].green;
357 xc -> blue = color_defs[pixel].blue;
358 xc -> flags = DoRed | DoGreen | DoBlue;
359
360 /* FIXME, TODO
361 if (!XAllocColor(d,cmp,xc))
362 cout << "wxAllocNearestColor : Warning : Cannot find nearest color !\n";
363 */
364
365 delete[] color_defs;
366 #endif
367 }
368
369 void wxAllocColor(Display *d,Colormap cmp,XColor *xc)
370 {
371 if (!XAllocColor(d,cmp,xc))
372 {
373 // cout << "wxAllocColor : Warning : Can not allocate color, attempt find nearest !\n";
374 wxAllocNearestColor(d,cmp,xc);
375 }
376 }
377
378 #ifdef __WXDEBUG__
379 wxString wxGetXEventName(XEvent& event)
380 {
381 #if wxUSE_NANOX
382 wxString str(wxT("(some event)"));
383 return str;
384 #else
385 int type = event.xany.type;
386 static char* event_name[] = {
387 wxMOTIF_STR(""), wxMOTIF_STR("unknown(-)"), // 0-1
388 wxMOTIF_STR("KeyPress"), wxMOTIF_STR("KeyRelease"), wxMOTIF_STR("ButtonPress"), wxMOTIF_STR("ButtonRelease"), // 2-5
389 wxMOTIF_STR("MotionNotify"), wxMOTIF_STR("EnterNotify"), wxMOTIF_STR("LeaveNotify"), wxMOTIF_STR("FocusIn"), // 6-9
390 wxMOTIF_STR("FocusOut"), wxMOTIF_STR("KeymapNotify"), wxMOTIF_STR("Expose"), wxMOTIF_STR("GraphicsExpose"), // 10-13
391 wxMOTIF_STR("NoExpose"), wxMOTIF_STR("VisibilityNotify"), wxMOTIF_STR("CreateNotify"), // 14-16
392 wxMOTIF_STR("DestroyNotify"), wxMOTIF_STR("UnmapNotify"), wxMOTIF_STR("MapNotify"), wxMOTIF_STR("MapRequest"),// 17-20
393 wxMOTIF_STR("ReparentNotify"), wxMOTIF_STR("ConfigureNotify"), wxMOTIF_STR("ConfigureRequest"), // 21-23
394 wxMOTIF_STR("GravityNotify"), wxMOTIF_STR("ResizeRequest"), wxMOTIF_STR("CirculateNotify"), // 24-26
395 wxMOTIF_STR("CirculateRequest"), wxMOTIF_STR("PropertyNotify"), wxMOTIF_STR("SelectionClear"), // 27-29
396 wxMOTIF_STR("SelectionRequest"), wxMOTIF_STR("SelectionNotify"), wxMOTIF_STR("ColormapNotify"), // 30-32
397 wxMOTIF_STR("ClientMessage"), wxMOTIF_STR("MappingNotify"), // 33-34
398 wxMOTIF_STR("unknown(+)")}; // 35
399 type = wxMin(35, type); type = wxMax(1, type);
400 wxString str(event_name[type]);
401 return str;
402 #endif
403 }
404 #endif
405
406 // ----------------------------------------------------------------------------
407 // accelerators
408 // ----------------------------------------------------------------------------
409
410 // Find the letter corresponding to the mnemonic, for Motif
411 char wxFindMnemonic (const char *s)
412 {
413 char mnem = 0;
414 int len = strlen (s);
415 int i;
416
417 for (i = 0; i < len; i++)
418 {
419 if (s[i] == '&')
420 {
421 // Carefully handle &&
422 if ((i + 1) <= len && s[i + 1] == '&')
423 i++;
424 else
425 {
426 mnem = s[i + 1];
427 break;
428 }
429 }
430 }
431 return mnem;
432 }
433
434 char* wxFindAccelerator( const char *s )
435 {
436 #if 1
437 wxUnusedVar(s);
438 // VZ: this function returns incorrect keysym which completely breaks kbd
439 // handling
440 return NULL;
441 #else
442 // The accelerator text is after the \t char.
443 s = strchr( s, '\t' );
444
445 if( !s ) return NULL;
446
447 /*
448 Now we need to format it as X standard:
449
450 input output
451
452 F7 --> <Key>F7
453 Ctrl+N --> Ctrl<Key>N
454 Alt+k --> Meta<Key>k
455 Ctrl+Shift+A --> Ctrl Shift<Key>A
456
457 and handle Ctrl-N & similia
458 */
459
460 static char buf[256];
461
462 buf[0] = '\0';
463 wxString tmp = s + 1; // skip TAB
464 size_t index = 0;
465
466 while( index < tmp.length() )
467 {
468 size_t plus = tmp.find( '+', index );
469 size_t minus = tmp.find( '-', index );
470
471 // neither '+' nor '-', add <Key>
472 if( plus == wxString::npos && minus == wxString::npos )
473 {
474 strcat( buf, "<Key>" );
475 strcat( buf, tmp.c_str() + index );
476
477 return buf;
478 }
479
480 // OK: npos is big and positive
481 size_t sep = wxMin( plus, minus );
482 wxString mod = tmp.substr( index, sep - index );
483
484 // Ctrl -> Ctrl
485 // Shift -> Shift
486 // Alt -> Meta
487 if( mod == "Alt" )
488 mod = "Meta";
489
490 if( buf[0] )
491 strcat( buf, " " );
492
493 strcat( buf, mod.c_str() );
494
495 index = sep + 1;
496 }
497
498 return NULL;
499 #endif
500 }
501
502 XmString wxFindAcceleratorText (const char *s)
503 {
504 #if 1
505 wxUnusedVar(s);
506 // VZ: this function returns incorrect keysym which completely breaks kbd
507 // handling
508 return NULL;
509 #else
510 // The accelerator text is after the \t char.
511 s = strchr( s, '\t' );
512
513 if( !s ) return NULL;
514
515 return wxStringToXmString( s + 1 ); // skip TAB!
516 #endif
517 }
518
519 // Change a widget's foreground and background colours.
520 void wxDoChangeForegroundColour(WXWidget widget, wxColour& foregroundColour)
521 {
522 if (!foregroundColour.Ok())
523 return;
524
525 // When should we specify the foreground, if it's calculated
526 // by wxComputeColours?
527 // Solution: say we start with the default (computed) foreground colour.
528 // If we call SetForegroundColour explicitly for a control or window,
529 // then the foreground is changed.
530 // Therefore SetBackgroundColour computes the foreground colour, and
531 // SetForegroundColour changes the foreground colour. The ordering is
532 // important.
533
534 XtVaSetValues ((Widget) widget,
535 XmNforeground, foregroundColour.AllocColour(XtDisplay((Widget) widget)),
536 NULL);
537 }
538
539 void wxDoChangeBackgroundColour(WXWidget widget, const wxColour& backgroundColour, bool changeArmColour)
540 {
541 if (!backgroundColour.Ok())
542 return;
543
544 wxComputeColours (XtDisplay((Widget) widget), & backgroundColour,
545 NULL);
546
547 XtVaSetValues ((Widget) widget,
548 XmNbackground, g_itemColors[wxBACK_INDEX].pixel,
549 XmNtopShadowColor, g_itemColors[wxTOPS_INDEX].pixel,
550 XmNbottomShadowColor, g_itemColors[wxBOTS_INDEX].pixel,
551 XmNforeground, g_itemColors[wxFORE_INDEX].pixel,
552 NULL);
553
554 if (changeArmColour)
555 XtVaSetValues ((Widget) widget,
556 XmNarmColor, g_itemColors[wxSELE_INDEX].pixel,
557 NULL);
558 }
559
560 extern void wxDoChangeFont(WXWidget widget, const wxFont& font)
561 {
562 // Lesstif 0.87 hangs here, but 0.93 does not; MBN: sometimes it does
563 #if !wxCHECK_LESSTIF() // || wxCHECK_LESSTIF_VERSION( 0, 93 )
564 Widget w = (Widget)widget;
565 XtVaSetValues( w,
566 wxFont::GetFontTag(), font.GetFontTypeC( XtDisplay(w) ),
567 NULL );
568 #else
569 wxUnusedVar(widget);
570 wxUnusedVar(font);
571 #endif
572
573 }
574
575 wxString wxXmStringToString( const XmString& xmString )
576 {
577 char *txt;
578 if( XmStringGetLtoR( xmString, XmSTRING_DEFAULT_CHARSET, &txt ) )
579 {
580 wxString str(txt);
581 XtFree (txt);
582 return str;
583 }
584
585 return wxEmptyString;
586 }
587
588 XmString wxStringToXmString( const char* str )
589 {
590 return XmStringCreateLtoR((char *)str, XmSTRING_DEFAULT_CHARSET);
591 }
592
593 // ----------------------------------------------------------------------------
594 // wxBitmap utility functions
595 // ----------------------------------------------------------------------------
596
597 // Creates a bitmap with transparent areas drawn in
598 // the given colour.
599 wxBitmap wxCreateMaskedBitmap(const wxBitmap& bitmap, const wxColour& colour)
600 {
601 wxBitmap newBitmap(bitmap.GetWidth(),
602 bitmap.GetHeight(),
603 bitmap.GetDepth());
604 wxMemoryDC destDC;
605 wxMemoryDC srcDC;
606
607 srcDC.SelectObjectAsSource(bitmap);
608 destDC.SelectObject(newBitmap);
609
610 wxBrush brush(colour, wxSOLID);
611 destDC.SetBackground(brush);
612 destDC.Clear();
613 destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(),
614 &srcDC, 0, 0, wxCOPY, true);
615
616 return newBitmap;
617 }
618
619 // ----------------------------------------------------------------------------
620 // Miscellaneous functions
621 // ----------------------------------------------------------------------------
622
623 WXWidget wxCreateBorderWidget( WXWidget parent, long style )
624 {
625 Widget borderWidget = (Widget)NULL, parentWidget = (Widget)parent;
626
627 if (style & wxSIMPLE_BORDER)
628 {
629 borderWidget = XtVaCreateManagedWidget
630 (
631 "simpleBorder",
632 xmFrameWidgetClass, parentWidget,
633 XmNshadowType, XmSHADOW_ETCHED_IN,
634 XmNshadowThickness, 1,
635 NULL
636 );
637 }
638 else if ((style & wxSUNKEN_BORDER) || (style & wxBORDER_THEME))
639 {
640 borderWidget = XtVaCreateManagedWidget
641 (
642 "sunkenBorder",
643 xmFrameWidgetClass, parentWidget,
644 XmNshadowType, XmSHADOW_IN,
645 NULL
646 );
647 }
648 else if (style & wxRAISED_BORDER)
649 {
650 borderWidget = XtVaCreateManagedWidget
651 (
652 "raisedBorder",
653 xmFrameWidgetClass, parentWidget,
654 XmNshadowType, XmSHADOW_OUT,
655 NULL
656 );
657 }
658
659 return borderWidget;
660 }