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