1 /***********************************************************/
2 /*                                                         */
3 /*  System dependent window management (unix, x11)         */
4 /*                                                         */
5 /***********************************************************/
6 
7 #include "unix/guts.h"
8 #include "Menu.h"
9 #include "Icon.h"
10 #include "Window.h"
11 #include "Application.h"
12 
13 /* Tell a NET-compliant window manager that the window needs special treatment.
14 	See freedesktop.org for docs
15 
16 	params - 0 - clear, 1 - set
17 */
18 static void
set_net_hint(XWindow window,Bool state,Atom prop1,Atom prop2)19 set_net_hint(XWindow window, Bool state, Atom prop1, Atom prop2)
20 {
21 	XClientMessageEvent ev;
22 
23 	if ( guts. icccm_only) return;
24 
25 	/* Send change message to root window, it's responsible for
26 		on-the-fly changes. Otherwise, the properties are not re-read
27 		until next XMapWindow() */
28 	bzero( &ev, sizeof(ev));
29 	ev. type = ClientMessage;
30 	ev. display = DISP;
31 	ev. window = window;
32 	ev. message_type = NET_WM_STATE;
33 	ev. format = 32;
34 
35 	/*
36 		_NET_WM_STATE_REMOVE        0    // remove/unset property
37 		_NET_WM_STATE_ADD           1    // add/set property
38 		_NET_WM_STATE_TOGGLE        2    // toggle property
39 	*/
40 
41 	ev. data. l[0] = state ? 1 : 0;
42 	ev. data. l[1] = (long)prop1;
43 	ev. data. l[2] = (long)prop2;
44 	XSendEvent( DISP, guts. root, false, SubstructureRedirectMask|SubstructureNotifyMask, (XEvent*)&ev);
45 }
46 
47 #define NETWM_SET_TASK_LISTED(xwindow,flag) set_net_hint(xwindow,flag,NET_WM_STATE_SKIP_TASKBAR,0)
48 #define NETWM_SET_MODAL(xwindow,flag)       set_net_hint(xwindow,flag,NET_WM_STATE_MODAL,0)
49 #define NETWM_SET_MAXIMIZED(xwindow,flag)   set_net_hint(xwindow,flag,NET_WM_STATE_MAXIMIZED_VERT,NET_WM_STATE_MAXIMIZED_HORZ)
50 #define NETWM_SET_ON_TOP(xwindow,flag)      set_net_hint(xwindow,flag,NET_WM_STATE_STAYS_ON_TOP,NET_WM_STATE_ABOVE)
51 
52 unsigned char *
prima_get_window_property(XWindow window,Atom property,Atom req_type,Atom * actual_type,int * actual_format,unsigned long * nitems)53 prima_get_window_property( XWindow window, Atom property, Atom req_type, Atom * actual_type,
54 									int * actual_format, unsigned long * nitems)
55 {
56 	Atom a_actual_type;
57 	unsigned char * ret, * ptr;
58 	unsigned long left, n, a_nitems;
59 	int a_actual_format, curr_size, new_size, malloc_size, offset;
60 
61 	ret = NULL;
62 	offset = 0;
63 	new_size = curr_size = malloc_size = 0;
64 	if ( actual_type   == NULL) actual_type   = &a_actual_type;
65 	if ( actual_format == NULL) actual_format = &a_actual_format;
66 	if ( nitems        == NULL) nitems        = &a_nitems;
67 
68 	*nitems = 0;
69 
70 	while ( XGetWindowProperty( DISP, window, property, offset, 2048, false, req_type,
71 			actual_type, actual_format, &n, &left, &ptr) == Success) {
72 		if ( ptr) {
73 			if ( n > 0) {
74 				if ( *actual_format == 32) *actual_format = sizeof(long) * 8; /* MUAHAHA!! That's even documented now */
75 				curr_size = n * *actual_format / 8;
76 				new_size += curr_size;
77 				offset += curr_size / 4;
78 				*nitems += n;
79 
80 				if ( ret == NULL) {
81 					malloc_size = new_size;
82 					ret = malloc( malloc_size);
83 					if ( ret == NULL) {
84 						warn("Not enough memory: %d bytes\n", malloc_size);
85 						return NULL;
86 					}
87 				} else {
88 					if ( new_size > malloc_size) {
89 							unsigned char * p;
90 							malloc_size = new_size * 2;
91 							p = realloc( ret, malloc_size);
92 							if ( p) {
93 								ret = p;
94 							} else {
95 								free( ret);
96 								warn("Not enough memory: %d bytes\n", malloc_size);
97 								return NULL;
98 							}
99 					}
100 				}
101 				memcpy( ret + new_size - curr_size, ptr, curr_size);
102 			}
103 			XFree( ptr);
104 		}
105 		if ( left <= 0) break;
106 	}
107 
108 	return ret;
109 }
110 
111 Bool
prima_wm_net_state_read_maximization(XWindow window,Atom property)112 prima_wm_net_state_read_maximization( XWindow window, Atom property)
113 /*
114 	reads property, returns true if it has both vertical and horizontal properties set.
115 */
116 {
117 	long * prop;
118 	unsigned long i, n;
119 	int horiz = 0, vert = 0;
120 
121 	if ( guts. icccm_only) return false;
122 
123 	prop = ( long *) prima_get_window_property( window, property, XA_ATOM, NULL, NULL, &n);
124 	if ( !prop) return false;
125 
126 	for ( i = 0; i < n; i++) {
127 		if ( prop[i] == NET_WM_STATE_MAXIMIZED_VERT) vert = 1;
128 		/* KDE v2 defines _HORIZ, KDE v3 defines _HORZ - a horrible hack follows */
129 		else if ( prop[i] == guts. atoms[ AI_NET_WM_STATE_MAXIMIZED_HORZ]) {
130 			if ( guts. net_wm_maximize_HORZ_vs_HORIZ == 0) {
131 				guts. net_wm_maximize_HORZ_vs_HORIZ = AI_NET_WM_STATE_MAXIMIZED_HORZ;
132 				Mdebug("wm: kde-3 style detected\n");
133 			}
134 			horiz = 1;
135 		}
136 		else if ( prop[i] == guts. atoms[ AI_NET_WM_STATE_MAXIMIZED_HORIZ]) {
137 			if ( guts. net_wm_maximize_HORZ_vs_HORIZ == 0) {
138 				guts. net_wm_maximize_HORZ_vs_HORIZ = AI_NET_WM_STATE_MAXIMIZED_HORIZ;
139 				Mdebug("wm: kde-2 style detected\n");
140 			}
141 			horiz = 1;
142 		}
143 	}
144 
145 	free( prop);
146 	return vert && horiz;
147 }
148 
149 static Bool
net_supports_maximization(void)150 net_supports_maximization(void)
151 /* If WM supports customization, root.NET_SUPPORTED contains NET_WM_STATE_MAXIMIZED atoms.
152 	Stores result in guts. net_wm_maximization, so ConfigureEvent handler doesn't apply
153 	maximization heuristics. */
154 {
155 	Bool has_max;
156 	has_max = prima_wm_net_state_read_maximization( guts. root, NET_SUPPORTED);
157 	if ( has_max != guts. net_wm_maximization) {
158 		guts. net_wm_maximization = has_max;
159 		Mdebug( has_max ? "wm: supports maximization\n" : "win: WM quits supporting maximization\n");
160 	}
161 	return has_max;
162 }
163 
164 static void
apc_window_task_listed(Handle self,Bool task_list)165 apc_window_task_listed( Handle self, Bool task_list)
166 {
167 	DEFXX;
168 	XX-> flags. task_listed = ( task_list ? 1 : 0);
169 	NETWM_SET_TASK_LISTED( X_WINDOW, XX-> flags.task_listed );
170 }
171 
172 /* Motif window hints */
173 #define MWM_HINTS_FUNCTIONS           (1L << 0)
174 #define MWM_HINTS_DECORATIONS         (1L << 1)
175 
176 /* bit definitions for MwmHints.functions */
177 #define MWM_FUNC_ALL            (1L << 0)
178 #define MWM_FUNC_RESIZE         (1L << 1)
179 #define MWM_FUNC_MOVE           (1L << 2)
180 #define MWM_FUNC_MINIMIZE       (1L << 3)
181 #define MWM_FUNC_MAXIMIZE       (1L << 4)
182 #define MWM_FUNC_CLOSE          (1L << 5)
183 
184 /* bit definitions for MwmHints.decorations */
185 #define MWM_DECOR_ALL                 (1L << 0)
186 #define MWM_DECOR_BORDER              (1L << 1)
187 #define MWM_DECOR_RESIZEH             (1L << 2)
188 #define MWM_DECOR_TITLE               (1L << 3)
189 #define MWM_DECOR_MENU                (1L << 4)
190 #define MWM_DECOR_MINIMIZE            (1L << 5)
191 #define MWM_DECOR_MAXIMIZE            (1L << 6)
192 
193 static void
set_motif_hints(XWindow window,int border_style,int border_icons)194 set_motif_hints( XWindow window, int border_style, int border_icons)
195 {
196 	struct {
197 	unsigned long flags, functions, decorations;
198 	long  input_mode;
199 	unsigned long status;
200 	} mwmhints;
201 
202 
203 #define MWMHINT_OR(field,value) mwmhints.field |= (value)
204 
205 	if ( guts. icccm_only) return;
206 
207 	bzero( &mwmhints, sizeof(mwmhints));
208 	MWMHINT_OR( flags, MWM_HINTS_DECORATIONS);
209 	MWMHINT_OR( flags, MWM_HINTS_FUNCTIONS);
210 	if ( border_style == bsSizeable) {
211 		MWMHINT_OR( decorations, MWM_DECOR_BORDER);
212 		MWMHINT_OR( decorations, MWM_DECOR_RESIZEH);
213 		MWMHINT_OR( functions, MWM_FUNC_RESIZE);
214 	}
215 	MWMHINT_OR( functions, MWM_FUNC_MOVE);
216 	MWMHINT_OR( functions, MWM_FUNC_CLOSE);
217 	if ( border_icons & biTitleBar)
218 		MWMHINT_OR( decorations, MWM_DECOR_TITLE);
219 	if ( border_icons & biSystemMenu)
220 		MWMHINT_OR( decorations, MWM_DECOR_MENU);
221 	if ( border_icons & biMinimize) {
222 		MWMHINT_OR( decorations, MWM_DECOR_MINIMIZE);
223 		MWMHINT_OR( functions, MWM_FUNC_MINIMIZE);
224 	}
225 	if (( border_icons & biMaximize) && ( border_style == bsSizeable)) {
226 		MWMHINT_OR( decorations, MWM_DECOR_MAXIMIZE);
227 		MWMHINT_OR( functions, MWM_FUNC_MAXIMIZE);
228 	}
229 
230 	XChangeProperty(DISP, window, XA_MOTIF_WM_HINTS, XA_MOTIF_WM_HINTS, 32,
231 		PropModeReplace, (unsigned char *) &mwmhints, 5);
232 }
233 
234 Bool
apc_window_create(Handle self,Handle owner,Bool sync_paint,int border_icons,int border_style,Bool task_list,int window_state,int on_top,Bool use_origin,Bool use_size,Bool layered)235 apc_window_create( Handle self, Handle owner, Bool sync_paint, int border_icons,
236 						int border_style, Bool task_list, int window_state,
237 						int on_top, Bool use_origin, Bool use_size, Bool layered)
238 {
239 	DEFXX;
240 	Handle real_owner;
241 	XSizeHints hints;
242 	XSetWindowAttributes attrs;
243 	Point p0 = {0,0};
244 	Atom atoms[ 2];
245 	XWMHints wmhints;
246 	XClassHint *class_hint;
247 	ConfigureEventPair *cep;
248 	unsigned long valuemask;
249 	Bool recreate;
250 	ViewProfile vprf;
251 	XWindow old = X_WINDOW;
252 
253 	if ( border_style != bsSizeable) border_style = bsDialog;
254 	border_icons &= biAll;
255 
256 	if ( !guts. argb_visual. visual || guts. argb_visual. visualid == guts. visual. visualid)
257 		layered = false;
258 
259 	recreate = X_WINDOW ? (layered != XX->flags.layered) : false;
260 	if ( recreate ) {
261 		int i, count;
262 		Handle * list;
263 		XEvent dummy_ev;
264 
265 		list  = PWidget(self)-> widgets. items;
266 		count = PWidget(self)-> widgets. count;
267 		CWidget(self)-> end_paint_info( self);
268 		CWidget(self)-> end_paint( self);
269 		prima_release_gc( XX);
270 		for( i = 0; i < count; i++)
271 			prima_get_view_ex( list[ i], ( ViewProfile*)( X( list[ i])-> recreateData = malloc( sizeof( ViewProfile))));
272 
273 		if ( XX-> recreateData) {
274 			memcpy( &vprf, XX-> recreateData, sizeof( vprf));
275 			free( XX-> recreateData);
276 			XX-> recreateData = NULL;
277 		} else
278 			prima_get_view_ex( self, &vprf);
279 		if ( guts. currentMenu && PComponent( guts. currentMenu)-> owner == self) prima_end_menu();
280 		apc_window_set_menu( self, NULL_HANDLE);
281 		CWidget( self)-> end_paint_info( self);
282 		CWidget( self)-> end_paint( self);
283 		if ( XX-> flags. paint_pending) {
284 			TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
285 			XX-> flags. paint_pending = false;
286 		}
287 		/* flush configure events */
288 		XSync( DISP, false);
289 		while ( XCheckIfEvent( DISP, &dummy_ev, (XIfEventProcType)prima_flush_events, (XPointer)self));
290 		hash_delete( guts.windows, (void*)&old, sizeof(old), false);
291 		hash_delete( guts.windows, (void*)&(XX->client), sizeof(XX->client), false);
292 		X_WINDOW = 0;
293 		XCHECKPOINT;
294 	}
295 
296 	if ( X_WINDOW) { /* recreate request */
297 		Bool destructive_motif_hints = 0; /* KDE 3.1: setting motif hints kills net_wm hints */
298 		if (
299 			!guts.icccm_only && (
300 				( border_style != ( XX-> flags. sizeable ? bsSizeable : bsDialog)) ||
301 				( border_icons != XX-> borderIcons) ||
302 			( on_top >= 0)
303 		)) {
304 			if (( border_style != ( XX-> flags. sizeable ? bsSizeable : bsDialog)) ||
305 				( border_icons != XX-> borderIcons))
306 				destructive_motif_hints = 1;
307 			if ( destructive_motif_hints && on_top < 0)
308 				on_top = apc_window_get_on_top( self);
309 			if ( destructive_motif_hints)
310 				set_motif_hints( X_WINDOW, border_style, border_icons);
311 			if ( on_top >= 0)
312 				NETWM_SET_ON_TOP( X_WINDOW, on_top);
313 			XX-> borderIcons = border_icons;
314 			XX-> flags. sizeable = ( border_style == bsSizeable) ? 1 : 0;
315 		}
316 		if (
317 			(( task_list ? 1 : 0) != ( XX-> flags. task_listed ? 1 : 0))
318 			|| destructive_motif_hints
319 		)
320 			apc_window_task_listed( self, task_list);
321 		return true;
322 	}
323 
324 	XX-> visual   = layered ? &guts. argb_visual : &guts. visual;
325 	XX-> colormap = layered ? guts. argbColormap : guts. defaultColormap;
326 	XX-> flags. layered    = !!layered;
327 
328 	/* create */
329 	attrs. event_mask = 0
330 		| KeyPressMask              /* Key events unmasked for both windows, since */
331 		| KeyReleaseMask            /* focusing is unpredicatble for some WM */
332 		/*| ButtonPressMask */
333 		/*| ButtonReleaseMask */
334 		/*| EnterWindowMask */
335 		/*| LeaveWindowMask */
336 		/*| PointerMotionMask */
337 		/* | PointerMotionHintMask */
338 		/* | Button1MotionMask */
339 		/* | Button2MotionMask */
340 		/* | Button3MotionMask */
341 		/* | Button4MotionMask */
342 		/* | Button5MotionMask */
343 		/*| ButtonMotionMask */
344 		/*| KeymapStateMask */
345 		| ExposureMask
346 		| VisibilityChangeMask
347 		| StructureNotifyMask
348 		/* | ResizeRedirectMask */
349 		/* | SubstructureNotifyMask */
350 		/* | SubstructureRedirectMask */
351 		| FocusChangeMask
352 		| PropertyChangeMask
353 		| ColormapChangeMask
354 		| OwnerGrabButtonMask;
355 	attrs. override_redirect = false;
356 	attrs. do_not_propagate_mask = attrs. event_mask;
357 	attrs. colormap = XX-> colormap;
358 	valuemask =
359 			0
360 		/* | CWBackPixmap */
361 		/* | CWBackPixel */
362 		/* | CWBorderPixmap */
363 		/* | CWBorderPixel */
364 		/* | CWBitGravity */
365 		/* | CWWinGravity */
366 		/* | CWBackingStore */
367 		/* | CWBackingPlanes */
368 		/* | CWBackingPixel */
369 		| CWOverrideRedirect
370 		/* | CWSaveUnder */
371 		| CWEventMask
372 		/* | CWDontPropagate */
373 			| CWColormap
374 		/* | CWCursor */
375 		;
376 	if ( layered ) {
377 		valuemask |= CWBackPixel | CWBorderPixel;
378 		attrs. background_pixel = 0;
379 		attrs. border_pixel = 0;
380 	}
381 	X_WINDOW = XCreateWindow( DISP, guts. root,
382 				0, 0, 1, 1, 0, XX-> visual->depth,
383 				InputOutput, XX->visual->visual,
384 				valuemask, &attrs);
385 	if (!X_WINDOW) return false;
386 
387 	attrs. event_mask = 0
388 		| KeyPressMask
389 		| KeyReleaseMask
390 		| ButtonPressMask
391 		| ButtonReleaseMask
392 		| EnterWindowMask
393 		| LeaveWindowMask
394 		| PointerMotionMask
395 		/* | PointerMotionHintMask */
396 		/* | Button1MotionMask */
397 		/* | Button2MotionMask */
398 		/* | Button3MotionMask */
399 		/* | Button4MotionMask */
400 		/* | Button5MotionMask */
401 		| ButtonMotionMask
402 		| KeymapStateMask
403 		| ExposureMask
404 		| VisibilityChangeMask
405 		| StructureNotifyMask
406 		/* | ResizeRedirectMask */
407 		/* | SubstructureNotifyMask */
408 		/* | SubstructureRedirectMask */
409 		| FocusChangeMask
410 		| PropertyChangeMask
411 		| ColormapChangeMask
412 		| OwnerGrabButtonMask;
413 	attrs. override_redirect = false;
414 	attrs. do_not_propagate_mask = attrs. event_mask;
415 	attrs. colormap = XX->colormap;
416 
417 	valuemask =
418 		0
419 		/* | CWBackPixmap */
420 		/* | CWBackPixel */
421 		/* | CWBorderPixmap */
422 		/* | CWBorderPixel */
423 		/* | CWBitGravity */
424 		/* | CWWinGravity */
425 		/* | CWBackingStore */
426 		/* | CWBackingPlanes */
427 		/* | CWBackingPixel */
428 		| CWOverrideRedirect
429 		/* | CWSaveUnder */
430 		| CWEventMask
431 		/* | CWDontPropagate */
432 			| CWColormap
433 		/* | CWCursor */
434 		;
435 	if ( layered ) {
436 		valuemask |= CWBackPixel | CWBorderPixel;
437 		attrs. background_pixel = 0;
438 		attrs. border_pixel = 0;
439 	}
440 
441 	XX-> client = XCreateWindow( DISP, X_WINDOW,
442 		0, 0, 1, 1, 0, XX->visual->depth,
443 		InputOutput, XX-> visual-> visual,
444 		valuemask, &attrs);
445 	if (!XX-> client) return false;
446 
447 	hash_store( guts.windows, &XX-> client, sizeof(XX-> client), (void*)self);
448 	hash_store( guts.windows, &X_WINDOW, sizeof(X_WINDOW), (void*)self);
449 	XCHECKPOINT;
450 	XMapWindow( DISP, XX-> client);
451 
452 	XX-> flags. iconic = ( window_state == wsMinimized) ? 1 : 0;
453 	wmhints. flags = InputHint | StateHint;
454 	wmhints. input = false;
455 	wmhints. initial_state = XX-> flags. iconic ? IconicState : NormalState;
456 	XSetWMHints( DISP, X_WINDOW, &wmhints);
457 	XCHECKPOINT;
458 
459 	atoms[ 0] = WM_DELETE_WINDOW;
460 	atoms[ 1] = WM_TAKE_FOCUS;
461 	XSetWMProtocols( DISP, X_WINDOW, atoms, 2);
462 	XCHECKPOINT;
463 
464 	if (( class_hint = XAllocClassHint()) != NULL) {
465 		class_hint-> res_class  = PComponent(application)-> name;
466 		class_hint-> res_name = CObject( self)-> className;
467 		XSetClassHint( DISP, X_WINDOW, class_hint);
468 		XFree (class_hint);
469 	}
470 
471 	if ( guts. hostname. value)
472 		XSetWMClientMachine(DISP, X_WINDOW, &guts. hostname);
473 	XSetCommand(DISP, X_WINDOW, PL_origargv, PL_origargc);
474 
475 	set_motif_hints( X_WINDOW, border_style, border_icons);
476 	XX-> borderIcons = border_icons;
477 
478 	XX-> type.drawable = true;
479 	XX-> type.widget = true;
480 	XX-> type.window = true;
481 
482 	real_owner = application;
483 	XX-> parent = guts. root;
484 	XX-> real_parent = NULL_HANDLE;
485 	XX-> udrawable = XX-> gdrawable = XX-> client;
486 
487 	XX-> flags. clip_owner = false;
488 	XX-> flags. sync_paint = sync_paint;
489 	XX-> flags. task_listed = 1;
490 	XX-> flags. layered = XX-> flags. layered_requested = layered;
491 
492 	XX-> above = NULL_HANDLE;
493 	XX-> owner = real_owner;
494 
495 	if ( on_top > 0) NETWM_SET_ON_TOP( X_WINDOW, 1);
496 	apc_window_task_listed( self, task_list);
497 
498 	if (recreate) {
499 		int i;
500 		int  count = PWidget(self)->widgets. count;
501 		Handle * list = PWidget(self)->widgets. items;
502 		Point pos;
503 
504 		pos = PWidget(self)-> pos;
505 		apc_window_set_menu( self, PWindow( self)-> menu);
506 		bzero( &hints, sizeof( XSizeHints));
507 		hints. flags  = PBaseSize;
508 		hints. width  = hints. base_width  = XX-> size. x;
509 		hints. height = hints. base_height = XX-> size. y;
510 		XSetWMNormalHints( DISP, X_WINDOW, &hints);
511 		prima_set_view_ex( self, &vprf);
512 		XX-> ackOrigin = pos;
513 		XX-> ackSize   = XX-> size;
514 		XX-> flags. mapped = XX-> flags. want_visible;
515 		for ( i = 0; i < count; i++) ((( PComponent) list[ i])-> self)-> recreate( list[ i]);
516 		XDestroyWindow( DISP, old);
517 		prima_notify_sys_handle( self );
518 		return true;
519 	}
520 
521 	apc_component_fullname_changed_notify( self);
522 	prima_send_create_event( X_WINDOW);
523 	if ( border_style == bsSizeable) XX-> flags. sizeable = 1;
524 
525 	/* setting initial size */
526 	{
527 		int nrects;
528 		Box * monitors;
529 		monitors = apc_application_get_monitor_rects( NULL_HANDLE, &nrects);
530 		if ( nrects > 0 ) {
531 			int i, min_x = monitors[0].x, min_y = monitors[0].y;
532 			XX-> size.x = monitors[0].width;
533 			XX-> size.y = monitors[0].height;
534 			for ( i = 1; i < nrects; i++) {
535 				if ( min_x > monitors[i].x && min_y > monitors[i].y ) {
536 					min_x = monitors[i].x;
537 					min_y = monitors[i].y;
538 					XX-> size.x = monitors[i].width;
539 					XX-> size.y = monitors[i].height;
540 				}
541 			}
542 		} else {
543 			XX-> size = guts. displaySize;
544 		}
545 		free( monitors);
546 	}
547 
548 	if ( window_state != wsMaximized) {
549 		XX-> zoomRect. right = XX-> size. x;
550 		XX-> zoomRect. top   = XX-> size. y;
551 		XX-> size. x *= 0.75;
552 		XX-> size. y *= 0.75;
553 	} else {
554 		XX-> flags. zoomed = 1;
555 		NETWM_SET_MAXIMIZED( X_WINDOW, 1);
556 		if ( net_supports_maximization()) {
557 			XX-> zoomRect. right = XX-> size. x;
558 			XX-> zoomRect. top   = XX-> size. y;
559 			XX-> size. x *= 0.75;
560 			XX-> size. y *= 0.75;
561 		}
562 	}
563 	XX-> origin. x = XX-> origin. y =
564 	XX-> ackOrigin. x = XX-> ackOrigin. y =
565 	XX-> ackSize. x = XX-> ackSize. y =
566 	XX-> ackFrameSize. x = XX-> ackFrameSize.y = 0;
567 
568 	bzero( &hints, sizeof( XSizeHints));
569 	hints. flags  = PBaseSize;
570 	hints. width  = hints. base_width  = XX-> size. x;
571 	hints. height = hints. base_height = XX-> size. y;
572 	XSetWMNormalHints( DISP, X_WINDOW, &hints);
573 	XResizeWindow( DISP, XX-> client, XX-> size. x, XX-> size. y);
574 	XResizeWindow( DISP, X_WINDOW, XX-> size. x, XX-> size. y);
575 
576 	TAILQ_INIT( &XX-> configure_pairs);
577 	if (( cep = malloc( sizeof( ConfigureEventPair)))) {
578 		bzero( cep, sizeof( ConfigureEventPair));
579 		cep-> w = XX-> size. x;
580 		cep-> h = XX-> size. y;
581 		TAILQ_INSERT_TAIL( &XX-> configure_pairs, cep, link);
582 	}
583 
584 	prima_send_cmSize( self, p0);
585 
586 	return true;
587 }
588 
589 Bool
apc_window_activate(Handle self)590 apc_window_activate( Handle self)
591 {
592 	DEFXX;
593 	int rev;
594 	XWindow xfoc;
595 	XEvent ev;
596 
597 	if ( !XX->flags. want_visible) return true;
598 	if ( guts. message_boxes) return false;
599 	if ( self && ( self != CApplication( application)-> map_focus( application, self)))
600 		return false;
601 
602 	XMapRaised( DISP, X_WINDOW);
603 	if ( XX-> flags. iconic || XX-> flags. withdrawn)
604 		prima_wm_sync( self, MapNotify);
605 	XGetInputFocus( DISP, &xfoc, &rev);
606 	if ( xfoc == X_WINDOW || xfoc == XX-> client) return true;
607 	XSetInputFocus( DISP, XX-> client, RevertToParent, guts. currentFocusTime);
608 	XCHECKPOINT;
609 
610 	XSync( DISP, false);
611 	while ( XCheckMaskEvent( DISP, FocusChangeMask|ExposureMask, &ev))
612 		prima_handle_event( &ev, NULL);
613 	return true;
614 }
615 
616 Bool
apc_window_is_active(Handle self)617 apc_window_is_active( Handle self)
618 {
619 	return apc_window_get_active() == self;
620 }
621 
622 Bool
apc_window_close(Handle self)623 apc_window_close( Handle self)
624 {
625 	return prima_simple_message( self, cmClose, true);
626 }
627 
628 Handle
apc_window_get_active(void)629 apc_window_get_active( void)
630 {
631 	Handle x = guts. focused;
632 	while ( x && !X(x)-> type. window) x = PWidget(x)-> owner;
633 	return x;
634 }
635 
636 int
apc_window_get_border_icons(Handle self)637 apc_window_get_border_icons( Handle self)
638 {
639 	return X(self)-> borderIcons;
640 }
641 
642 int
apc_window_get_border_style(Handle self)643 apc_window_get_border_style( Handle self)
644 {
645 	return X(self)-> flags. sizeable ? bsSizeable : bsDialog;
646 }
647 
648 ApiHandle
apc_window_get_client_handle(Handle self)649 apc_window_get_client_handle( Handle self)
650 {
651 	return X(self)-> client;
652 }
653 
654 Point
apc_window_get_client_pos(Handle self)655 apc_window_get_client_pos( Handle self)
656 {
657 	if ( !X(self)-> flags. configured) prima_wm_sync( self, ConfigureNotify);
658 	return X(self)-> origin;
659 }
660 
661 Point
apc_window_get_client_size(Handle self)662 apc_window_get_client_size( Handle self)
663 {
664 	if ( !X(self)-> flags. configured) prima_wm_sync( self, ConfigureNotify);
665 	return X(self)-> size;
666 }
667 
668 Bool
apc_window_get_icon(Handle self,Handle icon)669 apc_window_get_icon( Handle self, Handle icon)
670 {
671 	XWMHints * hints;
672 	Pixmap xor, and;
673 	unsigned int xx, xy, ax, ay, xd, ad;
674 	Bool ret;
675 
676 	if ( !icon)
677 		return X(self)-> flags. has_icon ? true : false;
678 	else
679 		if ( !X(self)-> flags. has_icon) return false;
680 
681 	if ( !( hints = XGetWMHints( DISP, X_WINDOW))) return false;
682 	if ( !icon || !hints-> icon_pixmap) {
683 		Bool ret = hints-> icon_pixmap != NULL_HANDLE;
684 		XFree( hints);
685 		return ret;
686 	}
687 	xor = hints-> icon_pixmap;
688 	and = hints-> icon_mask;
689 	XFree( hints);
690 
691 	{
692 		XWindow foo;
693 		unsigned int bar;
694 		int bar2;
695 		if ( !XGetGeometry( DISP, xor, &foo, &bar2, &bar2, &xx, &xy, &bar, &xd))
696 			return false;
697 		if ( and && (!XGetGeometry( DISP, and, &foo, &bar2, &bar2, &ax, &ay, &bar, &ad)))
698 			return false;
699 	}
700 
701 	CImage( icon)-> create_empty( icon, xx, xy, ( xd == 1) ? 1 : guts. qdepth);
702 	if ( !prima_std_query_image( icon, xor)) return false;
703 
704 	if ( and) {
705 		Handle mask = (Handle) create_object( "Prima::Image", "");
706 		CImage( mask)-> create_empty( mask, ax, ay, ( ad == 1) ? imBW : guts. qdepth);
707 		ret = prima_std_query_image( mask, and);
708 		if (( PImage( mask)-> type & imBPP) != 1)
709 			CImage( mask)-> type( mask, true, imBW);
710 		if ( ret) {
711 			int i;
712 			Byte *d = PImage(mask)-> data;
713 			for ( i = 0; i < PImage(mask)-> dataSize; i++, d++)
714 				*d = ~(*d);
715 		} else
716 			bzero( PImage( mask)-> data, PImage( mask)-> dataSize);
717 		if ( xx != ax || xy != ay)  {
718 			Point p;
719 			p.x = xx;
720 			p.y = xy;
721 			CImage( mask)-> size( mask, true, p);
722 		}
723 		memcpy( PIcon( icon)-> mask, PImage( mask)-> data, PIcon( icon)-> maskSize);
724 		Object_destroy( mask);
725 	}
726 
727 	return true;
728 }
729 
730 int
apc_window_get_window_state(Handle self)731 apc_window_get_window_state( Handle self)
732 {
733 	return (X(self)-> flags. iconic != 0) ? wsMinimized :
734 	((X(self)-> flags. zoomed != 0) ? wsMaximized : wsNormal);
735 }
736 
737 Bool
apc_window_get_task_listed(Handle self)738 apc_window_get_task_listed( Handle self)
739 {
740 	return X(self)-> flags. task_listed;
741 }
742 
743 Bool
apc_window_set_caption(Handle self,const char * caption,Bool utf8)744 apc_window_set_caption( Handle self, const char *caption, Bool utf8)
745 {
746 	XTextProperty p;
747 
748 	if ( utf8) {
749 		if ( Xutf8TextListToTextProperty(DISP, ( char **) &caption, 1,
750 #ifdef X_HAVE_UTF8_STRING
751 			XUTF8StringStyle,
752 #else
753 			XCompoundTextStyle,
754 #endif
755 			&p) >= Success) {
756 			XSetWMIconName( DISP, X_WINDOW, &p);
757 			XSetWMName( DISP, X_WINDOW, &p);
758 			XFree( p. value);
759 		}
760 		XChangeProperty( DISP, X_WINDOW, NET_WM_NAME, UTF8_STRING, 8,
761 			PropModeReplace, ( unsigned char*) caption, strlen( caption) + 1);
762 		XChangeProperty( DISP, X_WINDOW, NET_WM_ICON_NAME, UTF8_STRING, 8,
763 			PropModeReplace, ( unsigned char*) caption, strlen( caption) + 1);
764 		X(self)->flags. title_utf8 = 1;
765 	} else {
766 		XDeleteProperty( DISP, X_WINDOW, NET_WM_NAME);
767 		XDeleteProperty( DISP, X_WINDOW, NET_WM_ICON_NAME);
768 		if ( XStringListToTextProperty(( char **) &caption, 1, &p) != 0) {
769 			XSetWMIconName( DISP, X_WINDOW, &p);
770 			XSetWMName( DISP, X_WINDOW, &p);
771 			XFree( p. value);
772 		}
773 		X(self)->flags. title_utf8 = 0;
774 	}
775 	XFlush( DISP);
776 	return true;
777 }
778 
779 XWindow
prima_find_frame_window(XWindow w)780 prima_find_frame_window( XWindow w)
781 {
782 	XWindow r, p, *c;
783 	unsigned int nc;
784 
785 	if ( w == None)
786 		return None;
787 	while ( XQueryTree( DISP, w, &r, &p, &c, &nc)) {
788 		if (c)
789 			XFree(c);
790 		if ( p == r)
791 			return w;
792 		w = p;
793 	}
794 	return None;
795 }
796 
797 Bool
prima_get_frame_info(Handle self,PRect r)798 prima_get_frame_info( Handle self, PRect r)
799 {
800 	DEFXX;
801 	XWindow p, dummy;
802 	int px, py;
803 	unsigned int pw, ph, pb, pd;
804 
805 	bzero( r, sizeof( Rect));
806 	p = prima_find_frame_window( X_WINDOW);
807 	if ( p == NULL_HANDLE) {
808 		r-> left = XX-> decorationSize. x;
809 		r-> top  = XX-> decorationSize. y;
810 	} else if ( p != X_WINDOW)
811 		if ( !XTranslateCoordinates( DISP, X_WINDOW, p, 0, 0, &r-> left, &r-> bottom, &dummy))
812 			warn( "error in XTranslateCoordinates()");
813 	if ( !XGetGeometry( DISP, p, &dummy, &px, &py, &pw, &ph, &pb, &pd)) {
814 		warn( "error in XGetGeometry()");
815 		r-> right = pw - r-> left  - XX-> size. x;
816 		r-> top   = ph - r-> right - XX-> size. y;
817 	}
818 	r-> top += XX-> menuHeight;
819 	return true;
820 }
821 
822 void
apc_SetWMNormalHints(Handle self,XSizeHints * hints)823 apc_SetWMNormalHints( Handle self, XSizeHints * hints)
824 {
825 	DEFXX;
826 	hints-> flags |= PMinSize | PMaxSize;
827 	if ( XX-> flags. sizeable) {
828 		int h = PWidget(self)-> sizeMin.y;
829 		if ( h == 0) h = 1;
830 		hints-> min_width  = PWidget(self)-> sizeMin.x;
831 		hints-> min_height = h + XX-> menuHeight;
832 		hints-> max_width  = PWidget(self)-> sizeMax.x;
833 		hints-> max_height = PWidget(self)-> sizeMax.y + XX-> menuHeight;
834 		if ( !XX-> flags. sizemax_set &&
835 			PWidget(self)-> sizeMax.x == 16384 &&
836 			PWidget(self)-> sizeMax.y == 16384) {
837 			hints-> flags &= ~ PMaxSize;
838 		}
839 		else
840 			XX-> flags. sizemax_set = 1;
841 	} else {
842 		Point who;
843 		who. x = ( hints-> flags & USSize) ? hints-> width  : XX-> size. x;
844 		who. y = ( hints-> flags & USSize) ? hints-> height : XX-> size. y + XX-> menuHeight;
845 		hints-> min_width  = who. x;
846 		hints-> min_height = who. y;
847 		hints-> max_width  = who. x;
848 		hints-> max_height = who. y;
849 		XX-> flags. sizemax_set = 1;
850 	}
851 	XSetWMNormalHints( DISP, X_WINDOW, hints);
852 	XCHECKPOINT;
853 }
854 
855 Bool
apc_window_set_client_pos(Handle self,int x,int y)856 apc_window_set_client_pos( Handle self, int x, int y)
857 {
858 	DEFXX;
859 	XSizeHints hints;
860 
861 	bzero( &hints, sizeof( XSizeHints));
862 
863 	if ( XX-> flags. zoomed) {
864 		XX-> zoomRect. left = x;
865 		XX-> zoomRect. bottom = y;
866 		return true;
867 	}
868 
869 	if ( x == XX-> origin. x && y == XX-> origin. y) return true;
870 	XX-> flags. position_determined = 1;
871 
872 	if ( XX-> client == guts. grab_redirect) {
873 		XWindow rx;
874 		XTranslateCoordinates( DISP, XX-> client, guts. root, 0, 0,
875 			&guts. grab_translate_mouse.x, &guts. grab_translate_mouse.y, &rx);
876 	}
877 
878 	y = guts. displaySize.y - XX-> size.y - XX-> menuHeight - y;
879 	hints. flags = USPosition;
880 	hints. x = x - XX-> decorationSize. x;
881 	hints. y = y - XX-> decorationSize. y;
882 	XMoveWindow( DISP, X_WINDOW, hints. x, hints. y);
883 	prima_wm_sync( self, ConfigureNotify);
884 	return true;
885 }
886 
887 static void
apc_window_set_rect(Handle self,int x,int y,int szx,int szy)888 apc_window_set_rect( Handle self, int x, int y, int szx, int szy)
889 {
890 	DEFXX;
891 	XSizeHints hints;
892 	Point psize = XX-> size;
893 	ConfigureEventPair *cep;
894 
895 	bzero( &hints, sizeof( XSizeHints));
896 	hints. flags = USPosition | USSize;
897 	hints. x = x - XX-> decorationSize. x;
898 	hints. y = guts. displaySize. y - szy - XX-> menuHeight - y - XX-> decorationSize. y;
899 	hints. width  = szx;
900 	hints. height = szy + XX-> menuHeight;
901 	XX-> flags. position_determined = 1;
902 	XX-> size. x = szx;
903 	XX-> size. y = szy;
904 	XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, hints. width, hints. height - XX-> menuHeight);
905 	XMoveResizeWindow( DISP, X_WINDOW, hints. x, hints. y, hints. width, hints. height);
906 	if (( cep = malloc( sizeof( ConfigureEventPair)))) {
907 		bzero( cep, sizeof( ConfigureEventPair));
908 		cep-> w = hints. width;
909 		cep-> h = hints. height;
910 		TAILQ_INSERT_TAIL( &XX-> configure_pairs, cep, link);
911 	}
912 
913 	apc_SetWMNormalHints( self, &hints);
914 	prima_send_cmSize( self, psize);
915 	if ( PObject( self)-> stage == csDead) return;
916 	prima_wm_sync( self, ConfigureNotify);
917 }
918 
919 static Bool
window_set_client_size(Handle self,int width,int height)920 window_set_client_size( Handle self, int width, int height)
921 {
922 	DEFXX;
923 	XSizeHints hints;
924 	PWidget widg = PWidget( self);
925 	Bool implicit_move = false;
926 	Point post, psize;
927 	ConfigureEventPair *cep;
928 
929 	widg-> virtualSize. x = width;
930 	widg-> virtualSize. y = height;
931 
932 	width = ( width >= widg-> sizeMin. x)
933 			? (( width <= widg-> sizeMax. x)
934 				? width
935 				: widg-> sizeMax. x)
936 			: widg-> sizeMin. x;
937 	if ( width == 0) width = 1;
938 
939 	height = ( height >= widg-> sizeMin. y)
940 			? (( height <= widg-> sizeMax. y)
941 				? height
942 				: widg-> sizeMax. y)
943 			: widg-> sizeMin. y;
944 	if ( height == 0) height = 1;
945 
946 	if ( XX-> flags. zoomed) {
947 		XX-> zoomRect. right = width;
948 		XX-> zoomRect. top   = height;
949 		return true;
950 	}
951 
952 	bzero( &hints, sizeof( XSizeHints));
953 	hints. flags = USSize | ( XX-> flags. position_determined ? USPosition : 0);
954 	post = XX-> origin;
955 	psize = XX-> size;
956 	hints. x = XX-> origin. x - XX-> decorationSize. x;
957 	hints. y = guts. displaySize.y - height - XX-> menuHeight - XX-> origin. y - XX-> decorationSize.y;
958 	hints. width = width;
959 	hints. height = height + XX-> menuHeight;
960 	XX-> size. x = width;
961 	XX-> size. y = height;
962 	apc_SetWMNormalHints( self, &hints);
963 	XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, width, height);
964 	if ( XX-> flags. position_determined) {
965 		XMoveResizeWindow( DISP, X_WINDOW, hints. x, hints. y, width, height + XX-> menuHeight);
966 		implicit_move = true;
967 	} else {
968 		XResizeWindow( DISP, X_WINDOW, width, height + XX-> menuHeight);
969 	}
970 	XCHECKPOINT;
971 	prima_send_cmSize( self, psize);
972 	if ( PObject( self)-> stage == csDead) return false;
973 	prima_wm_sync( self, ConfigureNotify);
974 	if ( implicit_move && (( XX-> origin.x != post.x) || (XX-> origin.y != post.y))) {
975 		XX-> decorationSize. x =   XX-> origin.x - post. x;
976 		XX-> decorationSize. y = - XX-> origin.y + post. y;
977 	}
978 	if (( cep = malloc( sizeof( ConfigureEventPair)))) {
979 		bzero( cep, sizeof( ConfigureEventPair));
980 		cep-> w = hints. width;
981 		cep-> h = hints. height;
982 		TAILQ_INSERT_TAIL( &XX-> configure_pairs, cep, link);
983 	}
984 	return true;
985 }
986 
987 Bool
apc_window_set_client_rect(Handle self,int x,int y,int width,int height)988 apc_window_set_client_rect( Handle self, int x, int y, int width, int height)
989 {
990 	DEFXX;
991 	PWidget widg = PWidget( self);
992 
993 	widg-> virtualSize. x = width;
994 	widg-> virtualSize. y = height;
995 
996 	width = ( width >= widg-> sizeMin. x)
997 			? (( width <= widg-> sizeMax. x)
998 				? width
999 				: widg-> sizeMax. x)
1000 			: widg-> sizeMin. x;
1001 	if ( width == 0) width = 1;
1002 
1003 	height = ( height >= widg-> sizeMin. y)
1004 			? (( height <= widg-> sizeMax. y)
1005 				? height
1006 				: widg-> sizeMax. y)
1007 			: widg-> sizeMin. y;
1008 	if ( height == 0) height = 1;
1009 
1010 	if ( XX-> flags. zoomed) {
1011 		XX-> zoomRect. left = x;
1012 		XX-> zoomRect. bottom = y;
1013 		XX-> zoomRect. right = width;
1014 		XX-> zoomRect. top   = height;
1015 		return true;
1016 	}
1017 
1018 	if ( x == XX-> origin. x && y == XX-> origin. y &&
1019 		width == XX-> size. x && height == XX-> size. y ) return true;
1020 
1021 	apc_window_set_rect( self, x, y, width, height);
1022 	return true;
1023 }
1024 
1025 
1026 Bool
apc_window_set_client_size(Handle self,int width,int height)1027 apc_window_set_client_size( Handle self, int width, int height)
1028 {
1029 	DEFXX;
1030 	if ( width == XX-> size. x && height == XX-> size. y) return true;
1031 	return window_set_client_size( self, width, height);
1032 }
1033 
1034 Bool
prima_window_reset_menu(Handle self,int newMenuHeight)1035 prima_window_reset_menu( Handle self, int newMenuHeight)
1036 {
1037 	DEFXX;
1038 	int ret = true;
1039 	if ( newMenuHeight != XX-> menuHeight) {
1040 		int oh = XX-> menuHeight;
1041 		XX-> menuHeight = newMenuHeight;
1042 		if ( PWindow(self)-> stage <= csNormal)
1043 			ret = window_set_client_size( self, XX-> size.x, XX-> size.y);
1044 		else
1045 			XX-> size. y -= newMenuHeight - oh;
1046 
1047 #ifdef HAVE_X11_EXTENSIONS_SHAPE_H
1048 	if ( XX-> shape_extent. x != 0 || XX-> shape_extent. y != 0) {
1049 		int ny = XX-> menuHeight;
1050 		if ( XX-> shape_offset. y != ny) {
1051 			XRectangle xr;
1052 			XShapeOffsetShape( DISP, X_WINDOW, ShapeBounding, 0, ny - XX-> shape_offset. y);
1053 			XX-> shape_offset. y = ny;
1054 			xr. x = 0;
1055 			xr. y = 0;
1056 			xr. width  = XX->size.x;
1057 			xr. height = XX->menuHeight;
1058 			XShapeCombineRectangles( DISP, X_WINDOW, ShapeBounding, 0, 0, &xr, 1, ShapeUnion, 0);
1059 		}
1060 	}
1061 #endif
1062 	}
1063 	return ret;
1064 }
1065 
1066 Bool
apc_window_set_visible(Handle self,Bool show)1067 apc_window_set_visible( Handle self, Bool show)
1068 {
1069 	DEFXX;
1070 
1071 	if ( show) {
1072 		if ( XX-> flags. mapped) return true;
1073 	} else {
1074 		if ( !XX-> flags. mapped) return true;
1075 	}
1076 
1077 	XX-> flags. want_visible = show;
1078 	if ( show) {
1079 		Bool iconic = XX-> flags. iconic;
1080 		if ( XX-> flags. withdrawn) {
1081 			XWMHints wh;
1082 			wh. initial_state = iconic ? IconicState : NormalState;
1083 			wh. flags = StateHint;
1084 			XSetWMHints( DISP, X_WINDOW, &wh);
1085 			XX-> flags. withdrawn = 0;
1086 		}
1087 		XMapWindow( DISP, X_WINDOW);
1088 		XX-> flags. iconic = iconic;
1089 		prima_wm_sync( self, MapNotify);
1090 	} else {
1091 		if ( XX-> flags. iconic) {
1092 			XWithdrawWindow( DISP, X_WINDOW, SCREEN);
1093 			XX-> flags. withdrawn = 1;
1094 		} else
1095 			XUnmapWindow( DISP, X_WINDOW);
1096 		prima_wm_sync( self, UnmapNotify);
1097 	}
1098 	XCHECKPOINT;
1099 	return true;
1100 }
1101 
1102 /* apc_window_set_menu is in apc_menu.c */
1103 
1104 Bool
apc_window_set_icon(Handle self,Handle icon)1105 apc_window_set_icon( Handle self, Handle icon)
1106 {
1107 	DEFXX;
1108 	PIcon i = ( PIcon) icon;
1109 	XIconSize * sz = NULL;
1110 	Pixmap xor, and;
1111 	XWMHints wmhints;
1112 	int n;
1113 
1114 	if ( !icon || i-> w == 0 || i-> h == 0) {
1115 		if ( !XX-> flags. has_icon) return true;
1116 		XX-> flags. has_icon = false;
1117 		XDeleteProperty( DISP, X_WINDOW, XA_WM_HINTS);
1118 		wmhints. flags = InputHint;
1119 		wmhints. input = false;
1120 		XSetWMHints( DISP, X_WINDOW, &wmhints);
1121 		return true;
1122 	}
1123 
1124 	if ( XGetIconSizes( DISP, guts.root, &sz, &n) && n > 0) {
1125 		int zx = sz-> min_width, zy = sz-> min_height;
1126 		while ( 1) {
1127 			if ( i-> w <= zx || i-> h <= zy) break;
1128 			zx += sz-> width_inc;
1129 			zy += sz-> height_inc;
1130 			if ( zx >= sz-> max_width || zy >= sz-> max_height) break;
1131 		}
1132 		if ( zx > sz-> max_width)  zx = sz-> max_width;
1133 		if ( zy > sz-> max_height) zy = sz-> max_height;
1134 		if (( zx != i-> w && zy != i-> h) || ( sz-> max_width != i-> w && sz-> max_height != i-> h)) {
1135 			Point z;
1136 			i = ( PIcon) i-> self-> dup( icon);
1137 			z.x = zx;
1138 			z.y = zy;
1139 			i-> self-> size(( Handle) i, true, z);
1140 		}
1141 		XFree( sz);
1142 	}
1143 
1144 	xor = prima_std_pixmap( icon, CACHE_LOW_RES);
1145 	if ( !xor) goto FAIL;
1146 	{
1147 		GC gc;
1148 		XGCValues gcv;
1149 
1150 		and = XCreatePixmap( DISP, guts. root, i-> w, i-> h, 1);
1151 		if ( !and) {
1152 			XFreePixmap( DISP, xor);
1153 			goto FAIL;
1154 		}
1155 
1156 		gcv. graphics_exposures = false;
1157 		gc = XCreateGC( DISP, and, GCGraphicsExposures, &gcv);
1158 		if ( X(icon)-> image_cache. icon) {
1159 			XSetBackground( DISP, gc, 0xffffffff);
1160 			XSetForeground( DISP, gc, 0x00000000);
1161 			prima_put_ximage( and, gc, X(icon)-> image_cache. icon, 0, 0, 0, 0, i-> w, i-> h);
1162 		} else {
1163 			XSetForeground( DISP, gc, guts. monochromeMap[1]);
1164 			XFillRectangle( DISP, and, gc, 0, 0, i-> w + 1, i-> h + 1);
1165 		}
1166 		XFreeGC( DISP, gc);
1167 	}
1168 	if (( Handle) i != icon) Object_destroy(( Handle) i);
1169 
1170 	wmhints. flags = InputHint | IconPixmapHint | IconMaskHint;
1171 	wmhints. icon_pixmap = xor;
1172 	wmhints. icon_mask   = and;
1173 	wmhints. input       = false;
1174 	XSetWMHints( DISP, X_WINDOW, &wmhints);
1175 	XCHECKPOINT;
1176 
1177 	XX-> flags. has_icon = true;
1178 
1179 	return true;
1180 FAIL:
1181 
1182 	if (( Handle) i != icon) Object_destroy(( Handle) i);
1183 	return false;
1184 }
1185 
1186 Bool
apc_window_set_window_state(Handle self,int state)1187 apc_window_set_window_state( Handle self, int state)
1188 {
1189 	DEFXX;
1190 	Event e;
1191 	int sync = 0, did_net_zoom = 0;
1192 
1193 	switch ( state) {
1194 	case wsMinimized:
1195 		if ( XX-> flags. iconic) return false;
1196 		break;
1197 	case wsMaximized:
1198 		if ( XX-> flags. zoomed) return false;
1199 		break;
1200 	case wsNormal:
1201 		if ( !XX-> flags. iconic && !XX-> flags. zoomed) return false;
1202 		break;
1203 	default:
1204 		return false;
1205 	}
1206 
1207 	/* operate via NET_WM */
1208 	if ( state == wsMaximized && !XX-> flags. zoomed && net_supports_maximization()) {
1209 		Bool visible = XX-> flags. mapped;
1210 		Rect zoomRect;
1211 		NETWM_SET_MAXIMIZED( X_WINDOW, 1);
1212 		zoomRect. left   = XX-> origin.x;
1213 		zoomRect. bottom = XX-> origin.y;
1214 		zoomRect. right  = XX-> size.x;
1215 		zoomRect. top    = XX-> size.y;
1216 		if ( visible) {
1217 			prima_wm_sync( self, ConfigureNotify);
1218 			if ( !prima_wm_net_state_read_maximization( X_WINDOW, NET_WM_STATE)) {
1219 				/* wm denies maximization request, or we lost in the race ( see above ),
1220 					do maximization by casual heuristic */
1221 				goto FALL_THROUGH;
1222 			}
1223 		}
1224 		XX-> zoomRect = zoomRect; /* often reset in ConfigureNotify to already maximized window */
1225 		XX-> flags. zoomed = 1;
1226 		did_net_zoom = 1;
1227 		sync = 0;
1228 	FALL_THROUGH:;
1229 	}
1230 
1231 	if ( !XX-> flags. withdrawn) {
1232 		if ( state == wsMinimized) {
1233 			XIconifyWindow( DISP, X_WINDOW, SCREEN);
1234 			if ( XX-> flags. mapped) sync = UnmapNotify;
1235 		} else {
1236 			XMapWindow( DISP, X_WINDOW);
1237 			if ( !XX-> flags. mapped && !did_net_zoom) sync = MapNotify;
1238 		}
1239 	}
1240 	XX-> flags. iconic = ( state == wsMinimized) ? 1 : 0;
1241 
1242 	if ( state == wsMaximized && !XX-> flags. zoomed && !did_net_zoom) {
1243 		int dx = ( XX-> decorationSize. x > 0 ) ? XX-> decorationSize. x : 2;
1244 		int dy = ( XX-> decorationSize. y > 0 ) ? XX-> decorationSize. y : 20;
1245 		XX-> zoomRect. left   = XX-> origin.x;
1246 		XX-> zoomRect. bottom = XX-> origin.y;
1247 		XX-> zoomRect. right  = XX-> size.x;
1248 		XX-> zoomRect. top    = XX-> size.y;
1249 		apc_window_set_rect( self, dx * 2, dy * 2,
1250 				guts. displaySize.x - dx * 4, guts. displaySize. y - XX-> menuHeight - dy * 4);
1251 		if ( !XX-> flags. zoomed) sync = ConfigureNotify;
1252 		XX-> flags. zoomed = 1;
1253 	}
1254 
1255 	if ( XX-> flags. zoomed && state != wsMaximized) {
1256 		NETWM_SET_MAXIMIZED( X_WINDOW, 0);
1257 		apc_window_set_rect( self, XX-> zoomRect. left, XX-> zoomRect. bottom,
1258 			XX-> zoomRect. right, XX-> zoomRect. top);
1259 		if ( XX-> flags. zoomed) sync = ConfigureNotify;
1260 		XX-> flags. zoomed = 0;
1261 	}
1262 
1263 	bzero( &e, sizeof(e));
1264 	e. gen. source = self;
1265 	e. cmd = cmWindowState;
1266 	e. gen. i = state;
1267 	apc_message( self, &e, false);
1268 
1269 	if ( sync) prima_wm_sync( self, sync);
1270 
1271 	return true;
1272 }
1273 
1274 static Bool
window_start_modal(Handle self,Bool shared,Handle insert_before)1275 window_start_modal( Handle self, Bool shared, Handle insert_before)
1276 {
1277 	DEFXX;
1278 	Handle selectee;
1279 	if ( guts. grab_widget)
1280 		apc_widget_set_capture( guts. grab_widget, 0, 0);
1281 	if (( XX-> preexec_focus = apc_widget_get_focused()))
1282 		protect_object( XX-> preexec_focus);
1283 	CWindow( self)-> exec_enter_proc( self, shared, insert_before);
1284 	apc_widget_set_enabled( self, true);
1285 	apc_widget_set_visible( self, true);
1286 	apc_window_activate( self);
1287 	selectee = CWindow(self)->get_selectee( self);
1288 	if ( selectee && selectee != self) Widget_selected( selectee, true, true);
1289 	prima_simple_message( self, cmExecute, true);
1290 	guts. modal_count++;
1291 	return true;
1292 }
1293 
1294 Handle
prima_find_toplevel_window(Handle self)1295 prima_find_toplevel_window(Handle self)
1296 {
1297 	Handle toplevel = NULL_HANDLE;
1298 
1299 	if (!application) return NULL_HANDLE;
1300 
1301 	toplevel = CApplication(application)-> get_modal_window(application, mtExclusive, true);
1302 	if ( toplevel == NULL_HANDLE && self != NULL_HANDLE) {
1303 		if (
1304 			PWindow(self)-> owner &&
1305 			PWindow(self)-> owner != application
1306 		)
1307 			toplevel = PWindow(self)-> owner;
1308 	}
1309 
1310 	/* find main window */
1311 	if ( toplevel == NULL_HANDLE) {
1312 		int i;
1313 		PList l = & PWidget(application)-> widgets;
1314 		for ( i = 0; i < l-> count; i++) {
1315 			if ( PObject(l-> items[i])-> options. optMainWindow && self != l->items[i]) {
1316 				toplevel = l-> items[i];
1317 				break;
1318 			}
1319 		}
1320 	}
1321 
1322 	return toplevel;
1323 }
1324 
1325 Bool
apc_window_execute(Handle self,Handle insert_before)1326 apc_window_execute( Handle self, Handle insert_before)
1327 {
1328 	DEFXX;
1329 	Handle toplevel;
1330 
1331 	if (!application) return false;
1332 
1333 	toplevel = prima_find_toplevel_window(self);
1334 	if ( toplevel) XSetTransientForHint( DISP, X_WINDOW, PWidget(toplevel)-> handle);
1335 
1336 	XX-> flags.modal = true;
1337 	NETWM_SET_MODAL( X_WINDOW, XX-> flags.modal);
1338 	if ( !window_start_modal( self, false, insert_before))
1339 		return false;
1340 
1341 	protect_object( self);
1342 
1343 	XSync( DISP, false);
1344 	while ( prima_one_loop_round( WAIT_ALWAYS, true) && XX-> flags.modal)
1345 		;
1346 
1347 	if ( toplevel) XSetTransientForHint( DISP, X_WINDOW, None);
1348 	if ( X_WINDOW) NETWM_SET_MODAL( X_WINDOW, XX-> flags.modal);
1349 	unprotect_object( self);
1350 	return true;
1351 }
1352 
1353 Bool
apc_window_execute_shared(Handle self,Handle insert_before)1354 apc_window_execute_shared( Handle self, Handle insert_before)
1355 {
1356 	return window_start_modal( self, true, insert_before);
1357 }
1358 
1359 Bool
apc_window_end_modal(Handle self)1360 apc_window_end_modal( Handle self)
1361 {
1362 	PWindow win = PWindow(self);
1363 	Handle modal, oldfoc;
1364 	DEFXX;
1365 	XX-> flags.modal = false;
1366 	CWindow( self)-> exec_leave_proc( self);
1367 	apc_widget_set_visible( self, false);
1368 	if ( application) {
1369 		modal = CApplication(application)->popup_modal( application);
1370 		if ( !modal && win->owner)
1371 			CWidget( win->owner)-> set_selected( win->owner, true);
1372 		if (( oldfoc = XX-> preexec_focus)) {
1373 			if ( PWidget( oldfoc)-> stage == csNormal)
1374 				CWidget( oldfoc)-> set_focused( oldfoc, true);
1375 			unprotect_object( oldfoc);
1376 		}
1377 	}
1378 	if ( guts. modal_count > 0)
1379 		guts. modal_count--;
1380 	return true;
1381 }
1382 
1383 Bool
apc_window_get_on_top(Handle self)1384 apc_window_get_on_top( Handle self)
1385 {
1386 	Atom type;
1387 	long * prop;
1388 	int format;
1389 	unsigned long i, n, left;
1390 	Bool on_top = 0;
1391 
1392 	if ( guts. icccm_only) return false;
1393 
1394 	if ( XGetWindowProperty( DISP, X_WINDOW, NET_WM_STATE, 0, 32, false, XA_ATOM,
1395 			&type, &format, &n, &left, (unsigned char**)&prop) == Success) {
1396 	if ( prop) {
1397 			for ( i = 0; i < n; i++) {
1398 				if (
1399 					prop[i] == NET_WM_STATE_STAYS_ON_TOP ||
1400 					prop[i] == NET_WM_STATE_ABOVE
1401 				) {
1402 					on_top = 1;
1403 					break;
1404 				}
1405 			}
1406 			XFree(( unsigned char *) prop);
1407 		}
1408 	}
1409 
1410 	return on_top;
1411 }
1412 
1413 Bool
apc_window_set_effects(Handle self,PHash effects)1414 apc_window_set_effects( Handle self, PHash effects )
1415 {
1416 	return false;
1417 }
1418