Mercurial > projects > dwt2
annotate org.eclipse.swt.gtk.linux.x86/src/org/eclipse/swt/widgets/Shell.d @ 49:7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Fri, 27 Mar 2009 12:59:54 +0100 |
parents | ddbfe84d86df |
children | c01d033c633a |
rev | line source |
---|---|
25 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.widgets.Shell; | |
14 | |
15 import java.lang.all; | |
16 | |
17 import org.eclipse.swt.widgets.Composite; | |
18 import org.eclipse.swt.widgets.Control; | |
49
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
19 //import org.eclipse.swt.internal.c.gtk; |
25 | 20 |
21 import org.eclipse.swt.SWT; | |
22 import org.eclipse.swt.internal.gtk.OS; | |
23 import org.eclipse.swt.events.ShellListener; | |
24 import org.eclipse.swt.graphics.Cursor; | |
25 import org.eclipse.swt.graphics.GC; | |
26 import org.eclipse.swt.graphics.Image; | |
27 import org.eclipse.swt.graphics.Point; | |
28 import org.eclipse.swt.graphics.Rectangle; | |
29 import org.eclipse.swt.graphics.Region; | |
30 import org.eclipse.swt.internal.Converter; | |
31 import org.eclipse.swt.internal.SWTEventListener; | |
32 import org.eclipse.swt.widgets.Composite; | |
33 import org.eclipse.swt.widgets.Control; | |
34 import org.eclipse.swt.widgets.Decorations; | |
35 import org.eclipse.swt.widgets.Display; | |
36 import org.eclipse.swt.widgets.Event; | |
37 import org.eclipse.swt.widgets.EventTable; | |
38 import org.eclipse.swt.widgets.Layout; | |
39 import org.eclipse.swt.widgets.Listener; | |
40 import org.eclipse.swt.widgets.Menu; | |
41 import org.eclipse.swt.widgets.Monitor; | |
42 import org.eclipse.swt.widgets.TypedListener; | |
43 import org.eclipse.swt.widgets.Widget; | |
44 | |
48 | 45 version(Tango){ |
25 | 46 import Unicode = tango.text.Unicode; |
48 | 47 } else { // Phobos |
48 } | |
25 | 49 |
50 /** | |
51 * Instances of this class represent the "windows" | |
52 * which the desktop or "window manager" is managing. | |
53 * Instances that do not have a parent (that is, they | |
54 * are built using the constructor, which takes a | |
55 * <code>Display</code> as the argument) are described | |
56 * as <em>top level</em> shells. Instances that do have | |
57 * a parent are described as <em>secondary</em> or | |
58 * <em>dialog</em> shells. | |
59 * <p> | |
60 * Instances are always displayed in one of the maximized, | |
61 * minimized or normal states: | |
62 * <ul> | |
63 * <li> | |
64 * When an instance is marked as <em>maximized</em>, the | |
65 * window manager will typically resize it to fill the | |
66 * entire visible area of the display, and the instance | |
67 * is usually put in a state where it can not be resized | |
68 * (even if it has style <code>RESIZE</code>) until it is | |
69 * no longer maximized. | |
70 * </li><li> | |
71 * When an instance is in the <em>normal</em> state (neither | |
72 * maximized or minimized), its appearance is controlled by | |
73 * the style constants which were specified when it was created | |
74 * and the restrictions of the window manager (see below). | |
75 * </li><li> | |
76 * When an instance has been marked as <em>minimized</em>, | |
77 * its contents (client area) will usually not be visible, | |
78 * and depending on the window manager, it may be | |
79 * "iconified" (that is, replaced on the desktop by a small | |
80 * simplified representation of itself), relocated to a | |
81 * distinguished area of the screen, or hidden. Combinations | |
82 * of these changes are also possible. | |
83 * </li> | |
84 * </ul> | |
85 * </p><p> | |
86 * The <em>modality</em> of an instance may be specified using | |
87 * style bits. The modality style bits are used to determine | |
88 * whether input is blocked for other shells on the display. | |
89 * The <code>PRIMARY_MODAL</code> style allows an instance to block | |
90 * input to its parent. The <code>APPLICATION_MODAL</code> style | |
91 * allows an instance to block input to every other shell in the | |
92 * display. The <code>SYSTEM_MODAL</code> style allows an instance | |
93 * to block input to all shells, including shells belonging to | |
94 * different applications. | |
95 * </p><p> | |
96 * Note: The styles supported by this class are treated | |
97 * as <em>HINT</em>s, since the window manager for the | |
98 * desktop on which the instance is visible has ultimate | |
99 * control over the appearance and behavior of decorations | |
100 * and modality. For example, some window managers only | |
101 * support resizable windows and will always assume the | |
102 * RESIZE style, even if it is not set. In addition, if a | |
103 * modality style is not supported, it is "upgraded" to a | |
104 * more restrictive modality style that is supported. For | |
105 * example, if <code>PRIMARY_MODAL</code> is not supported, | |
106 * it would be upgraded to <code>APPLICATION_MODAL</code>. | |
107 * A modality style may also be "downgraded" to a less | |
108 * restrictive style. For example, most operating systems | |
109 * no longer support <code>SYSTEM_MODAL</code> because | |
110 * it can freeze up the desktop, so this is typically | |
111 * downgraded to <code>APPLICATION_MODAL</code>. | |
112 * <dl> | |
113 * <dt><b>Styles:</b></dt> | |
114 * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd> | |
115 * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd> | |
116 * <dt><b>Events:</b></dt> | |
117 * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd> | |
118 * </dl> | |
119 * Class <code>SWT</code> provides two "convenience constants" | |
120 * for the most commonly required style combinations: | |
121 * <dl> | |
122 * <dt><code>SHELL_TRIM</code></dt> | |
123 * <dd> | |
124 * the result of combining the constants which are required | |
125 * to produce a typical application top level shell: (that | |
126 * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>) | |
127 * </dd> | |
128 * <dt><code>DIALOG_TRIM</code></dt> | |
129 * <dd> | |
130 * the result of combining the constants which are required | |
131 * to produce a typical application dialog shell: (that | |
132 * is, <code>TITLE | CLOSE | BORDER</code>) | |
133 * </dd> | |
134 * </dl> | |
135 * </p> | |
136 * <p> | |
137 * Note: Only one of the styles APPLICATION_MODAL, MODELESS, | |
138 * PRIMARY_MODAL and SYSTEM_MODAL may be specified. | |
139 * </p><p> | |
140 * IMPORTANT: This class is not intended to be subclassed. | |
141 * </p> | |
142 * | |
143 * @see Decorations | |
144 * @see SWT | |
145 * @see <a href="http://www.eclipse.org/swt/snippets/#shell">Shell snippets</a> | |
146 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a> | |
147 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
148 */ | |
149 public class Shell : Decorations { | |
150 | |
151 alias Decorations.createHandle createHandle; | |
152 alias Decorations.fixStyle fixStyle; | |
153 alias Decorations.setBounds setBounds; | |
154 alias Decorations.setCursor setCursor; | |
155 alias Decorations.setToolTipText setToolTipText; | |
156 alias Decorations.setZOrder setZOrder; | |
157 | |
158 GtkWidget* shellHandle, tooltipsHandle, tooltipWindow, group, modalGroup; | |
159 bool mapped, moved, resized, opened, fullScreen, showWithParent; | |
160 | |
161 int oldX, oldY, oldWidth, oldHeight; | |
162 int minWidth, minHeight; | |
163 Control lastActive; | |
164 CallbackData filterProcCallbackData; | |
165 CallbackData sizeAllocateProcCallbackData; | |
166 CallbackData sizeRequestProcCallbackData; | |
167 | |
168 static const int MAXIMUM_TRIM = 128; | |
169 | |
170 /** | |
171 * Constructs a new instance of this class. This is equivalent | |
172 * to calling <code>Shell((Display) null)</code>. | |
173 * | |
174 * @exception SWTException <ul> | |
175 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
176 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
177 * </ul> | |
178 */ | |
179 public this () { | |
180 this (cast(Display) null); | |
181 } | |
182 /** | |
183 * Constructs a new instance of this class given only the style | |
184 * value describing its behavior and appearance. This is equivalent | |
185 * to calling <code>Shell((Display) null, style)</code>. | |
186 * <p> | |
187 * The style value is either one of the style constants defined in | |
188 * class <code>SWT</code> which is applicable to instances of this | |
189 * class, or must be built by <em>bitwise OR</em>'ing together | |
190 * (that is, using the <code>int</code> "|" operator) two or more | |
191 * of those <code>SWT</code> style constants. The class description | |
192 * lists the style constants that are applicable to the class. | |
193 * Style bits are also inherited from superclasses. | |
194 * </p> | |
195 * | |
196 * @param style the style of control to construct | |
197 * | |
198 * @exception SWTException <ul> | |
199 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
200 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
201 * </ul> | |
202 * | |
203 * @see SWT#BORDER | |
204 * @see SWT#CLOSE | |
205 * @see SWT#MIN | |
206 * @see SWT#MAX | |
207 * @see SWT#RESIZE | |
208 * @see SWT#TITLE | |
209 * @see SWT#NO_TRIM | |
210 * @see SWT#SHELL_TRIM | |
211 * @see SWT#DIALOG_TRIM | |
212 * @see SWT#MODELESS | |
213 * @see SWT#PRIMARY_MODAL | |
214 * @see SWT#APPLICATION_MODAL | |
215 * @see SWT#SYSTEM_MODAL | |
216 */ | |
217 public this (int style) { | |
218 this (cast(Display) null, style); | |
219 } | |
220 | |
221 /** | |
222 * Constructs a new instance of this class given only the display | |
223 * to create it on. It is created with style <code>SWT.SHELL_TRIM</code>. | |
224 * <p> | |
225 * Note: Currently, null can be passed in for the display argument. | |
226 * This has the effect of creating the shell on the currently active | |
227 * display if there is one. If there is no current display, the | |
228 * shell is created on a "default" display. <b>Passing in null as | |
229 * the display argument is not considered to be good coding style, | |
230 * and may not be supported in a future release of SWT.</b> | |
231 * </p> | |
232 * | |
233 * @param display the display to create the shell on | |
234 * | |
235 * @exception SWTException <ul> | |
236 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
237 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
238 * </ul> | |
239 */ | |
240 public this (Display display) { | |
241 this (display, SWT.SHELL_TRIM); | |
242 } | |
243 /** | |
244 * Constructs a new instance of this class given the display | |
245 * to create it on and a style value describing its behavior | |
246 * and appearance. | |
247 * <p> | |
248 * The style value is either one of the style constants defined in | |
249 * class <code>SWT</code> which is applicable to instances of this | |
250 * class, or must be built by <em>bitwise OR</em>'ing together | |
251 * (that is, using the <code>int</code> "|" operator) two or more | |
252 * of those <code>SWT</code> style constants. The class description | |
253 * lists the style constants that are applicable to the class. | |
254 * Style bits are also inherited from superclasses. | |
255 * </p><p> | |
256 * Note: Currently, null can be passed in for the display argument. | |
257 * This has the effect of creating the shell on the currently active | |
258 * display if there is one. If there is no current display, the | |
259 * shell is created on a "default" display. <b>Passing in null as | |
260 * the display argument is not considered to be good coding style, | |
261 * and may not be supported in a future release of SWT.</b> | |
262 * </p> | |
263 * | |
264 * @param display the display to create the shell on | |
265 * @param style the style of control to construct | |
266 * | |
267 * @exception SWTException <ul> | |
268 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
269 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
270 * </ul> | |
271 * | |
272 * @see SWT#BORDER | |
273 * @see SWT#CLOSE | |
274 * @see SWT#MIN | |
275 * @see SWT#MAX | |
276 * @see SWT#RESIZE | |
277 * @see SWT#TITLE | |
278 * @see SWT#NO_TRIM | |
279 * @see SWT#SHELL_TRIM | |
280 * @see SWT#DIALOG_TRIM | |
281 * @see SWT#MODELESS | |
282 * @see SWT#PRIMARY_MODAL | |
283 * @see SWT#APPLICATION_MODAL | |
284 * @see SWT#SYSTEM_MODAL | |
285 */ | |
286 public this (Display display, int style) { | |
287 this (display, null, style, null, false); | |
288 } | |
289 | |
290 this (Display display, Shell parent, int style, GtkWidget* handle, bool embedded) { | |
291 super (); | |
292 checkSubclass (); | |
293 if (display is null) display = Display.getCurrent (); | |
294 if (display is null) display = Display.getDefault (); | |
295 if (!display.isValidThread ()) { | |
296 error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
297 } | |
298 if (parent !is null && parent.isDisposed ()) { | |
299 error (SWT.ERROR_INVALID_ARGUMENT); | |
300 } | |
301 this.style = checkStyle (style); | |
302 this.parent = parent; | |
303 this.display = display; | |
304 if (handle !is null) { | |
305 if (embedded) { | |
306 this.handle = handle; | |
307 } else { | |
308 shellHandle = handle; | |
309 state |= FOREIGN_HANDLE; | |
310 } | |
311 } | |
312 createWidget (0); | |
313 } | |
314 | |
315 /** | |
316 * Constructs a new instance of this class given only its | |
317 * parent. It is created with style <code>SWT.DIALOG_TRIM</code>. | |
318 * <p> | |
319 * Note: Currently, null can be passed in for the parent. | |
320 * This has the effect of creating the shell on the currently active | |
321 * display if there is one. If there is no current display, the | |
322 * shell is created on a "default" display. <b>Passing in null as | |
323 * the parent is not considered to be good coding style, | |
324 * and may not be supported in a future release of SWT.</b> | |
325 * </p> | |
326 * | |
327 * @param parent a shell which will be the parent of the new instance | |
328 * | |
329 * @exception IllegalArgumentException <ul> | |
330 * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> | |
331 * </ul> | |
332 * @exception SWTException <ul> | |
333 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
334 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
335 * </ul> | |
336 */ | |
337 public this (Shell parent) { | |
338 this (parent, SWT.DIALOG_TRIM); | |
339 } | |
340 | |
341 /** | |
342 * Constructs a new instance of this class given its parent | |
343 * and a style value describing its behavior and appearance. | |
344 * <p> | |
345 * The style value is either one of the style constants defined in | |
346 * class <code>SWT</code> which is applicable to instances of this | |
347 * class, or must be built by <em>bitwise OR</em>'ing together | |
348 * (that is, using the <code>int</code> "|" operator) two or more | |
349 * of those <code>SWT</code> style constants. The class description | |
350 * lists the style constants that are applicable to the class. | |
351 * Style bits are also inherited from superclasses. | |
352 * </p><p> | |
353 * Note: Currently, null can be passed in for the parent. | |
354 * This has the effect of creating the shell on the currently active | |
355 * display if there is one. If there is no current display, the | |
356 * shell is created on a "default" display. <b>Passing in null as | |
357 * the parent is not considered to be good coding style, | |
358 * and may not be supported in a future release of SWT.</b> | |
359 * </p> | |
360 * | |
361 * @param parent a shell which will be the parent of the new instance | |
362 * @param style the style of control to construct | |
363 * | |
364 * @exception IllegalArgumentException <ul> | |
365 * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> | |
366 * </ul> | |
367 * @exception SWTException <ul> | |
368 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
369 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
370 * </ul> | |
371 * | |
372 * @see SWT#BORDER | |
373 * @see SWT#CLOSE | |
374 * @see SWT#MIN | |
375 * @see SWT#MAX | |
376 * @see SWT#RESIZE | |
377 * @see SWT#TITLE | |
378 * @see SWT#NO_TRIM | |
379 * @see SWT#SHELL_TRIM | |
380 * @see SWT#DIALOG_TRIM | |
381 * @see SWT#ON_TOP | |
382 * @see SWT#TOOL | |
383 * @see SWT#MODELESS | |
384 * @see SWT#PRIMARY_MODAL | |
385 * @see SWT#APPLICATION_MODAL | |
386 * @see SWT#SYSTEM_MODAL | |
387 */ | |
388 public this (Shell parent, int style) { | |
389 this (parent !is null ? parent.display : null, parent, style, null, false); | |
390 } | |
391 | |
392 public static Shell gtk_new (Display display, GtkWidget* handle) { | |
393 return new Shell (display, null, SWT.NO_TRIM, handle, true); | |
394 } | |
395 | |
396 /** | |
397 * Invokes platform specific functionality to allocate a new shell | |
398 * that is not embedded. | |
399 * <p> | |
400 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
401 * API for <code>Shell</code>. It is marked public only so that it | |
402 * can be shared within the packages provided by SWT. It is not | |
403 * available on all platforms, and should never be called from | |
404 * application code. | |
405 * </p> | |
406 * | |
407 * @param display the display for the shell | |
408 * @param handle the handle for the shell | |
409 * @return a new shell object containing the specified display and handle | |
410 * | |
411 * @since 3.3 | |
412 */ | |
413 public static Shell internal_new (Display display, GtkWidget* handle) { | |
414 return new Shell (display, null, SWT.NO_TRIM, handle, false); | |
415 } | |
416 | |
417 static int checkStyle (int style) { | |
418 style = Decorations.checkStyle (style); | |
419 style &= ~SWT.TRANSPARENT; | |
420 if ((style & SWT.ON_TOP) !is 0) style &= ~SWT.SHELL_TRIM; | |
421 int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL; | |
422 int bits = style & ~mask; | |
423 if ((style & SWT.SYSTEM_MODAL) !is 0) return bits | SWT.SYSTEM_MODAL; | |
424 if ((style & SWT.APPLICATION_MODAL) !is 0) return bits | SWT.APPLICATION_MODAL; | |
425 if ((style & SWT.PRIMARY_MODAL) !is 0) return bits | SWT.PRIMARY_MODAL; | |
426 return bits; | |
427 } | |
428 | |
429 /** | |
430 * Adds the listener to the collection of listeners who will | |
431 * be notified when operations are performed on the receiver, | |
432 * by sending the listener one of the messages defined in the | |
433 * <code>ShellListener</code> interface. | |
434 * | |
435 * @param listener the listener which should be notified | |
436 * | |
437 * @exception IllegalArgumentException <ul> | |
438 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
439 * </ul> | |
440 * @exception SWTException <ul> | |
441 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
442 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
443 * </ul> | |
444 * | |
445 * @see ShellListener | |
446 * @see #removeShellListener | |
447 */ | |
448 public void addShellListener (ShellListener listener) { | |
449 checkWidget(); | |
450 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
451 TypedListener typedListener = new TypedListener (listener); | |
452 addListener (SWT.Close,typedListener); | |
453 addListener (SWT.Iconify,typedListener); | |
454 addListener (SWT.Deiconify,typedListener); | |
455 addListener (SWT.Activate, typedListener); | |
456 addListener (SWT.Deactivate, typedListener); | |
457 } | |
458 | |
459 void adjustTrim () { | |
460 if (display.ignoreTrim) return; | |
461 int width = OS.GTK_WIDGET_WIDTH (shellHandle); | |
462 int height = OS.GTK_WIDGET_HEIGHT (shellHandle); | |
463 auto window = OS.GTK_WIDGET_WINDOW (shellHandle); | |
464 GdkRectangle* rect = new GdkRectangle (); | |
465 OS.gdk_window_get_frame_extents (window, rect); | |
466 int trimWidth = Math.max (0, rect.width - width); | |
467 int trimHeight = Math.max (0, rect.height - height); | |
468 /* | |
469 * Bug in GTK. gdk_window_get_frame_extents() fails for various window | |
470 * managers, causing a large incorrect value to be returned as the trim. | |
471 * The fix is to ignore the returned trim values if they are too large. | |
472 */ | |
473 if (trimWidth > MAXIMUM_TRIM || trimHeight > MAXIMUM_TRIM) { | |
474 display.ignoreTrim = true; | |
475 return; | |
476 } | |
477 bool hasTitle = false, hasResize = false, hasBorder = false; | |
478 if ((style & SWT.NO_TRIM) is 0) { | |
479 hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) !is 0; | |
480 hasResize = (style & SWT.RESIZE) !is 0; | |
481 hasBorder = (style & SWT.BORDER) !is 0; | |
482 } | |
483 if (hasTitle) { | |
484 if (hasResize) { | |
485 display.titleResizeTrimWidth = trimWidth; | |
486 display.titleResizeTrimHeight = trimHeight; | |
487 return; | |
488 } | |
489 if (hasBorder) { | |
490 display.titleBorderTrimWidth = trimWidth; | |
491 display.titleBorderTrimHeight = trimHeight; | |
492 return; | |
493 } | |
494 display.titleTrimWidth = trimWidth; | |
495 display.titleTrimHeight = trimHeight; | |
496 return; | |
497 } | |
498 if (hasResize) { | |
499 display.resizeTrimWidth = trimWidth; | |
500 display.resizeTrimHeight = trimHeight; | |
501 return; | |
502 } | |
503 if (hasBorder) { | |
504 display.borderTrimWidth = trimWidth; | |
505 display.borderTrimHeight = trimHeight; | |
506 return; | |
507 } | |
508 } | |
509 | |
510 void bringToTop (bool force) { | |
511 if (!OS.GTK_WIDGET_VISIBLE (shellHandle)) return; | |
512 Display display = this.display; | |
513 Shell activeShell = display.activeShell; | |
514 if (activeShell is this) return; | |
515 if (!force) { | |
516 if (activeShell is null) return; | |
517 if (!display.activePending) { | |
518 auto focusHandle = OS.gtk_window_get_focus (cast(GtkWindow*)activeShell.shellHandle); | |
519 if (focusHandle !is null && !OS.GTK_WIDGET_HAS_FOCUS (focusHandle)) return; | |
520 } | |
521 } | |
522 /* | |
523 * Bug in GTK. When a shell that is not managed by the window | |
524 * manage is given focus, GTK gets stuck in "focus follows pointer" | |
525 * mode when the pointer is within the shell and its parent when | |
526 * the shell is hidden or disposed. The fix is to use XSetInputFocus() | |
527 * to assign focus when ever the active shell has not managed by | |
528 * the window manager. | |
529 * | |
530 * NOTE: This bug is fixed in GTK+ 2.6.8 and above. | |
531 */ | |
532 bool xFocus = false; | |
533 if (activeShell !is null) { | |
534 if (OS.GTK_VERSION < OS.buildVERSION (2, 6, 8)) { | |
535 xFocus = activeShell.isUndecorated (); | |
536 } | |
537 display.activeShell = null; | |
538 display.activePending = true; | |
539 } | |
540 /* | |
541 * Feature in GTK. When the shell is an override redirect | |
542 * window, gdk_window_focus() does not give focus to the | |
543 * window. The fix is to use XSetInputFocus() to force | |
544 * the focus. | |
545 */ | |
546 auto window = OS.GTK_WIDGET_WINDOW (shellHandle); | |
547 if ((xFocus || (style & SWT.ON_TOP) !is 0) && OS.GDK_WINDOWING_X11 ()) { | |
548 auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (window); | |
549 auto xWindow = OS.gdk_x11_drawable_get_xid (window); | |
550 OS.gdk_error_trap_push (); | |
551 /* Use CurrentTime instead of the last event time to ensure that the shell becomes active */ | |
552 OS.XSetInputFocus (xDisplay, xWindow, OS.RevertToParent, OS.CurrentTime); | |
553 OS.gdk_error_trap_pop (); | |
554 } else { | |
555 /* | |
556 * Bug in metacity. Calling gdk_window_focus() with a timestamp more | |
557 * recent than the last user interaction time can cause windows not | |
558 * to come forward in versions > 2.10.0. The fix is to use the last | |
559 * user event time. | |
560 */ | |
561 if ( Unicode.toLower( display.windowManager ) ==/*eq*/ "metacity") { | |
562 OS.gdk_window_focus (window, display.lastUserEventTime); | |
563 } else { | |
564 OS.gdk_window_focus (window, OS.GDK_CURRENT_TIME); | |
565 } | |
566 } | |
567 display.activeShell = this; | |
568 display.activePending = true; | |
569 } | |
570 | |
571 override void checkBorder () { | |
572 /* Do nothing */ | |
573 } | |
574 | |
575 override void checkOpen () { | |
576 if (!opened) resized = false; | |
577 } | |
578 | |
579 override GtkStyle* childStyle () { | |
580 return null; | |
581 } | |
582 | |
583 /** | |
584 * Requests that the window manager close the receiver in | |
585 * the same way it would be closed when the user clicks on | |
586 * the "close box" or performs some other platform specific | |
587 * key or mouse combination that indicates the window | |
588 * should be removed. | |
589 * | |
590 * @exception SWTException <ul> | |
591 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
592 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
593 * </ul> | |
594 * | |
595 * @see SWT#Close | |
596 * @see #dispose | |
597 */ | |
598 public void close () { | |
599 checkWidget (); | |
600 closeWidget (); | |
601 } | |
602 | |
603 void closeWidget () { | |
604 Event event = new Event (); | |
605 sendEvent (SWT.Close, event); | |
606 if (event.doit && !isDisposed ()) dispose (); | |
607 } | |
608 | |
609 override public Rectangle computeTrim (int x, int y, int width, int height) { | |
610 checkWidget(); | |
611 Rectangle trim = super.computeTrim (x, y, width, height); | |
612 int border = 0; | |
613 if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) { | |
614 border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle); | |
615 } | |
616 int trimWidth = trimWidth (), trimHeight = trimHeight (); | |
617 trim.x -= (trimWidth / 2) + border; | |
618 trim.y -= trimHeight - (trimWidth / 2) + border; | |
619 trim.width += trimWidth + border * 2; | |
620 trim.height += trimHeight + border * 2; | |
621 if (menuBar !is null) { | |
622 forceResize (); | |
623 int menuBarHeight = OS.GTK_WIDGET_HEIGHT (menuBar.handle); | |
624 trim.y -= menuBarHeight; | |
625 trim.height += menuBarHeight; | |
626 } | |
627 return trim; | |
628 } | |
629 | |
630 override void createHandle (int index) { | |
631 state |= HANDLE | CANVAS; | |
632 if (shellHandle is null) { | |
633 if (handle is null) { | |
634 int type = OS.GTK_WINDOW_TOPLEVEL; | |
635 if ((style & SWT.ON_TOP) !is 0) type = OS.GTK_WINDOW_POPUP; | |
636 shellHandle = cast(GtkWidget*)OS.gtk_window_new (type); | |
637 } else { | |
638 shellHandle = cast(GtkWidget*) OS.gtk_plug_new (cast(uint)handle); | |
639 } | |
640 if (shellHandle is null) error (SWT.ERROR_NO_HANDLES); | |
641 if (parent !is null) { | |
642 OS.gtk_window_set_transient_for (cast(GtkWindow*)shellHandle, cast(GtkWindow*)parent.topHandle ()); | |
643 OS.gtk_window_set_destroy_with_parent (cast(GtkWindow*)shellHandle, true); | |
644 if (!isUndecorated ()) { | |
645 OS.gtk_window_set_type_hint (cast(GtkWindow*)shellHandle, OS.GDK_WINDOW_TYPE_HINT_DIALOG); | |
646 } else { | |
647 if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 0)) { | |
648 OS.gtk_window_set_skip_taskbar_hint (cast(GtkWindow*)shellHandle, true); | |
649 } | |
650 } | |
651 } | |
652 /* | |
653 * Feature in GTK. The window size must be set when the window | |
654 * is created or it will not be allowed to be resized smaller that the | |
655 * initial size by the user. The fix is to set the size to zero. | |
656 */ | |
657 if ((style & SWT.RESIZE) !is 0) { | |
658 OS.gtk_widget_set_size_request (shellHandle, 0, 0); | |
659 OS.gtk_window_set_resizable (cast(GtkWindow*)shellHandle, true); | |
660 } else { | |
661 OS.gtk_window_set_resizable (cast(GtkWindow*)shellHandle, false); | |
662 } | |
663 vboxHandle = OS.gtk_vbox_new (false, 0); | |
664 if (vboxHandle is null) error (SWT.ERROR_NO_HANDLES); | |
665 createHandle (index, false, true); | |
666 OS.gtk_container_add (cast(GtkContainer*)vboxHandle, scrolledHandle); | |
667 OS.gtk_box_set_child_packing (cast(GtkBox*)vboxHandle, scrolledHandle, true, true, 0, OS.GTK_PACK_END); | |
668 String dummy = "a"; | |
669 OS.gtk_window_set_title (cast(GtkWindow*)shellHandle, dummy.ptr ); | |
670 if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) { | |
671 OS.gtk_container_set_border_width (cast(GtkContainer*)shellHandle, 1); | |
672 GdkColor* color = new GdkColor (); | |
673 OS.gtk_style_get_black (OS.gtk_widget_get_style (shellHandle), color); | |
674 OS.gtk_widget_modify_bg (shellHandle, OS.GTK_STATE_NORMAL, color); | |
675 } | |
676 } else { | |
677 vboxHandle = OS.gtk_bin_get_child (cast(GtkBin*)shellHandle); | |
678 if (vboxHandle is null) error (SWT.ERROR_NO_HANDLES); | |
679 auto children = OS.gtk_container_get_children (cast(GtkContainer*)vboxHandle); | |
680 if (OS.g_list_length (children) > 0) { | |
681 scrolledHandle = cast(GtkWidget*)OS.g_list_data (children); | |
682 } | |
683 OS.g_list_free (children); | |
684 if (scrolledHandle is null) error (SWT.ERROR_NO_HANDLES); | |
685 handle = OS.gtk_bin_get_child (cast(GtkBin*)scrolledHandle); | |
686 if (handle is null) error (SWT.ERROR_NO_HANDLES); | |
687 } | |
688 group = cast(GtkWidget*) OS.gtk_window_group_new (); | |
689 if (group is null) error (SWT.ERROR_NO_HANDLES); | |
690 /* | |
691 * Feature in GTK. Realizing the shell triggers a size allocate event, | |
692 * which may be confused for a resize event from the window manager if | |
693 * received too late. The fix is to realize the window during creation | |
694 * to avoid confusion. | |
695 */ | |
696 OS.gtk_widget_realize (shellHandle); | |
697 } | |
698 | |
699 override int /*long*/ filterProc ( XEvent* xEvent, GdkEvent* gdkEvent, void* data2) { | |
700 int eventType = OS.X_EVENT_TYPE (xEvent); | |
701 if (eventType !is OS.FocusOut && eventType !is OS.FocusIn) return 0; | |
702 XFocusChangeEvent* xFocusEvent = cast(XFocusChangeEvent*)xEvent; | |
703 switch (eventType) { | |
704 case OS.FocusIn: | |
705 if (xFocusEvent.mode is OS.NotifyNormal || xFocusEvent.mode is OS.NotifyWhileGrabbed) { | |
706 switch (xFocusEvent.detail) { | |
707 case OS.NotifyNonlinear: | |
708 case OS.NotifyNonlinearVirtual: | |
709 case OS.NotifyAncestor: | |
710 if (tooltipsHandle !is null) OS.gtk_tooltips_enable (cast(GtkTooltips*)tooltipsHandle); | |
711 display.activeShell = this; | |
712 display.activePending = false; | |
713 sendEvent (SWT.Activate); | |
714 break; | |
715 default: | |
716 } | |
717 } | |
718 break; | |
719 case OS.FocusOut: | |
720 if (xFocusEvent.mode is OS.NotifyNormal || xFocusEvent.mode is OS.NotifyWhileGrabbed) { | |
721 switch (xFocusEvent.detail) { | |
722 case OS.NotifyNonlinear: | |
723 case OS.NotifyNonlinearVirtual: | |
724 case OS.NotifyVirtual: | |
725 if (tooltipsHandle !is null) OS.gtk_tooltips_disable (cast(GtkTooltips*)tooltipsHandle); | |
726 Display display = this.display; | |
727 sendEvent (SWT.Deactivate); | |
728 setActiveControl (null); | |
729 if (display.activeShell is this) { | |
730 display.activeShell = null; | |
731 display.activePending = false; | |
732 } | |
733 break; | |
734 default: | |
735 } | |
736 } | |
737 break; | |
738 default: | |
739 } | |
740 return 0; | |
741 } | |
742 | |
743 override Control findBackgroundControl () { | |
744 return (state & BACKGROUND) !is 0 || backgroundImage !is null ? this : null; | |
745 } | |
746 | |
747 override Composite findDeferredControl () { | |
748 return layoutCount > 0 ? this : null; | |
749 } | |
750 | |
751 override bool hasBorder () { | |
752 return false; | |
753 } | |
754 | |
755 override void hookEvents () { | |
756 super.hookEvents (); | |
757 OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [KEY_PRESS_EVENT], 0, display.closures [KEY_PRESS_EVENT], false); | |
758 OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [WINDOW_STATE_EVENT], 0, display.closures [WINDOW_STATE_EVENT], false); | |
759 OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [SIZE_ALLOCATE], 0, display.closures [SIZE_ALLOCATE], false); | |
760 OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [CONFIGURE_EVENT], 0, display.closures [CONFIGURE_EVENT], false); | |
761 OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [DELETE_EVENT], 0, display.closures [DELETE_EVENT], false); | |
762 OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [MAP_EVENT], 0, display.shellMapProcClosure, false); | |
763 OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [ENTER_NOTIFY_EVENT], 0, display.closures [ENTER_NOTIFY_EVENT], false); | |
764 OS.g_signal_connect_closure (shellHandle, OS.move_focus.ptr, display.closures [MOVE_FOCUS], false); | |
765 auto window = OS.GTK_WIDGET_WINDOW (shellHandle); | |
766 display.doWindowAddFilter( &filterProcCallbackData, window, shellHandle ); | |
767 //OS.gdk_window_add_filter (window, display.filterProc, shellHandle); | |
768 } | |
769 | |
770 override public bool isEnabled () { | |
771 checkWidget (); | |
772 return getEnabled (); | |
773 } | |
774 | |
775 bool isUndecorated () { | |
776 return | |
777 (style & (SWT.SHELL_TRIM | SWT.BORDER)) is SWT.NONE || | |
778 (style & (SWT.NO_TRIM | SWT.ON_TOP)) !is 0; | |
779 } | |
780 | |
781 override public bool isVisible () { | |
782 checkWidget(); | |
783 return getVisible (); | |
784 } | |
785 | |
786 override void register () { | |
787 super.register (); | |
788 display.addWidget (shellHandle, this); | |
789 } | |
790 | |
791 override void releaseParent () { | |
792 /* Do nothing */ | |
793 } | |
794 | |
795 override GtkWidget* topHandle () { | |
796 return shellHandle; | |
797 } | |
798 | |
799 void fixActiveShell () { | |
800 if (display.activeShell is this) { | |
801 Shell shell = null; | |
802 if (parent !is null && parent.isVisible ()) shell = parent.getShell (); | |
803 if (shell is null && isUndecorated ()) { | |
804 Shell [] shells = display.getShells (); | |
805 for (int i = 0; i < shells.length; i++) { | |
806 if (shells [i] !is null && shells [i].isVisible ()) { | |
807 shell = shells [i]; | |
808 break; | |
809 } | |
810 } | |
811 } | |
812 if (shell !is null) shell.bringToTop (false); | |
813 } | |
814 } | |
815 | |
816 void fixShell (Shell newShell, Control control) { | |
817 if (this is newShell) return; | |
818 if (control is lastActive) setActiveControl (null); | |
819 String toolTipText = control.toolTipText; | |
820 if (toolTipText !is null) { | |
821 control.setToolTipText (this, null); | |
822 control.setToolTipText (newShell, toolTipText); | |
823 } | |
824 } | |
825 | |
826 override void fixedSizeAllocateProc(GtkWidget* widget, GtkAllocation* allocationPtr) { | |
827 int clientWidth = 0; | |
828 if ((style & SWT.MIRRORED) !is 0) clientWidth = getClientWidth (); | |
829 super.fixedSizeAllocateProc (widget, allocationPtr); | |
830 if ((style & SWT.MIRRORED) !is 0) moveChildren (clientWidth); | |
831 } | |
832 | |
833 override void fixStyle (GtkWidget* handle) { | |
834 } | |
835 | |
836 override void forceResize () { | |
837 forceResize (OS.GTK_WIDGET_WIDTH (vboxHandle), OS.GTK_WIDGET_HEIGHT (vboxHandle)); | |
838 } | |
839 | |
840 void forceResize (int width, int height) { | |
841 GtkRequisition requisition; | |
842 OS.gtk_widget_size_request (vboxHandle, &requisition); | |
843 GtkAllocation allocation; | |
844 int border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle); | |
845 allocation.x = border; | |
846 allocation.y = border; | |
847 allocation.width = width; | |
848 allocation.height = height; | |
849 OS.gtk_widget_size_allocate (cast(GtkWidget*)vboxHandle, &allocation); | |
850 } | |
851 | |
852 /** | |
853 * Returns the receiver's alpha value. The alpha value | |
854 * is between 0 (transparent) and 255 (opaque). | |
855 * | |
856 * @return the alpha value | |
857 * | |
858 * @exception SWTException <ul> | |
859 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
860 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
861 * </ul> | |
862 * | |
863 * @since 3.4 | |
864 */ | |
865 public int getAlpha () { | |
866 checkWidget (); | |
867 if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) { | |
868 if (OS.gtk_widget_is_composited (shellHandle)) { | |
869 return cast(int) (OS.gtk_window_get_opacity (shellHandle) * 255); | |
870 } | |
871 } | |
872 return 255; | |
873 } | |
874 | |
875 /** | |
876 * Returns <code>true</code> if the receiver is currently | |
877 * in fullscreen state, and false otherwise. | |
878 * <p> | |
879 * | |
880 * @return the fullscreen state | |
881 * | |
882 * @exception SWTException <ul> | |
883 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
884 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
885 * </ul> | |
886 * | |
887 * @since 3.4 | |
888 */ | |
889 public bool getFullScreen () { | |
890 checkWidget(); | |
891 return fullScreen; | |
892 } | |
893 | |
894 override public Point getLocation () { | |
895 checkWidget (); | |
896 int x, y; | |
897 OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x,&y); | |
898 return new Point (x, y); | |
899 } | |
900 | |
901 public bool getMaximized () { | |
902 checkWidget(); | |
903 return !fullScreen && super.getMaximized (); | |
904 } | |
905 | |
906 /** | |
907 * Returns a point describing the minimum receiver's size. The | |
908 * x coordinate of the result is the minimum width of the receiver. | |
909 * The y coordinate of the result is the minimum height of the | |
910 * receiver. | |
911 * | |
912 * @return the receiver's size | |
913 * | |
914 * @exception SWTException <ul> | |
915 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
916 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
917 * </ul> | |
918 * | |
919 * @since 3.1 | |
920 */ | |
921 public Point getMinimumSize () { | |
922 checkWidget (); | |
923 int width = Math.max (1, minWidth + trimWidth ()); | |
924 int height = Math.max (1, minHeight + trimHeight ()); | |
925 return new Point (width, height); | |
926 } | |
927 | |
928 Shell getModalShell () { | |
929 Shell shell = null; | |
930 Shell [] modalShells = display.modalShells; | |
931 if (modalShells !is null) { | |
932 int bits = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; | |
933 int index = modalShells.length; | |
934 while (--index >= 0) { | |
935 Shell modal = modalShells [index]; | |
936 if (modal !is null) { | |
937 if ((modal.style & bits) !is 0) { | |
938 Control control = this; | |
939 while (control !is null) { | |
940 if (control is modal) break; | |
941 control = control.parent; | |
942 } | |
943 if (control !is modal) return modal; | |
944 break; | |
945 } | |
946 if ((modal.style & SWT.PRIMARY_MODAL) !is 0) { | |
947 if (shell is null) shell = getShell (); | |
948 if (modal.parent is shell) return modal; | |
949 } | |
950 } | |
951 } | |
952 } | |
953 return null; | |
954 } | |
955 | |
956 override public Point getSize () { | |
957 checkWidget (); | |
958 int width = OS.GTK_WIDGET_WIDTH (vboxHandle); | |
959 int height = OS.GTK_WIDGET_HEIGHT (vboxHandle); | |
960 int border = 0; | |
961 if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) { | |
962 border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle); | |
963 } | |
964 return new Point (width + trimWidth () + 2*border, height + trimHeight () + 2*border); | |
965 } | |
966 | |
967 override public bool getVisible () { | |
968 checkWidget(); | |
969 return OS.GTK_WIDGET_VISIBLE (shellHandle); | |
970 } | |
971 | |
972 /** | |
973 * Returns the region that defines the shape of the shell, | |
974 * or null if the shell has the default shape. | |
975 * | |
976 * @return the region that defines the shape of the shell (or null) | |
977 * | |
978 * @exception SWTException <ul> | |
979 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
980 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
981 * </ul> | |
982 * | |
983 * @since 3.0 | |
984 * | |
985 */ | |
986 public Region getRegion () { | |
987 /* This method is needed for @since 3.0 Javadoc */ | |
988 checkWidget (); | |
989 return region; | |
990 } | |
991 | |
992 /** | |
993 * Returns the receiver's input method editor mode. This | |
994 * will be the result of bitwise OR'ing together one or | |
995 * more of the following constants defined in class | |
996 * <code>SWT</code>: | |
997 * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>, | |
998 * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>. | |
999 * | |
1000 * @return the IME mode | |
1001 * | |
1002 * @exception SWTException <ul> | |
1003 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1004 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1005 * </ul> | |
1006 * | |
1007 * @see SWT | |
1008 */ | |
1009 public int getImeInputMode () { | |
1010 checkWidget(); | |
1011 return SWT.NONE; | |
1012 } | |
1013 | |
1014 override Shell _getShell () { | |
1015 return this; | |
1016 } | |
1017 /** | |
1018 * Returns an array containing all shells which are | |
1019 * descendants of the receiver. | |
1020 * <p> | |
1021 * @return the dialog shells | |
1022 * | |
1023 * @exception SWTException <ul> | |
1024 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1025 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1026 * </ul> | |
1027 */ | |
1028 public Shell [] getShells () { | |
1029 checkWidget(); | |
1030 int count = 0; | |
1031 Shell [] shells = display.getShells (); | |
1032 for (int i=0; i<shells.length; i++) { | |
1033 Control shell = shells [i]; | |
1034 do { | |
1035 shell = shell.getParent (); | |
1036 } while (shell !is null && shell !is this); | |
1037 if (shell is this) count++; | |
1038 } | |
1039 int index = 0; | |
1040 Shell [] result = new Shell [count]; | |
1041 for (int i=0; i<shells.length; i++) { | |
1042 Control shell = shells [i]; | |
1043 do { | |
1044 shell = shell.getParent (); | |
1045 } while (shell !is null && shell !is this); | |
1046 if (shell is this) { | |
1047 result [index++] = shells [i]; | |
1048 } | |
1049 } | |
1050 return result; | |
1051 } | |
1052 | |
1053 override int /*long*/ gtk_configure_event (GtkWidget* widget, int /*long*/ event) { | |
1054 int x, y; | |
1055 OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x, &y); | |
1056 if (!moved || oldX !is x || oldY !is y) { | |
1057 moved = true; | |
1058 oldX = x; | |
1059 oldY = y; | |
1060 sendEvent (SWT.Move); | |
1061 // widget could be disposed at this point | |
1062 } | |
1063 return 0; | |
1064 } | |
1065 | |
1066 override int /*long*/ gtk_delete_event (GtkWidget* widget, int /*long*/ event) { | |
1067 if (isEnabled()) closeWidget (); | |
1068 return 1; | |
1069 } | |
1070 | |
1071 override int /*long*/ gtk_enter_notify_event (GtkWidget* widget, GdkEventCrossing* event) { | |
1072 if (widget !is shellHandle) { | |
1073 return super.gtk_enter_notify_event (widget, event); | |
1074 } | |
1075 return 0; | |
1076 } | |
1077 | |
1078 override int /*long*/ gtk_focus (GtkWidget* widget, int directionType) { | |
1079 switch (cast(int)/*64*/directionType) { | |
1080 case OS.GTK_DIR_TAB_FORWARD: | |
1081 case OS.GTK_DIR_TAB_BACKWARD: | |
1082 Control control = display.getFocusControl (); | |
1083 if (control !is null) { | |
1084 if ((control.state & CANVAS) !is 0 && (control.style & SWT.EMBEDDED) !is 0) { | |
1085 int traversal = directionType is OS.GTK_DIR_TAB_FORWARD ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS; | |
1086 control.traverse (traversal); | |
1087 return 1; | |
1088 } | |
1089 } | |
1090 break; | |
1091 default: | |
1092 } | |
1093 return super.gtk_focus (widget, directionType); | |
1094 } | |
1095 | |
1096 override int /*long*/ gtk_move_focus (GtkWidget* widget, int directionType) { | |
1097 Control control = display.getFocusControl (); | |
1098 if (control !is null) { | |
1099 auto focusHandle = control.focusHandle (); | |
1100 OS.gtk_widget_child_focus (focusHandle, directionType); | |
1101 } | |
1102 OS.g_signal_stop_emission_by_name (shellHandle, OS.move_focus.ptr ); | |
1103 return 1; | |
1104 } | |
1105 | |
1106 override int /*long*/ gtk_key_press_event (GtkWidget* widget, GdkEventKey* event) { | |
1107 /* Stop menu mnemonics when the shell is disabled */ | |
1108 if (widget is shellHandle) { | |
1109 return (state & DISABLED) !is 0 ? 1 : 0; | |
1110 } | |
1111 return super.gtk_key_press_event (widget, event); | |
1112 } | |
1113 | |
1114 override int /*long*/ gtk_size_allocate (GtkWidget* widget, int /*long*/ allocation) { | |
1115 int width = OS.GTK_WIDGET_WIDTH (shellHandle); | |
1116 int height = OS.GTK_WIDGET_HEIGHT (shellHandle); | |
1117 if (!resized || oldWidth !is width || oldHeight !is height) { | |
1118 oldWidth = width; | |
1119 oldHeight = height; | |
1120 resizeBounds (width, height, true); | |
1121 } | |
1122 return 0; | |
1123 } | |
1124 | |
1125 override int /*long*/ gtk_realize (GtkWidget* widget) { | |
1126 auto result = super.gtk_realize (widget); | |
1127 auto window = OS.GTK_WIDGET_WINDOW (shellHandle); | |
1128 if ((style & SWT.SHELL_TRIM) !is SWT.SHELL_TRIM) { | |
1129 int decorations = 0; | |
1130 if ((style & SWT.NO_TRIM) is 0) { | |
1131 if ((style & SWT.MIN) !is 0) decorations |= OS.GDK_DECOR_MINIMIZE; | |
1132 if ((style & SWT.MAX) !is 0) decorations |= OS.GDK_DECOR_MAXIMIZE; | |
1133 if ((style & SWT.RESIZE) !is 0) decorations |= OS.GDK_DECOR_RESIZEH; | |
1134 if ((style & SWT.BORDER) !is 0) decorations |= OS.GDK_DECOR_BORDER; | |
1135 if ((style & SWT.MENU) !is 0) decorations |= OS.GDK_DECOR_MENU; | |
1136 if ((style & SWT.TITLE) !is 0) decorations |= OS.GDK_DECOR_TITLE; | |
1137 /* | |
1138 * Feature in GTK. Under some Window Managers (Sawmill), in order | |
1139 * to get any border at all from the window manager it is necessary to | |
1140 * set GDK_DECOR_BORDER. The fix is to force these bits when any | |
1141 * kind of border is requested. | |
1142 */ | |
1143 if ((style & SWT.RESIZE) !is 0) decorations |= OS.GDK_DECOR_BORDER; | |
1144 } | |
1145 OS.gdk_window_set_decorations (window, decorations); | |
1146 } | |
1147 if ((style & SWT.ON_TOP) !is 0) { | |
1148 OS.gdk_window_set_override_redirect (window, true); | |
1149 } | |
1150 return result; | |
1151 } | |
1152 | |
1153 override int /*long*/ gtk_window_state_event (GtkWidget* widget, GdkEventWindowState* event) { | |
1154 minimized = (event.new_window_state & OS.GDK_WINDOW_STATE_ICONIFIED) !is 0; | |
1155 maximized = (event.new_window_state & OS.GDK_WINDOW_STATE_MAXIMIZED) !is 0; | |
1156 fullScreen = (event.new_window_state & OS.GDK_WINDOW_STATE_FULLSCREEN) !is 0; | |
1157 if ((event.changed_mask & OS.GDK_WINDOW_STATE_ICONIFIED) !is 0) { | |
1158 if (minimized) { | |
1159 sendEvent (SWT.Iconify); | |
1160 } else { | |
1161 sendEvent (SWT.Deiconify); | |
1162 } | |
1163 updateMinimized (minimized); | |
1164 } | |
1165 return 0; | |
1166 } | |
1167 | |
1168 /** | |
1169 * Moves the receiver to the top of the drawing order for | |
1170 * the display on which it was created (so that all other | |
1171 * shells on that display, which are not the receiver's | |
1172 * children will be drawn behind it), marks it visible, | |
1173 * sets the focus and asks the window manager to make the | |
1174 * shell active. | |
1175 * | |
1176 * @exception SWTException <ul> | |
1177 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1178 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1179 * </ul> | |
1180 * | |
1181 * @see Control#moveAbove | |
1182 * @see Control#setFocus | |
1183 * @see Control#setVisible | |
1184 * @see Display#getActiveShell | |
1185 * @see Decorations#setDefaultButton(Button) | |
1186 * @see Shell#setActive | |
1187 * @see Shell#forceActive | |
1188 */ | |
1189 public void open () { | |
1190 checkWidget (); | |
1191 bringToTop (false); | |
1192 setVisible (true); | |
1193 if (isDisposed ()) return; | |
1194 if (!restoreFocus () && !traverseGroup (true)) setFocus (); | |
1195 } | |
1196 | |
1197 public bool print (GC gc) { | |
1198 checkWidget (); | |
1199 if (gc is null) error (SWT.ERROR_NULL_ARGUMENT); | |
1200 if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); | |
1201 return false; | |
1202 } | |
1203 | |
1204 /** | |
1205 * Removes the listener from the collection of listeners who will | |
1206 * be notified when operations are performed on the receiver. | |
1207 * | |
1208 * @param listener the listener which should no longer be notified | |
1209 * | |
1210 * @exception IllegalArgumentException <ul> | |
1211 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
1212 * </ul> | |
1213 * @exception SWTException <ul> | |
1214 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1215 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1216 * </ul> | |
1217 * | |
1218 * @see ShellListener | |
1219 * @see #addShellListener | |
1220 */ | |
1221 public void removeShellListener (ShellListener listener) { | |
1222 checkWidget(); | |
1223 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
1224 if (eventTable is null) return; | |
1225 eventTable.unhook (SWT.Close, listener); | |
1226 eventTable.unhook (SWT.Iconify,listener); | |
1227 eventTable.unhook (SWT.Deiconify,listener); | |
1228 eventTable.unhook (SWT.Activate, listener); | |
1229 eventTable.unhook (SWT.Deactivate, listener); | |
1230 } | |
1231 | |
1232 /** | |
1233 * If the receiver is visible, moves it to the top of the | |
1234 * drawing order for the display on which it was created | |
1235 * (so that all other shells on that display, which are not | |
1236 * the receiver's children will be drawn behind it) and asks | |
1237 * the window manager to make the shell active | |
1238 * | |
1239 * @exception SWTException <ul> | |
1240 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1241 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1242 * </ul> | |
1243 * | |
1244 * @since 2.0 | |
1245 * @see Control#moveAbove | |
1246 * @see Control#setFocus | |
1247 * @see Control#setVisible | |
1248 * @see Display#getActiveShell | |
1249 * @see Decorations#setDefaultButton(Button) | |
1250 * @see Shell#open | |
1251 * @see Shell#setActive | |
1252 */ | |
1253 public void setActive () { | |
1254 checkWidget (); | |
1255 bringToTop (false); | |
1256 } | |
1257 | |
1258 void setActiveControl (Control control) { | |
1259 if (control !is null && control.isDisposed ()) control = null; | |
1260 if (lastActive !is null && lastActive.isDisposed ()) lastActive = null; | |
1261 if (lastActive is control) return; | |
1262 | |
1263 /* | |
1264 * Compute the list of controls to be activated and | |
1265 * deactivated by finding the first common parent | |
1266 * control. | |
1267 */ | |
1268 Control [] activate = (control is null) ? new Control[0] : control.getPath (); | |
1269 Control [] deactivate = (lastActive is null) ? new Control[0] : lastActive.getPath (); | |
1270 lastActive = control; | |
1271 int index = 0, length = Math.min (activate.length, deactivate.length); | |
1272 while (index < length) { | |
1273 if (activate [index] !is deactivate [index]) break; | |
1274 index++; | |
1275 } | |
1276 | |
1277 /* | |
1278 * It is possible (but unlikely), that application | |
1279 * code could have destroyed some of the widgets. If | |
1280 * this happens, keep processing those widgets that | |
1281 * are not disposed. | |
1282 */ | |
1283 for (int i=deactivate.length-1; i>=index; --i) { | |
1284 if (!deactivate [i].isDisposed ()) { | |
1285 deactivate [i].sendEvent (SWT.Deactivate); | |
1286 } | |
1287 } | |
1288 for (int i=activate.length-1; i>=index; --i) { | |
1289 if (!activate [i].isDisposed ()) { | |
1290 activate [i].sendEvent (SWT.Activate); | |
1291 } | |
1292 } | |
1293 } | |
1294 | |
1295 /** | |
1296 * Sets the receiver's alpha value which must be | |
1297 * between 0 (transparent) and 255 (opaque). | |
1298 * <p> | |
1299 * This operation requires the operating system's advanced | |
1300 * widgets subsystem which may not be available on some | |
1301 * platforms. | |
1302 * </p> | |
1303 * @param alpha the alpha value | |
1304 * | |
1305 * @exception SWTException <ul> | |
1306 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1307 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1308 * </ul> | |
1309 * | |
1310 * @since 3.4 | |
1311 */ | |
1312 public void setAlpha (int alpha) { | |
1313 checkWidget (); | |
1314 if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) { | |
1315 if (OS.gtk_widget_is_composited (shellHandle)) { | |
1316 alpha &= 0xFF; | |
1317 OS.gtk_window_set_opacity (shellHandle, alpha / 255f); | |
1318 } | |
1319 } | |
1320 } | |
1321 | |
1322 void resizeBounds (int width, int height, bool notify) { | |
1323 if (redrawWindow !is null) { | |
1324 OS.gdk_window_resize (redrawWindow, width, height); | |
1325 } | |
1326 if (enableWindow !is null) { | |
1327 OS.gdk_window_resize (enableWindow, width, height); | |
1328 } | |
1329 int border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle); | |
1330 int boxWidth = width - 2*border; | |
1331 int boxHeight = height - 2*border; | |
1332 OS.gtk_widget_set_size_request (vboxHandle, boxWidth, boxHeight); | |
1333 forceResize (boxWidth, boxHeight); | |
1334 if (notify) { | |
1335 resized = true; | |
1336 sendEvent (SWT.Resize); | |
1337 if (isDisposed ()) return; | |
1338 if (layout_ !is null) { | |
1339 markLayout (false, false); | |
1340 updateLayout (false); | |
1341 } | |
1342 } | |
1343 } | |
1344 | |
1345 override int setBounds (int x, int y, int width, int height, bool move, bool resize) { | |
1346 if (fullScreen) setFullScreen (false); | |
1347 /* | |
1348 * Bug in GTK. When either of the location or size of | |
1349 * a shell is changed while the shell is maximized, the | |
1350 * shell is moved to (0, 0). The fix is to explicitly | |
1351 * unmaximize the shell before setting the bounds to | |
1352 * anything different from the current bounds. | |
1353 */ | |
1354 if (getMaximized ()) { | |
1355 Rectangle rect = getBounds (); | |
1356 bool sameOrigin = !move || (rect.x is x && rect.y is y); | |
1357 bool sameExtent = !resize || (rect.width is width && rect.height is height); | |
1358 if (sameOrigin && sameExtent) return 0; | |
1359 setMaximized (false); | |
1360 } | |
1361 int result = 0; | |
1362 if (move) { | |
1363 int x_pos, y_pos; | |
1364 OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x_pos, &y_pos); | |
1365 OS.gtk_window_move (cast(GtkWindow*)shellHandle, x, y); | |
1366 if (x_pos !is x || y_pos !is y) { | |
1367 moved = true; | |
1368 oldX = x; | |
1369 oldY = y; | |
1370 sendEvent (SWT.Move); | |
1371 if (isDisposed ()) return 0; | |
1372 result |= MOVED; | |
1373 } | |
1374 } | |
1375 if (resize) { | |
1376 width = Math.max (1, Math.max (minWidth, width - trimWidth ())); | |
1377 height = Math.max (1, Math.max (minHeight, height - trimHeight ())); | |
1378 if ((style & SWT.RESIZE) !is 0) OS.gtk_window_resize (cast(GtkWindow*)shellHandle, width, height); | |
1379 bool changed = width !is oldWidth || height !is oldHeight; | |
1380 if (changed) { | |
1381 oldWidth = width; | |
1382 oldHeight = height; | |
1383 result |= RESIZED; | |
1384 } | |
1385 resizeBounds (width, height, changed); | |
1386 } | |
1387 return result; | |
1388 } | |
1389 | |
1390 override void gtk_setCursor (GdkCursor* cursor) { | |
1391 if (enableWindow !is null) { | |
1392 OS.gdk_window_set_cursor (cast(GdkDrawable*)enableWindow, cursor); | |
1393 if (!OS.GDK_WINDOWING_X11 ()) { | |
1394 OS.gdk_flush (); | |
1395 } else { | |
1396 auto xDisplay = OS.GDK_DISPLAY (); | |
1397 OS.XFlush (xDisplay); | |
1398 } | |
1399 } | |
1400 super.gtk_setCursor (cursor); | |
1401 } | |
1402 | |
1403 public override void setEnabled (bool enabled) { | |
1404 checkWidget(); | |
1405 if (((state & DISABLED) is 0) is enabled) return; | |
1406 Display display = this.display; | |
1407 Control control = null; | |
1408 bool fixFocus_ = false; | |
1409 if (!enabled) { | |
1410 if (display.focusEvent !is SWT.FocusOut) { | |
1411 control = display.getFocusControl (); | |
1412 fixFocus_ = isFocusAncestor (control); | |
1413 } | |
1414 } | |
1415 if (enabled) { | |
1416 state &= ~DISABLED; | |
1417 } else { | |
1418 state |= DISABLED; | |
1419 } | |
1420 enableWidget (enabled); | |
1421 if (isDisposed ()) return; | |
1422 if (enabled) { | |
1423 if (enableWindow !is null) { | |
1424 OS.gdk_window_set_user_data (enableWindow, null); | |
1425 OS.gdk_window_destroy (enableWindow); | |
1426 enableWindow = null; | |
1427 } | |
1428 } else { | |
1429 auto parentHandle = shellHandle; | |
1430 OS.gtk_widget_realize (parentHandle); | |
1431 auto window = OS.GTK_WIDGET_WINDOW (parentHandle); | |
1432 Rectangle rect = getBounds (); | |
1433 GdkWindowAttr* attributes = new GdkWindowAttr (); | |
1434 attributes.width = rect.width; | |
1435 attributes.height = rect.height; | |
1436 attributes.event_mask = (0xFFFFFFFF & ~OS.ExposureMask); | |
1437 attributes.wclass = OS.GDK_INPUT_ONLY; | |
1438 attributes.window_type = OS.GDK_WINDOW_CHILD; | |
1439 enableWindow = OS.gdk_window_new (window, attributes, 0); | |
1440 if (enableWindow !is null) { | |
1441 if (cursor !is null) { | |
1442 OS.gdk_window_set_cursor (enableWindow, cursor.handle); | |
1443 if (!OS.GDK_WINDOWING_X11 ()) { | |
1444 OS.gdk_flush (); | |
1445 } else { | |
1446 auto xDisplay = OS.GDK_DISPLAY (); | |
1447 OS.XFlush (xDisplay); | |
1448 } | |
1449 } | |
1450 OS.gdk_window_set_user_data (enableWindow, parentHandle); | |
1451 OS.gdk_window_show (enableWindow); | |
1452 } | |
1453 } | |
1454 if (fixFocus_) fixFocus (control); | |
1455 if (enabled && display.activeShell is this) { | |
1456 if (!restoreFocus ()) traverseGroup (false); | |
1457 } | |
1458 } | |
1459 | |
1460 /** | |
1461 * Sets the full screen state of the receiver. | |
1462 * If the argument is <code>true</code> causes the receiver | |
1463 * to switch to the full screen state, and if the argument is | |
1464 * <code>false</code> and the receiver was previously switched | |
1465 * into full screen state, causes the receiver to switch back | |
1466 * to either the maximmized or normal states. | |
1467 * <p> | |
1468 * Note: The result of intermixing calls to <code>setFullScreen(true)</code>, | |
1469 * <code>setMaximized(true)</code> and <code>setMinimized(true)</code> will | |
1470 * vary by platform. Typically, the behavior will match the platform user's | |
1471 * expectations, but not always. This should be avoided if possible. | |
1472 * </p> | |
1473 * | |
1474 * @param fullScreen the new fullscreen state | |
1475 * | |
1476 * @exception SWTException <ul> | |
1477 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1478 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1479 * </ul> | |
1480 * | |
1481 * @since 3.4 | |
1482 */ | |
1483 public void setFullScreen (bool fullScreen) { | |
1484 checkWidget(); | |
1485 if (fullScreen) { | |
1486 OS.gtk_window_fullscreen (shellHandle); | |
1487 } else { | |
1488 OS.gtk_window_unfullscreen (shellHandle); | |
1489 if (maximized) { | |
1490 setMaximized (true); | |
1491 } | |
1492 } | |
1493 this.fullScreen = fullScreen; | |
1494 } | |
1495 | |
1496 /** | |
1497 * Sets the input method editor mode to the argument which | |
1498 * should be the result of bitwise OR'ing together one or more | |
1499 * of the following constants defined in class <code>SWT</code>: | |
1500 * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>, | |
1501 * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>. | |
1502 * | |
1503 * @param mode the new IME mode | |
1504 * | |
1505 * @exception SWTException <ul> | |
1506 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1507 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1508 * </ul> | |
1509 * | |
1510 * @see SWT | |
1511 */ | |
1512 public void setImeInputMode (int mode) { | |
1513 checkWidget(); | |
1514 } | |
1515 | |
1516 override void setInitialBounds () { | |
1517 if ((state & FOREIGN_HANDLE) !is 0) return; | |
1518 org.eclipse.swt.widgets.Monitor.Monitor monitor = getMonitor (); | |
1519 Rectangle rect = monitor.getClientArea (); | |
1520 int width = rect.width * 5 / 8; | |
1521 int height = rect.height * 5 / 8; | |
1522 if ((style & SWT.RESIZE) !is 0) { | |
1523 OS.gtk_window_resize (cast(GtkWindow*)shellHandle, width, height); | |
1524 } | |
1525 resizeBounds (width, height, false); | |
1526 } | |
1527 | |
1528 public override void setMaximized (bool maximized) { | |
1529 checkWidget(); | |
1530 super.setMaximized (maximized); | |
1531 if (maximized) { | |
1532 OS.gtk_window_maximize (cast(GtkWindow*)shellHandle); | |
1533 } else { | |
1534 OS.gtk_window_unmaximize (cast(GtkWindow*)shellHandle); | |
1535 } | |
1536 } | |
1537 | |
1538 public override void setMenuBar (Menu menu) { | |
1539 checkWidget(); | |
1540 if (menuBar is menu) return; | |
1541 bool both = menu !is null && menuBar !is null; | |
1542 if (menu !is null) { | |
1543 if ((menu.style & SWT.BAR) is 0) error (SWT.ERROR_MENU_NOT_BAR); | |
1544 if (menu.parent !is this) error (SWT.ERROR_INVALID_PARENT); | |
1545 } | |
1546 if (menuBar !is null) { | |
1547 auto menuHandle = menuBar.handle; | |
1548 OS.gtk_widget_hide (menuHandle); | |
1549 destroyAccelGroup (); | |
1550 } | |
1551 menuBar = menu; | |
1552 if (menuBar !is null) { | |
1553 auto menuHandle = menu.handle; | |
1554 OS.gtk_widget_show (menuHandle); | |
1555 createAccelGroup (); | |
1556 menuBar.addAccelerators (accelGroup); | |
1557 } | |
1558 int width = OS.GTK_WIDGET_WIDTH (vboxHandle); | |
1559 int height = OS.GTK_WIDGET_HEIGHT (vboxHandle); | |
1560 resizeBounds (width, height, !both); | |
1561 } | |
1562 | |
1563 public override void setMinimized (bool minimized) { | |
1564 checkWidget(); | |
1565 if (this.minimized is minimized) return; | |
1566 super.setMinimized (minimized); | |
1567 if (minimized) { | |
1568 OS.gtk_window_iconify (cast(GtkWindow*)shellHandle); | |
1569 } else { | |
1570 OS.gtk_window_deiconify (cast(GtkWindow*)shellHandle); | |
1571 bringToTop (false); | |
1572 } | |
1573 } | |
1574 | |
1575 /** | |
1576 * Sets the receiver's minimum size to the size specified by the arguments. | |
1577 * If the new minimum size is larger than the current size of the receiver, | |
1578 * the receiver is resized to the new minimum size. | |
1579 * | |
1580 * @param width the new minimum width for the receiver | |
1581 * @param height the new minimum height for the receiver | |
1582 * | |
1583 * @exception SWTException <ul> | |
1584 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1585 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1586 * </ul> | |
1587 * | |
1588 * @since 3.1 | |
1589 */ | |
1590 public void setMinimumSize (int width, int height) { | |
1591 checkWidget (); | |
1592 GdkGeometry* geometry = new GdkGeometry (); | |
1593 minWidth = geometry.min_width = Math.max (width, trimWidth ()) - trimWidth (); | |
1594 minHeight = geometry.min_height = Math.max (height, trimHeight ()) - trimHeight (); | |
1595 OS.gtk_window_set_geometry_hints (cast(GtkWindow*)shellHandle, null, geometry, OS.GDK_HINT_MIN_SIZE); | |
1596 } | |
1597 | |
1598 /** | |
1599 * Sets the receiver's minimum size to the size specified by the argument. | |
1600 * If the new minimum size is larger than the current size of the receiver, | |
1601 * the receiver is resized to the new minimum size. | |
1602 * | |
1603 * @param size the new minimum size for the receiver | |
1604 * | |
1605 * @exception IllegalArgumentException <ul> | |
1606 * <li>ERROR_NULL_ARGUMENT - if the point is null</li> | |
1607 * </ul> | |
1608 * @exception SWTException <ul> | |
1609 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1610 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1611 * </ul> | |
1612 * | |
1613 * @since 3.1 | |
1614 */ | |
1615 public void setMinimumSize (Point size) { | |
1616 checkWidget (); | |
1617 if (size is null) error (SWT.ERROR_NULL_ARGUMENT); | |
1618 setMinimumSize (size.x, size.y); | |
1619 } | |
1620 | |
1621 /** | |
1622 * Sets the shape of the shell to the region specified | |
1623 * by the argument. When the argument is null, the | |
1624 * default shape of the shell is restored. The shell | |
1625 * must be created with the style SWT.NO_TRIM in order | |
1626 * to specify a region. | |
1627 * | |
1628 * @param region the region that defines the shape of the shell (or null) | |
1629 * | |
1630 * @exception IllegalArgumentException <ul> | |
1631 * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li> | |
1632 * </ul> | |
1633 * @exception SWTException <ul> | |
1634 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1635 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1636 * </ul> | |
1637 * | |
1638 * @since 3.0 | |
1639 * | |
1640 */ | |
1641 public void setRegion (Region region) { | |
1642 checkWidget (); | |
1643 if ((style & SWT.NO_TRIM) is 0) return; | |
1644 super.setRegion (region); | |
1645 } | |
1646 | |
1647 /* | |
1648 * Shells are never labelled by other widgets, so no initialization is needed. | |
1649 */ | |
1650 override void setRelations() { | |
1651 } | |
1652 | |
1653 public override void setText (String string) { | |
1654 super.setText (string); | |
1655 | |
1656 /* | |
1657 * GTK bug 82013. For some reason, if the title string | |
1658 * is less than 7 bytes long and is not terminated by | |
1659 * a space, some window managers occasionally draw | |
1660 * garbage after the last character in the title. | |
1661 * The fix is to pad the title. | |
1662 */ | |
1663 int length_ = string.length; | |
1664 char [] chars = new char [Math.max (6, length_) + 1]; | |
1665 chars = string[ 0 .. length_]; | |
1666 for (int i=length_; i<chars.length; i++) chars [i] = ' '; | |
1667 OS.gtk_window_set_title (cast(GtkWindow*)shellHandle, toStringz( chars ) ); | |
1668 } | |
1669 | |
1670 public override void setVisible (bool visible) { | |
1671 checkWidget(); | |
1672 int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; | |
1673 if ((style & mask) !is 0) { | |
1674 if (visible) { | |
1675 display.setModalShell (this); | |
1676 OS.gtk_window_set_modal (shellHandle, true); | |
1677 } else { | |
1678 display.clearModal (this); | |
1679 OS.gtk_window_set_modal (shellHandle, false); | |
1680 } | |
1681 } else { | |
1682 updateModal (); | |
1683 } | |
1684 showWithParent = visible; | |
1685 if ((OS.GTK_WIDGET_MAPPED (shellHandle) is visible)) return; | |
1686 if (visible) { | |
1687 sendEvent (SWT.Show); | |
1688 if (isDisposed ()) return; | |
1689 | |
1690 /* | |
1691 * In order to ensure that the shell is visible | |
1692 * and fully painted, dispatch events such as | |
1693 * GDK_MAP and GDK_CONFIGURE, until the GDK_MAP | |
1694 * event for the shell is received. | |
1695 * | |
1696 * Note that if the parent is minimized or withdrawn | |
1697 * from the desktop, this should not be done since | |
1698 * the shell not will be mapped until the parent is | |
1699 * unminimized or shown on the desktop. | |
1700 */ | |
1701 OS.gtk_widget_show (shellHandle); | |
1702 if (enableWindow !is null) OS.gdk_window_raise (enableWindow); | |
1703 if (!OS.GTK_IS_PLUG (cast(GTypeInstance*)shellHandle)) { | |
1704 mapped = false; | |
1705 if (isDisposed ()) return; | |
1706 display.dispatchEvents = [ | |
1707 OS.GDK_EXPOSE, | |
1708 OS.GDK_FOCUS_CHANGE, | |
1709 OS.GDK_CONFIGURE, | |
1710 OS.GDK_MAP, | |
1711 OS.GDK_UNMAP, | |
1712 OS.GDK_NO_EXPOSE | |
1713 ]; | |
1714 Display display = this.display; | |
1715 display.putGdkEvents(); | |
1716 bool iconic = false; | |
1717 Shell shell = parent !is null ? parent.getShell() : null; | |
1718 do { | |
1719 OS.g_main_context_iteration (null, false); | |
1720 if (isDisposed ()) break; | |
1721 iconic = minimized || (shell !is null && shell.minimized); | |
1722 } while (!mapped && !iconic); | |
1723 display.dispatchEvents = null; | |
1724 if (isDisposed ()) return; | |
1725 if (!iconic) { | |
1726 update (true, true); | |
1727 if (isDisposed ()) return; | |
1728 adjustTrim (); | |
1729 } | |
1730 } | |
1731 mapped = true; | |
1732 | |
1733 if ((style & mask) !is 0) { | |
1734 OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME); | |
1735 } | |
1736 opened = true; | |
1737 if (!moved) { | |
1738 moved = true; | |
1739 Point location = getLocation(); | |
1740 oldX = location.x; | |
1741 oldY = location.y; | |
1742 sendEvent (SWT.Move); | |
1743 if (isDisposed ()) return; | |
1744 } | |
1745 if (!resized) { | |
1746 resized = true; | |
1747 Point size = getSize (); | |
1748 oldWidth = size.x - trimWidth (); | |
1749 oldHeight = size.y - trimHeight (); | |
1750 sendEvent (SWT.Resize); | |
1751 if (isDisposed ()) return; | |
1752 if (layout_ !is null) { | |
1753 markLayout (false, false); | |
1754 updateLayout (false); | |
1755 } | |
1756 } | |
1757 } else { | |
1758 fixActiveShell (); | |
1759 OS.gtk_widget_hide (shellHandle); | |
1760 sendEvent (SWT.Hide); | |
1761 } | |
1762 } | |
1763 | |
1764 override void setZOrder (Control sibling, bool above, bool fixRelations) { | |
1765 /* | |
1766 * Bug in GTK+. Changing the toplevel window Z-order causes | |
1767 * X to send a resize event. Before the shell is mapped, these | |
1768 * resize events always have a size of 200x200, causing extra | |
1769 * layout work to occur. The fix is to modify the Z-order only | |
1770 * if the shell has already been mapped at least once. | |
1771 */ | |
1772 /* Shells are never included in labelled-by relations */ | |
1773 if (mapped) setZOrder (sibling, above, false, false); | |
1774 } | |
1775 | |
1776 override int /*long*/ shellMapProc (GtkWidget* handle, int /*long*/ arg0, int /*long*/ user_data) { | |
1777 mapped = true; | |
1778 display.dispatchEvents = null; | |
1779 return 0; | |
1780 } | |
1781 | |
1782 void showWidget () { | |
1783 if ((state & FOREIGN_HANDLE) !is 0) return; | |
1784 OS.gtk_container_add (cast(GtkContainer*)shellHandle, vboxHandle); | |
1785 if (scrolledHandle !is null) OS.gtk_widget_show (scrolledHandle); | |
1786 if (handle !is null) OS.gtk_widget_show (handle); | |
1787 if (vboxHandle !is null) OS.gtk_widget_show (vboxHandle); | |
1788 } | |
1789 | |
1790 override int /*long*/ sizeAllocateProc (GtkWidget* handle, int /*long*/ arg0, int /*long*/ user_data) { | |
1791 int offset = 16; | |
1792 int x, y; | |
1793 OS.gdk_window_get_pointer (null, &x, &y, null); | |
1794 y += offset; | |
1795 auto screen = OS.gdk_screen_get_default (); | |
1796 if (screen !is null) { | |
1797 int monitorNumber = OS.gdk_screen_get_monitor_at_point (screen, x, y); | |
1798 GdkRectangle* dest = new GdkRectangle (); | |
1799 OS.gdk_screen_get_monitor_geometry (screen, monitorNumber, dest); | |
1800 int width = OS.GTK_WIDGET_WIDTH (handle); | |
1801 int height = OS.GTK_WIDGET_HEIGHT (handle); | |
1802 if (x + width > dest.x + dest.width) { | |
1803 x = (dest.x + dest.width) - width; | |
1804 } | |
1805 if (y + height > dest.y + dest.height) { | |
1806 y = (dest.y + dest.height) - height; | |
1807 } | |
1808 } | |
1809 OS.gtk_window_move (cast(GtkWindow*)handle, x, y); | |
1810 return 0; | |
1811 } | |
1812 | |
1813 override int /*long*/ sizeRequestProc (GtkWidget* handle, int /*long*/ arg0, int /*long*/ user_data) { | |
1814 OS.gtk_widget_hide (handle); | |
1815 return 0; | |
1816 } | |
1817 | |
1818 override bool traverseEscape () { | |
1819 if (parent is null) return false; | |
1820 if (!isVisible () || !isEnabled ()) return false; | |
1821 close (); | |
1822 return true; | |
1823 } | |
1824 int trimHeight () { | |
1825 if ((style & SWT.NO_TRIM) !is 0) return 0; | |
1826 if (fullScreen) return 0; | |
1827 bool hasTitle = false, hasResize = false, hasBorder = false; | |
1828 hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) !is 0; | |
1829 hasResize = (style & SWT.RESIZE) !is 0; | |
1830 hasBorder = (style & SWT.BORDER) !is 0; | |
1831 if (hasTitle) { | |
1832 if (hasResize) return display.titleResizeTrimHeight; | |
1833 if (hasBorder) return display.titleBorderTrimHeight; | |
1834 return display.titleTrimHeight; | |
1835 } | |
1836 if (hasResize) return display.resizeTrimHeight; | |
1837 if (hasBorder) return display.borderTrimHeight; | |
1838 return 0; | |
1839 } | |
1840 | |
1841 int trimWidth () { | |
1842 if ((style & SWT.NO_TRIM) !is 0) return 0; | |
1843 if (fullScreen) return 0; | |
1844 bool hasTitle = false, hasResize = false, hasBorder = false; | |
1845 hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) !is 0; | |
1846 hasResize = (style & SWT.RESIZE) !is 0; | |
1847 hasBorder = (style & SWT.BORDER) !is 0; | |
1848 if (hasTitle) { | |
1849 if (hasResize) return display.titleResizeTrimWidth; | |
1850 if (hasBorder) return display.titleBorderTrimWidth; | |
1851 return display.titleTrimWidth; | |
1852 } | |
1853 if (hasResize) return display.resizeTrimWidth; | |
1854 if (hasBorder) return display.borderTrimWidth; | |
1855 return 0; | |
1856 } | |
1857 | |
1858 void updateModal () { | |
1859 GtkWidget* group = null; | |
1860 if (display.getModalDialog () is null) { | |
1861 Shell modal = getModalShell (); | |
1862 int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; | |
1863 Composite shell = null; | |
1864 if (modal is null) { | |
1865 if ((style & mask) !is 0) shell = this; | |
1866 } else { | |
1867 shell = modal; | |
1868 } | |
1869 while (shell !is null) { | |
1870 if ((shell.style & mask) is 0) { | |
1871 group = shell.getShell ().group; | |
1872 break; | |
1873 } | |
1874 shell = shell.parent; | |
1875 } | |
1876 } | |
1877 if (OS.GTK_VERSION >= OS.buildVERSION (2, 10, 0) && group is null) { | |
1878 /* | |
1879 * Feature in GTK. Starting with GTK version 2.10, GTK | |
1880 * doesn't assign windows to a default group. The fix is to | |
1881 * get the handle of the default group and add windows to the | |
1882 * group. | |
1883 */ | |
1884 group = cast(GtkWidget*)OS.gtk_window_get_group(null); | |
1885 } | |
1886 if (group !is null) { | |
1887 OS.gtk_window_group_add_window (group, shellHandle); | |
1888 } else { | |
1889 if (modalGroup !is null) { | |
1890 OS.gtk_window_group_remove_window (modalGroup, shellHandle); | |
1891 } | |
1892 } | |
1893 if (OS.GTK_VERSION < OS.buildVERSION (2, 4, 0)) { | |
1894 fixModal (group, modalGroup); | |
1895 } | |
1896 modalGroup = group; | |
1897 } | |
1898 | |
1899 void updateMinimized (bool minimized) { | |
1900 Shell[] shells = getShells (); | |
1901 for (int i = 0; i < shells.length; i++) { | |
1902 bool update = false; | |
1903 Shell shell = shells[i]; | |
1904 while (shell !is null && shell !is this && !shell.isUndecorated ()) { | |
1905 shell = cast(Shell) shell.getParent (); | |
1906 } | |
1907 if (shell !is null && shell !is this) update = true; | |
1908 if (update) { | |
1909 if (minimized) { | |
1910 if (shells[i].isVisible ()) { | |
1911 shells[i].showWithParent = true; | |
1912 OS.gtk_widget_hide(shells[i].shellHandle); | |
1913 } | |
1914 } else { | |
1915 if (shells[i].showWithParent) { | |
1916 shells[i].showWithParent = false; | |
1917 OS.gtk_widget_show(shells[i].shellHandle); | |
1918 } | |
1919 } | |
1920 } | |
1921 } | |
1922 } | |
1923 | |
1924 override void deregister () { | |
1925 super.deregister (); | |
1926 display.removeWidget (shellHandle); | |
1927 } | |
1928 | |
1929 override public void dispose () { | |
1930 /* | |
1931 * Note: It is valid to attempt to dispose a widget | |
1932 * more than once. If this happens, fail silently. | |
1933 */ | |
1934 if (isDisposed()) return; | |
1935 fixActiveShell (); | |
1936 OS.gtk_widget_hide (shellHandle); | |
1937 super.dispose (); | |
1938 } | |
1939 | |
1940 /** | |
1941 * If the receiver is visible, moves it to the top of the | |
1942 * drawing order for the display on which it was created | |
1943 * (so that all other shells on that display, which are not | |
1944 * the receiver's children will be drawn behind it) and forces | |
1945 * the window manager to make the shell active. | |
1946 * | |
1947 * @exception SWTException <ul> | |
1948 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1949 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1950 * </ul> | |
1951 * | |
1952 * @since 2.0 | |
1953 * @see Control#moveAbove | |
1954 * @see Control#setFocus | |
1955 * @see Control#setVisible | |
1956 * @see Display#getActiveShell | |
1957 * @see Decorations#setDefaultButton(Button) | |
1958 * @see Shell#open | |
1959 * @see Shell#setActive | |
1960 */ | |
1961 public void forceActive () { | |
1962 checkWidget (); | |
1963 bringToTop (true); | |
1964 } | |
1965 | |
1966 override public Rectangle getBounds () { | |
1967 checkWidget (); | |
1968 int x, y ; | |
1969 OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x, &y); | |
1970 int width = OS.GTK_WIDGET_WIDTH (vboxHandle); | |
1971 int height = OS.GTK_WIDGET_HEIGHT (vboxHandle); | |
1972 int border = 0; | |
1973 if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) { | |
1974 border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle); | |
1975 } | |
1976 return new Rectangle (x, y, width + trimWidth () + 2*border, height + trimHeight () + 2*border); | |
1977 } | |
1978 | |
1979 override void releaseHandle () { | |
1980 super.releaseHandle (); | |
1981 shellHandle = null; | |
1982 } | |
1983 | |
1984 override void releaseChildren (bool destroy) { | |
1985 Shell [] shells = getShells (); | |
1986 for (int i=0; i<shells.length; i++) { | |
1987 Shell shell = shells [i]; | |
1988 if (shell !is null && !shell.isDisposed ()) { | |
1989 shell.release (false); | |
1990 } | |
1991 } | |
1992 super.releaseChildren (destroy); | |
1993 } | |
1994 | |
1995 override void releaseWidget () { | |
1996 super.releaseWidget (); | |
1997 destroyAccelGroup (); | |
1998 display.clearModal (this); | |
1999 if (display.activeShell is this) display.activeShell = null; | |
2000 if (tooltipsHandle !is null) OS.g_object_unref (tooltipsHandle); | |
2001 tooltipsHandle = null; | |
2002 if (group !is null) OS.g_object_unref (group); | |
2003 group = modalGroup = null; | |
2004 auto window = OS.GTK_WIDGET_WINDOW (shellHandle); | |
2005 display.doWindowRemoveFilter( &filterProcCallbackData, window, shellHandle ); | |
2006 | |
2007 lastActive = null; | |
2008 } | |
2009 | |
2010 void setToolTipText (GtkWidget* tipWidget, String string) { | |
2011 setToolTipText (tipWidget, tipWidget, string); | |
2012 } | |
2013 | |
2014 void setToolTipText (GtkWidget* rootWidget, GtkWidget* tipWidget, String string) { | |
2015 if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) { | |
2016 char * buffer = null; | |
2017 if (string !is null && string.length > 0) { | |
2018 char [] chars = fixMnemonic (string, false); | |
2019 buffer = toStringz( chars ); | |
2020 } | |
2021 OS.gtk_widget_set_tooltip_text (rootWidget, null); | |
2022 /* | |
2023 * Bug in GTK. In GTK 2.12, due to a miscalculation of window | |
2024 * coordinates, using gtk_tooltip_trigger_tooltip_query () | |
2025 * to update an existing a tooltip will result in the tooltip | |
2026 * being displayed at a wrong position. The fix is to send out | |
2027 * 2 fake GDK_MOTION_NOTIFY events (to mimic the GTK call) which | |
2028 * contain the proper x and y coordinates. | |
2029 */ | |
2030 GdkEvent* eventPtr = null; | |
2031 auto tipWindow = OS.GTK_WIDGET_WINDOW (rootWidget); | |
2032 if (tipWindow !is null) { | |
2033 int x, y; | |
2034 auto window = OS.gdk_window_at_pointer (&x, &y); | |
2035 void* user_data; | |
2036 if( window !is null ) OS.gdk_window_get_user_data (window, &user_data); | |
2037 if (tipWidget is user_data ) { | |
2038 eventPtr = OS.gdk_event_new (OS.GDK_MOTION_NOTIFY); | |
2039 eventPtr.type = OS.GDK_MOTION_NOTIFY; | |
2040 eventPtr.motion.window = cast(GdkDrawable*)OS.g_object_ref (tipWindow); | |
2041 eventPtr.motion.x = x; | |
2042 eventPtr.motion.y = y; | |
2043 OS.gdk_window_get_origin (window, &x, &y); | |
2044 eventPtr.motion.x_root = eventPtr.motion.x + x; | |
2045 eventPtr.motion.y_root = eventPtr.motion.y + y; | |
2046 OS.gtk_main_do_event (eventPtr); | |
2047 } | |
2048 } | |
2049 OS.gtk_widget_set_tooltip_text (rootWidget, buffer); | |
2050 if (eventPtr !is null) { | |
2051 OS.gtk_main_do_event (eventPtr); | |
2052 OS.gdk_event_free (eventPtr); | |
2053 } | |
2054 } else { | |
2055 char* buffer = null; | |
2056 if (string !is null && string.length > 0) { | |
2057 char [] chars = fixMnemonic (string, false); | |
2058 buffer = toStringz( chars ); | |
2059 } | |
2060 if (tooltipsHandle is null) { | |
2061 tooltipsHandle = cast(GtkWidget*)OS.gtk_tooltips_new (); | |
2062 if (tooltipsHandle is null) error (SWT.ERROR_NO_HANDLES); | |
2063 OS.g_object_ref (tooltipsHandle); | |
2064 OS.gtk_object_sink (cast(GtkObject*)tooltipsHandle); | |
2065 } | |
2066 | |
2067 /* | |
2068 * Feature in GTK. There is no API to position a tooltip. | |
2069 * The fix is to connect to the size_allocate signal for | |
2070 * the tooltip window and position it before it is mapped. | |
2071 * | |
2072 * Bug in Solaris-GTK. Invoking gtk_tooltips_force_window() | |
2073 * can cause a crash in older versions of GTK. The fix is | |
2074 * to avoid this call if the GTK version is older than 2.2.x. | |
2075 */ | |
2076 if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 1)) { | |
2077 OS.gtk_tooltips_force_window (cast(GtkTooltips*)tooltipsHandle); | |
2078 } | |
2079 auto tipWindow = OS.GTK_TOOLTIPS_TIP_WINDOW (cast(GtkTooltips*)tooltipsHandle); | |
2080 if (tipWindow !is null && tipWindow !is tooltipWindow) { | |
2081 display.doSizeAllocateConnect( &sizeAllocateProcCallbackData, tipWindow, shellHandle ); | |
2082 tooltipWindow = tipWindow; | |
2083 } | |
2084 | |
2085 /* | |
2086 * Bug in GTK. If the cursor is inside the window when a new | |
2087 * tooltip is set and the old tooltip is hidden, the new tooltip | |
2088 * is not displayed until the mouse re-enters the window. The | |
2089 * fix is force the new tooltip to be active. | |
2090 */ | |
2091 bool set = true; | |
2092 if (tipWindow !is null) { | |
2093 if ((OS.GTK_WIDGET_FLAGS (tipWidget) & (OS.GTK_REALIZED | OS.GTK_VISIBLE)) !is 0) { | |
2094 int x, y; | |
2095 auto window = OS.gdk_window_at_pointer (&x, &y); | |
2096 if (window !is null) { | |
2097 GtkWidget* user_data; | |
2098 OS.gdk_window_get_user_data (window, cast(void**)&user_data); | |
2099 if (tipWidget is user_data) { | |
2100 /* | |
2101 * Feature in GTK. Calling gtk_tooltips_set_tip() positions and | |
2102 * shows the tooltip. If the tooltip is already visible, moving | |
2103 * it to a new location in the size_allocate signal causes flashing. | |
2104 * The fix is to hide the tip window in the size_request signal | |
2105 * and before the new tooltip is forced to be active. | |
2106 */ | |
2107 set = false; | |
2108 int handler_id = display.doSizeRequestConnect( &sizeRequestProcCallbackData, tipWindow, shellHandle ); | |
2109 OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null); | |
2110 OS.gtk_widget_hide (tipWindow); | |
2111 auto data = OS.gtk_tooltips_data_get (tipWidget); | |
2112 OS.GTK_TOOLTIPS_SET_ACTIVE (cast(GtkTooltips*)tooltipsHandle, cast(GtkTooltipsData*)data); | |
2113 OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null); | |
2114 if (handler_id !is 0) OS.g_signal_handler_disconnect (tipWindow, handler_id); | |
2115 } | |
2116 } | |
2117 } | |
2118 } | |
2119 if (set) OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null); | |
2120 } | |
2121 | |
2122 } | |
2123 } |