]> git.saurik.com Git - wxWidgets.git/blob - src/motif/utils.cpp
preserve type when loaded image is rescaled, #11543
[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 wxString wxGetXEventName(XEvent& event)
379 {
380 #if wxUSE_NANOX
381 wxString str(wxT("(some event)"));
382 return str;
383 #else
384 int type = event.xany.type;
385 static char* event_name[] = {
386 wxMOTIF_STR(""), wxMOTIF_STR("unknown(-)"), // 0-1
387 wxMOTIF_STR("KeyPress"), wxMOTIF_STR("KeyRelease"), wxMOTIF_STR("ButtonPress"), wxMOTIF_STR("ButtonRelease"), // 2-5
388 wxMOTIF_STR("MotionNotify"), wxMOTIF_STR("EnterNotify"), wxMOTIF_STR("LeaveNotify"), wxMOTIF_STR("FocusIn"), // 6-9
389 wxMOTIF_STR("FocusOut"), wxMOTIF_STR("KeymapNotify"), wxMOTIF_STR("Expose"), wxMOTIF_STR("GraphicsExpose"), // 10-13
390 wxMOTIF_STR("NoExpose"), wxMOTIF_STR("VisibilityNotify"), wxMOTIF_STR("CreateNotify"), // 14-16
391 wxMOTIF_STR("DestroyNotify"), wxMOTIF_STR("UnmapNotify"), wxMOTIF_STR("MapNotify"), wxMOTIF_STR("MapRequest"),// 17-20
392 wxMOTIF_STR("ReparentNotify"), wxMOTIF_STR("ConfigureNotify"), wxMOTIF_STR("ConfigureRequest"), // 21-23
393 wxMOTIF_STR("GravityNotify"), wxMOTIF_STR("ResizeRequest"), wxMOTIF_STR("CirculateNotify"), // 24-26
394 wxMOTIF_STR("CirculateRequest"), wxMOTIF_STR("PropertyNotify"), wxMOTIF_STR("SelectionClear"), // 27-29
395 wxMOTIF_STR("SelectionRequest"), wxMOTIF_STR("SelectionNotify"), wxMOTIF_STR("ColormapNotify"), // 30-32
396 wxMOTIF_STR("ClientMessage"), wxMOTIF_STR("MappingNotify"), // 33-34
397 wxMOTIF_STR("unknown(+)")}; // 35
398 type = wxMin(35, type); type = wxMax(1, type);
399 wxString str(event_name[type]);
400 return str;
401 #endif
402 }
403
404 // ----------------------------------------------------------------------------
405 // accelerators
406 // ----------------------------------------------------------------------------
407
408 // Find the letter corresponding to the mnemonic, for Motif
409 char wxFindMnemonic (const char *s)
410 {
411 char mnem = 0;
412 int len = strlen (s);
413 int i;
414
415 for (i = 0; i < len; i++)
416 {
417 if (s[i] == '&')
418 {
419 // Carefully handle &&
420 if ((i + 1) <= len && s[i + 1] == '&')
421 i++;
422 else
423 {
424 mnem = s[i + 1];
425 break;
426 }
427 }
428 }
429 return mnem;
430 }
431
432 char* wxFindAccelerator( const char *s )
433 {
434 #if 1
435 wxUnusedVar(s);
436 // VZ: this function returns incorrect keysym which completely breaks kbd
437 // handling
438 return NULL;
439 #else
440 // The accelerator text is after the \t char.
441 s = strchr( s, '\t' );
442
443 if( !s ) return NULL;
444
445 /*
446 Now we need to format it as X standard:
447
448 input output
449
450 F7 --> <Key>F7
451 Ctrl+N --> Ctrl<Key>N
452 Alt+k --> Meta<Key>k
453 Ctrl+Shift+A --> Ctrl Shift<Key>A
454
455 and handle Ctrl-N & similia
456 */
457
458 static char buf[256];
459
460 buf[0] = '\0';
461 wxString tmp = s + 1; // skip TAB
462 size_t index = 0;
463
464 while( index < tmp.length() )
465 {
466 size_t plus = tmp.find( '+', index );
467 size_t minus = tmp.find( '-', index );
468
469 // neither '+' nor '-', add <Key>
470 if( plus == wxString::npos && minus == wxString::npos )
471 {
472 strcat( buf, "<Key>" );
473 strcat( buf, tmp.c_str() + index );
474
475 return buf;
476 }
477
478 // OK: npos is big and positive
479 size_t sep = wxMin( plus, minus );
480 wxString mod = tmp.substr( index, sep - index );
481
482 // Ctrl -> Ctrl
483 // Shift -> Shift
484 // Alt -> Meta
485 if( mod == "Alt" )
486 mod = "Meta";
487
488 if( buf[0] )
489 strcat( buf, " " );
490
491 strcat( buf, mod.c_str() );
492
493 index = sep + 1;
494 }
495
496 return NULL;
497 #endif
498 }
499
500 XmString wxFindAcceleratorText (const char *s)
501 {
502 #if 1
503 wxUnusedVar(s);
504 // VZ: this function returns incorrect keysym which completely breaks kbd
505 // handling
506 return NULL;
507 #else
508 // The accelerator text is after the \t char.
509 s = strchr( s, '\t' );
510
511 if( !s ) return NULL;
512
513 return wxStringToXmString( s + 1 ); // skip TAB!
514 #endif
515 }
516
517 // Change a widget's foreground and background colours.
518 void wxDoChangeForegroundColour(WXWidget widget, wxColour& foregroundColour)
519 {
520 if (!foregroundColour.Ok())
521 return;
522
523 // When should we specify the foreground, if it's calculated
524 // by wxComputeColours?
525 // Solution: say we start with the default (computed) foreground colour.
526 // If we call SetForegroundColour explicitly for a control or window,
527 // then the foreground is changed.
528 // Therefore SetBackgroundColour computes the foreground colour, and
529 // SetForegroundColour changes the foreground colour. The ordering is
530 // important.
531
532 XtVaSetValues ((Widget) widget,
533 XmNforeground, foregroundColour.AllocColour(XtDisplay((Widget) widget)),
534 NULL);
535 }
536
537 void wxDoChangeBackgroundColour(WXWidget widget, const wxColour& backgroundColour, bool changeArmColour)
538 {
539 if (!backgroundColour.Ok())
540 return;
541
542 wxComputeColours (XtDisplay((Widget) widget), & backgroundColour,
543 NULL);
544
545 XtVaSetValues ((Widget) widget,
546 XmNbackground, g_itemColors[wxBACK_INDEX].pixel,
547 XmNtopShadowColor, g_itemColors[wxTOPS_INDEX].pixel,
548 XmNbottomShadowColor, g_itemColors[wxBOTS_INDEX].pixel,
549 XmNforeground, g_itemColors[wxFORE_INDEX].pixel,
550 NULL);
551
552 if (changeArmColour)
553 XtVaSetValues ((Widget) widget,
554 XmNarmColor, g_itemColors[wxSELE_INDEX].pixel,
555 NULL);
556 }
557
558 extern void wxDoChangeFont(WXWidget widget, const wxFont& font)
559 {
560 // Lesstif 0.87 hangs here, but 0.93 does not; MBN: sometimes it does
561 #if !wxCHECK_LESSTIF() // || wxCHECK_LESSTIF_VERSION( 0, 93 )
562 Widget w = (Widget)widget;
563 XtVaSetValues( w,
564 wxFont::GetFontTag(), font.GetFontTypeC( XtDisplay(w) ),
565 NULL );
566 #else
567 wxUnusedVar(widget);
568 wxUnusedVar(font);
569 #endif
570
571 }
572
573 wxString wxXmStringToString( const XmString& xmString )
574 {
575 char *txt;
576 if( XmStringGetLtoR( xmString, XmSTRING_DEFAULT_CHARSET, &txt ) )
577 {
578 wxString str(txt);
579 XtFree (txt);
580 return str;
581 }
582
583 return wxEmptyString;
584 }
585
586 XmString wxStringToXmString( const char* str )
587 {
588 return XmStringCreateLtoR((char *)str, XmSTRING_DEFAULT_CHARSET);
589 }
590
591 // ----------------------------------------------------------------------------
592 // wxBitmap utility functions
593 // ----------------------------------------------------------------------------
594
595 // Creates a bitmap with transparent areas drawn in
596 // the given colour.
597 wxBitmap wxCreateMaskedBitmap(const wxBitmap& bitmap, const wxColour& colour)
598 {
599 wxBitmap newBitmap(bitmap.GetWidth(),
600 bitmap.GetHeight(),
601 bitmap.GetDepth());
602 wxMemoryDC destDC;
603 wxMemoryDC srcDC;
604
605 srcDC.SelectObjectAsSource(bitmap);
606 destDC.SelectObject(newBitmap);
607
608 wxBrush brush(colour, wxSOLID);
609 destDC.SetBackground(brush);
610 destDC.Clear();
611 destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(),
612 &srcDC, 0, 0, wxCOPY, true);
613
614 return newBitmap;
615 }
616
617 // ----------------------------------------------------------------------------
618 // Miscellaneous functions
619 // ----------------------------------------------------------------------------
620
621 WXWidget wxCreateBorderWidget( WXWidget parent, long style )
622 {
623 Widget borderWidget = (Widget)NULL, parentWidget = (Widget)parent;
624
625 if (style & wxSIMPLE_BORDER)
626 {
627 borderWidget = XtVaCreateManagedWidget
628 (
629 "simpleBorder",
630 xmFrameWidgetClass, parentWidget,
631 XmNshadowType, XmSHADOW_ETCHED_IN,
632 XmNshadowThickness, 1,
633 NULL
634 );
635 }
636 else if ((style & wxSUNKEN_BORDER) || (style & wxBORDER_THEME))
637 {
638 borderWidget = XtVaCreateManagedWidget
639 (
640 "sunkenBorder",
641 xmFrameWidgetClass, parentWidget,
642 XmNshadowType, XmSHADOW_IN,
643 NULL
644 );
645 }
646 else if (style & wxRAISED_BORDER)
647 {
648 borderWidget = XtVaCreateManagedWidget
649 (
650 "raisedBorder",
651 xmFrameWidgetClass, parentWidget,
652 XmNshadowType, XmSHADOW_OUT,
653 NULL
654 );
655 }
656
657 return borderWidget;
658 }