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