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