wmaker: replaced macro 'store_modifier' by an inline function, in X Modifier initiali...
[wmaker-crm.git] / WINGs / wwindow.c
blob28844fb99fc3d5baf80cc16d12e1cb49c5b59d38
2 #include <X11/Xmd.h>
4 #include "WINGsP.h"
6 #include <X11/Xatom.h>
8 typedef struct W_Window {
9 W_Class widgetClass;
10 W_View *view;
12 struct W_Window *nextPtr; /* next in the window list */
14 struct W_Window *owner;
16 char *title;
18 WMPixmap *miniImage; /* miniwindow */
19 char *miniTitle;
21 char *wname;
23 WMSize resizeIncrement;
24 WMSize baseSize;
25 WMSize minSize;
26 WMSize maxSize;
27 WMPoint minAspect;
28 WMPoint maxAspect;
30 WMPoint upos;
31 WMPoint ppos;
33 WMAction *closeAction;
34 void *closeData;
36 int level;
38 struct {
39 unsigned style:4;
40 unsigned configured:1;
41 unsigned documentEdited:1;
43 unsigned setUPos:1;
44 unsigned setPPos:1;
45 unsigned setAspect:1;
46 } flags;
47 } _Window;
49 typedef struct {
50 CARD32 flags;
51 CARD32 window_style;
52 CARD32 window_level;
53 CARD32 reserved;
54 Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
55 Pixmap close_pixmap; /* pixmap for close button */
56 Pixmap miniaturize_mask; /* miniaturize pixmap mask */
57 Pixmap close_mask; /* close pixmap mask */
58 CARD32 extra_flags;
59 } GNUstepWMAttributes;
61 #define GSWindowStyleAttr (1<<0)
62 #define GSWindowLevelAttr (1<<1)
63 #define GSMiniaturizePixmapAttr (1<<3)
64 #define GSClosePixmapAttr (1<<4)
65 #define GSMiniaturizeMaskAttr (1<<5)
66 #define GSCloseMaskAttr (1<<6)
67 #define GSExtraFlagsAttr (1<<7)
69 /* extra flags */
70 #define GSDocumentEditedFlag (1<<0)
71 #define GSNoApplicationIconFlag (1<<5)
73 #define WMFHideOtherApplications 10
74 #define WMFHideApplication 12
76 static void willResizeWindow(W_ViewDelegate *, WMView *, unsigned *, unsigned *);
78 struct W_ViewDelegate _WindowViewDelegate = {
79 NULL,
80 NULL,
81 NULL,
82 NULL,
83 willResizeWindow
86 #define DEFAULT_WIDTH 400
87 #define DEFAULT_HEIGHT 180
88 #define DEFAULT_TITLE ""
90 static void destroyWindow(_Window * win);
92 static void handleEvents(XEvent * event, void *clientData);
94 static void realizeWindow(WMWindow * win);
96 static void realizeObserver(void *self, WMNotification * not)
98 /* Parameter not used, but tell the compiler that it is ok */
99 (void) not;
101 realizeWindow(self);
104 WMWindow *WMCreatePanelWithStyleForWindow(WMWindow * owner, const char *name, int style)
106 WMWindow *win;
108 win = WMCreateWindowWithStyle(owner->view->screen, name, style);
109 win->owner = owner;
111 return win;
114 WMWindow *WMCreatePanelForWindow(WMWindow * owner, const char *name)
116 return WMCreatePanelWithStyleForWindow(owner, name,
117 WMTitledWindowMask | WMClosableWindowMask | WMResizableWindowMask);
120 void WMChangePanelOwner(WMWindow * win, WMWindow * newOwner)
122 win->owner = newOwner;
124 if (win->view->flags.realized && newOwner) {
125 XSetTransientForHint(win->view->screen->display, win->view->window, newOwner->view->window);
129 WMWindow *WMCreateWindow(WMScreen * screen, const char *name)
131 return WMCreateWindowWithStyle(screen, name, WMTitledWindowMask
132 | WMClosableWindowMask
133 | WMMiniaturizableWindowMask | WMResizableWindowMask);
136 WMWindow *WMCreateWindowWithStyle(WMScreen * screen, const char *name, int style)
138 _Window *win;
140 win = wmalloc(sizeof(_Window));
141 win->widgetClass = WC_Window;
143 win->view = W_CreateTopView(screen);
144 if (!win->view) {
145 wfree(win);
146 return NULL;
148 win->view->self = win;
150 win->view->delegate = &_WindowViewDelegate;
152 win->wname = wstrdup(name);
154 /* add to the window list of the screen (application) */
155 win->nextPtr = screen->windowList;
156 screen->windowList = win;
158 WMCreateEventHandler(win->view, ExposureMask | StructureNotifyMask
159 | ClientMessageMask | FocusChangeMask, handleEvents, win);
161 W_ResizeView(win->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
163 WMAddNotificationObserver(realizeObserver, win, WMViewRealizedNotification, win->view);
165 win->flags.style = style;
167 win->level = WMNormalWindowLevel;
169 /* kluge. Find a better solution */
170 W_SetFocusOfTopLevel(win->view, win->view);
172 return win;
175 static void setWindowTitle(WMWindow * win, const char *title)
177 WMScreen *scr = win->view->screen;
178 XTextProperty property;
179 int result;
181 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
182 if (result == XNoMemory || result == XLocaleNotSupported) {
183 wwarning("window title conversion error... using STRING encoding");
184 XStoreName(scr->display, win->view->window, title);
185 } else {
186 XSetWMName(scr->display, win->view->window, &property);
187 if (property.value)
188 XFree(property.value);
191 XChangeProperty(scr->display, win->view->window,
192 scr->netwmName, scr->utf8String, 8,
193 PropModeReplace, (unsigned char *)title, strlen(title));
196 static void setMiniwindowTitle(WMWindow * win, const char *title)
198 WMScreen *scr = win->view->screen;
199 XTextProperty property;
200 int result;
202 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
203 if (result == XNoMemory || result == XLocaleNotSupported) {
204 wwarning("icon title conversion error..using STRING encoding");
205 XSetIconName(scr->display, win->view->window, title);
206 } else {
207 XSetWMIconName(scr->display, win->view->window, &property);
208 if (property.value)
209 XFree(property.value);
212 XChangeProperty(scr->display, win->view->window,
213 scr->netwmIconName, scr->utf8String, 8,
214 PropModeReplace, (unsigned char *)title, strlen(title));
217 static void setMiniwindow(WMWindow *win, RImage *image)
219 WMScreen *scr = win->view->screen;
220 unsigned long *data;
221 int x, y;
222 int o;
224 if (!image)
225 return;
227 data = wmalloc((image->width * image->height + 2) * sizeof(long));
229 o = 0;
230 data[o++] = image->width;
231 data[o++] = image->height;
233 for (y = 0; y < image->height; y++) {
234 for (x = 0; x < image->width; x++) {
235 unsigned long pixel;
236 int offs = (x + y * image->width);
238 if (image->format == RRGBFormat) {
239 pixel = ((unsigned long) image->data[offs * 3 ]) << 16;
240 pixel |= ((unsigned long) image->data[offs * 3 + 1]) << 8;
241 pixel |= ((unsigned long) image->data[offs * 3 + 2]);
242 } else {
243 pixel = ((unsigned long) image->data[offs * 4 ]) << 16;
244 pixel |= ((unsigned long) image->data[offs * 4 + 1]) << 8;
245 pixel |= ((unsigned long) image->data[offs * 4 + 2]);
246 pixel |= ((unsigned long) image->data[offs * 4 + 3]) << 24;
249 data[o++] = pixel;
253 XChangeProperty(scr->display, win->view->window, scr->netwmIcon,
254 XA_CARDINAL, 32, PropModeReplace,
255 (unsigned char *)data, (image->width * image->height + 2));
257 wfree(data);
260 void WMSetWindowTitle(WMWindow * win, const char *title)
262 wassertr(title != NULL);
264 if (win->title != NULL)
265 wfree(win->title);
267 win->title = wstrdup(title);
269 if (win->view->flags.realized) {
270 setWindowTitle(win, title);
274 void WMSetWindowCloseAction(WMWindow * win, WMAction * action, void *clientData)
276 Atom *atoms = NULL;
277 Atom *newAtoms;
278 int count;
279 WMScreen *scr = win->view->screen;
281 if (win->view->flags.realized) {
282 if (action && !win->closeAction) {
283 if (!XGetWMProtocols(scr->display, win->view->window, &atoms, &count)) {
284 count = 0;
286 newAtoms = wmalloc((count + 1) * sizeof(Atom));
287 if (count > 0)
288 memcpy(newAtoms, atoms, count * sizeof(Atom));
289 newAtoms[count++] = scr->deleteWindowAtom;
290 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
291 if (atoms)
292 XFree(atoms);
293 wfree(newAtoms);
294 } else if (!action && win->closeAction) {
295 int i, ncount;
297 if (XGetWMProtocols(scr->display, win->view->window, &atoms, &count) && count > 0) {
298 newAtoms = wmalloc((count - 1) * sizeof(Atom));
299 ncount = 0;
300 for (i = 0; i < count; i++) {
301 if (atoms[i] != scr->deleteWindowAtom) {
302 newAtoms[i] = atoms[i];
303 ncount++;
306 XSetWMProtocols(scr->display, win->view->window, newAtoms, ncount);
307 if (atoms)
308 XFree(atoms);
309 wfree(newAtoms);
313 win->closeAction = action;
314 win->closeData = clientData;
317 static void willResizeWindow(W_ViewDelegate * self, WMView * view, unsigned *width, unsigned *height)
319 WMWindow *win = (WMWindow *) view->self;
321 /* Parameter not used, but tell the compiler that it is ok */
322 (void) self;
324 if (win->minSize.width > 0 && win->minSize.height > 0) {
325 if (*width < win->minSize.width)
326 *width = win->minSize.width;
327 if (*height < win->minSize.height)
328 *height = win->minSize.height;
331 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
332 if (*width > win->maxSize.width)
333 *width = win->maxSize.width;
334 if (*height > win->maxSize.height)
335 *height = win->maxSize.height;
339 static void setSizeHints(WMWindow * win)
341 XSizeHints *hints;
343 hints = XAllocSizeHints();
344 if (!hints) {
345 wwarning("could not allocate memory for window size hints");
346 return;
349 hints->flags = 0;
351 if (win->flags.setPPos) {
352 hints->flags |= PPosition;
353 hints->x = win->ppos.x;
354 hints->y = win->ppos.y;
356 if (win->flags.setUPos) {
357 hints->flags |= USPosition;
358 hints->x = win->upos.x;
359 hints->y = win->upos.y;
361 if (win->minSize.width > 0 && win->minSize.height > 0) {
362 hints->flags |= PMinSize;
363 hints->min_width = win->minSize.width;
364 hints->min_height = win->minSize.height;
366 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
367 hints->flags |= PMaxSize;
368 hints->max_width = win->maxSize.width;
369 hints->max_height = win->maxSize.height;
371 if (win->baseSize.width > 0 && win->baseSize.height > 0) {
372 hints->flags |= PBaseSize;
373 hints->base_width = win->baseSize.width;
374 hints->base_height = win->baseSize.height;
376 if (win->resizeIncrement.width > 0 && win->resizeIncrement.height > 0) {
377 hints->flags |= PResizeInc;
378 hints->width_inc = win->resizeIncrement.width;
379 hints->height_inc = win->resizeIncrement.height;
381 if (win->flags.setAspect) {
382 hints->flags |= PAspect;
383 hints->min_aspect.x = win->minAspect.x;
384 hints->min_aspect.y = win->minAspect.y;
385 hints->max_aspect.x = win->maxAspect.x;
386 hints->max_aspect.y = win->maxAspect.y;
389 if (hints->flags) {
390 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
392 XFree(hints);
395 static void writeGNUstepWMAttr(WMScreen * scr, Window window, GNUstepWMAttributes * attr)
397 unsigned long data[9];
399 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
400 data[0] = attr->flags;
401 data[1] = attr->window_style;
402 data[2] = attr->window_level;
403 data[3] = 0; /* reserved */
404 /* The X protocol says XIDs are 32bit */
405 data[4] = attr->miniaturize_pixmap;
406 data[5] = attr->close_pixmap;
407 data[6] = attr->miniaturize_mask;
408 data[7] = attr->close_mask;
409 data[8] = attr->extra_flags;
410 XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
411 32, PropModeReplace, (unsigned char *)data, 9);
414 static void setWindowMakerHints(WMWindow * win)
416 GNUstepWMAttributes attribs;
417 WMScreen *scr = WMWidgetScreen(win);
419 memset(&attribs, 0, sizeof(GNUstepWMAttributes));
420 attribs.flags = GSWindowStyleAttr | GSWindowLevelAttr | GSExtraFlagsAttr;
421 attribs.window_style = win->flags.style;
422 attribs.window_level = win->level;
423 if (win->flags.documentEdited)
424 attribs.extra_flags = GSDocumentEditedFlag;
425 else
426 attribs.extra_flags = 0;
428 writeGNUstepWMAttr(scr, win->view->window, &attribs);
431 static void realizeWindow(WMWindow * win)
433 XWMHints *hints;
434 XClassHint *classHint;
435 WMScreen *scr = win->view->screen;
436 Atom atoms[4];
437 int count;
439 classHint = XAllocClassHint();
440 classHint->res_name = win->wname;
441 classHint->res_class = WMGetApplicationName();
442 XSetClassHint(scr->display, win->view->window, classHint);
443 XFree(classHint);
445 hints = XAllocWMHints();
446 hints->flags = 0;
447 if (!scr->aflags.simpleApplication) {
448 hints->flags |= WindowGroupHint;
449 hints->window_group = scr->groupLeader;
451 if (win->miniImage) {
452 hints->flags |= IconPixmapHint;
453 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
454 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
455 if (hints->icon_mask != None) {
456 hints->flags |= IconMaskHint;
459 if (hints->flags != 0)
460 XSetWMHints(scr->display, win->view->window, hints);
461 XFree(hints);
463 count = 0;
464 if (win->closeAction) {
465 atoms[count++] = scr->deleteWindowAtom;
468 if (count > 0)
469 XSetWMProtocols(scr->display, win->view->window, atoms, count);
471 if (win->title || win->miniTitle)
472 XmbSetWMProperties(scr->display, win->view->window, win->title,
473 win->miniTitle, NULL, 0, NULL, NULL, NULL);
475 setWindowMakerHints(win);
477 setSizeHints(win);
479 if (win->owner) {
480 XSetTransientForHint(scr->display, win->view->window, win->owner->view->window);
483 if (win->title)
484 setWindowTitle(win, win->title);
487 void WMSetWindowAspectRatio(WMWindow * win, int minX, int minY, int maxX, int maxY)
489 win->flags.setAspect = 1;
490 win->minAspect.x = minX;
491 win->minAspect.y = minY;
492 win->maxAspect.x = maxX;
493 win->maxAspect.y = maxY;
494 if (win->view->flags.realized)
495 setSizeHints(win);
498 void WMSetWindowInitialPosition(WMWindow * win, int x, int y)
500 win->flags.setPPos = 1;
501 win->ppos.x = x;
502 win->ppos.y = y;
503 if (win->view->flags.realized)
504 setSizeHints(win);
505 WMMoveWidget(win, x, y);
508 void WMSetWindowUserPosition(WMWindow * win, int x, int y)
510 win->flags.setUPos = 1;
511 win->upos.x = x;
512 win->upos.y = y;
513 if (win->view->flags.realized)
514 setSizeHints(win);
515 WMMoveWidget(win, x, y);
518 void WMSetWindowMinSize(WMWindow * win, unsigned width, unsigned height)
520 win->minSize.width = width;
521 win->minSize.height = height;
522 if (win->view->flags.realized)
523 setSizeHints(win);
526 void WMSetWindowMaxSize(WMWindow * win, unsigned width, unsigned height)
528 win->maxSize.width = width;
529 win->maxSize.height = height;
530 if (win->view->flags.realized)
531 setSizeHints(win);
534 void WMSetWindowBaseSize(WMWindow * win, unsigned width, unsigned height)
536 /* TODO: validate sizes */
537 win->baseSize.width = width;
538 win->baseSize.height = height;
539 if (win->view->flags.realized)
540 setSizeHints(win);
543 void WMSetWindowResizeIncrements(WMWindow * win, unsigned wIncr, unsigned hIncr)
545 win->resizeIncrement.width = wIncr;
546 win->resizeIncrement.height = hIncr;
547 if (win->view->flags.realized)
548 setSizeHints(win);
551 void WMSetWindowLevel(WMWindow * win, int level)
553 win->level = level;
554 if (win->view->flags.realized)
555 setWindowMakerHints(win);
558 void WMSetWindowDocumentEdited(WMWindow * win, Bool flag)
560 flag = ((flag == 0) ? 0 : 1);
561 if (win->flags.documentEdited != flag) {
562 win->flags.documentEdited = flag;
563 if (win->view->flags.realized)
564 setWindowMakerHints(win);
568 void WMSetWindowMiniwindowImage(WMWindow * win, RImage * image)
570 if (win->view->flags.realized)
571 setMiniwindow(win, image);
574 void WMSetWindowMiniwindowPixmap(WMWindow * win, WMPixmap * pixmap)
576 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
577 if (win->miniImage)
578 WMReleasePixmap(win->miniImage);
580 if (pixmap)
581 win->miniImage = WMRetainPixmap(pixmap);
582 else
583 win->miniImage = NULL;
585 if (win->view->flags.realized) {
586 XWMHints *hints;
588 hints = XGetWMHints(win->view->screen->display, win->view->window);
589 if (!hints) {
590 hints = XAllocWMHints();
591 if (!hints) {
592 wwarning("could not allocate memory for WM hints");
593 return;
595 hints->flags = 0;
597 if (pixmap) {
598 hints->flags |= IconPixmapHint;
599 hints->icon_pixmap = WMGetPixmapXID(pixmap);
600 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
601 if (hints->icon_mask != None) {
602 hints->flags |= IconMaskHint;
605 XSetWMHints(win->view->screen->display, win->view->window, hints);
606 XFree(hints);
611 void WMSetWindowMiniwindowTitle(WMWindow * win, const char *title)
613 if (win && ((win->miniTitle && !title) || (!win->miniTitle && title)
614 || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0))) {
615 if (win->miniTitle)
616 wfree(win->miniTitle);
618 if (title)
619 win->miniTitle = wstrdup(title);
620 else
621 win->miniTitle = NULL;
623 if (win->view->flags.realized) {
624 setMiniwindowTitle(win, title);
629 void WMCloseWindow(WMWindow * win)
631 WMUnmapWidget(win);
632 /* withdraw the window */
633 if (win->view->flags.realized)
634 XWithdrawWindow(win->view->screen->display, win->view->window, win->view->screen->screen);
637 static void handleEvents(XEvent * event, void *clientData)
639 _Window *win = (_Window *) clientData;
640 W_View *view = win->view;
642 switch (event->type) {
643 case ClientMessage:
644 if (event->xclient.message_type == win->view->screen->protocolsAtom
645 && event->xclient.format == 32
646 && event->xclient.data.l[0] == win->view->screen->deleteWindowAtom) {
648 if (win->closeAction) {
649 (*win->closeAction) (win, win->closeData);
652 break;
654 * was causing windows to ignore commands like closeWindow
655 * after the windows is iconized/restored or a workspace change
656 * if this is really needed, put the MapNotify portion too and
657 * fix the restack bug in wmaker
658 case UnmapNotify:
659 WMUnmapWidget(win);
660 break;
662 case MapNotify:
663 WMMapWidget(win);
664 break;
667 case DestroyNotify:
668 destroyWindow(win);
669 break;
671 case ConfigureNotify:
672 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
674 view->size.width = event->xconfigure.width;
675 view->size.height = event->xconfigure.height;
677 if (view->flags.notifySizeChanged) {
678 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
681 if (event->xconfigure.x != view->pos.x || event->xconfigure.y != view->pos.y) {
683 if (event->xconfigure.send_event) {
684 view->pos.x = event->xconfigure.x;
685 view->pos.y = event->xconfigure.y;
686 } else {
687 Window foo;
689 XTranslateCoordinates(view->screen->display,
690 view->window, view->screen->rootWin,
691 event->xconfigure.x, event->xconfigure.y,
692 &view->pos.x, &view->pos.y, &foo);
695 break;
699 static void destroyWindow(_Window * win)
701 WMScreen *scr = win->view->screen;
703 WMRemoveNotificationObserver(win);
705 if (scr->windowList == win) {
706 scr->windowList = scr->windowList->nextPtr;
707 } else {
708 WMWindow *ptr;
709 ptr = scr->windowList;
711 if (ptr) {
712 while (ptr->nextPtr) {
713 if (ptr->nextPtr == win) {
714 ptr->nextPtr = ptr->nextPtr->nextPtr;
715 break;
717 ptr = ptr->nextPtr;
722 if (win->title) {
723 wfree(win->title);
726 if (win->miniTitle) {
727 wfree(win->miniTitle);
730 if (win->miniImage) {
731 WMReleasePixmap(win->miniImage);
734 if (win->wname)
735 wfree(win->wname);
737 wfree(win);