Include screen.h in dialog.h for definition of WScreen
[wmaker-crm.git] / WINGs / wwindow.c
blob4a27f4377d9950d3fe3cfef361d18133894722b0
2 #include <X11/Xmd.h>
4 #include "wconfig.h"
6 #include "WINGsP.h"
8 #include "GNUstep.h"
10 #include <X11/Xatom.h>
12 typedef struct W_Window {
13 W_Class widgetClass;
14 W_View *view;
16 struct W_Window *nextPtr; /* next in the window list */
18 struct W_Window *owner;
20 char *title;
22 WMPixmap *miniImage; /* miniwindow */
23 char *miniTitle;
25 char *wname;
27 WMSize resizeIncrement;
28 WMSize baseSize;
29 WMSize minSize;
30 WMSize maxSize;
31 WMPoint minAspect;
32 WMPoint maxAspect;
34 WMPoint upos;
35 WMPoint ppos;
37 WMAction *closeAction;
38 void *closeData;
40 int level;
42 struct {
43 unsigned style:4;
44 unsigned configured:1;
45 unsigned documentEdited:1;
47 unsigned setUPos:1;
48 unsigned setPPos:1;
49 unsigned setAspect:1;
50 } flags;
51 } _Window;
54 static void willResizeWindow(W_ViewDelegate *, WMView *, unsigned *, unsigned *);
56 struct W_ViewDelegate _WindowViewDelegate = {
57 NULL,
58 NULL,
59 NULL,
60 NULL,
61 willResizeWindow
64 #define DEFAULT_WIDTH 400
65 #define DEFAULT_HEIGHT 180
67 static void destroyWindow(_Window * win);
69 static void handleEvents(XEvent * event, void *clientData);
71 static void realizeWindow(WMWindow * win);
73 static void realizeObserver(void *self, WMNotification * not)
75 /* Parameter not used, but tell the compiler that it is ok */
76 (void) not;
78 realizeWindow(self);
81 WMWindow *WMCreatePanelWithStyleForWindow(WMWindow * owner, const char *name, int style)
83 WMWindow *win;
85 win = WMCreateWindowWithStyle(owner->view->screen, name, style);
86 win->owner = owner;
88 return win;
91 WMWindow *WMCreatePanelForWindow(WMWindow * owner, const char *name)
93 return WMCreatePanelWithStyleForWindow(owner, name,
94 WMTitledWindowMask | WMClosableWindowMask | WMResizableWindowMask);
97 void WMChangePanelOwner(WMWindow * win, WMWindow * newOwner)
99 win->owner = newOwner;
101 if (win->view->flags.realized && newOwner) {
102 XSetTransientForHint(win->view->screen->display, win->view->window, newOwner->view->window);
106 WMWindow *WMCreateWindow(WMScreen * screen, const char *name)
108 return WMCreateWindowWithStyle(screen, name, WMTitledWindowMask
109 | WMClosableWindowMask
110 | WMMiniaturizableWindowMask | WMResizableWindowMask);
113 WMWindow *WMCreateWindowWithStyle(WMScreen * screen, const char *name, int style)
115 _Window *win;
117 win = wmalloc(sizeof(_Window));
118 win->widgetClass = WC_Window;
120 win->view = W_CreateTopView(screen);
121 if (!win->view) {
122 wfree(win);
123 return NULL;
125 win->view->self = win;
127 win->view->delegate = &_WindowViewDelegate;
129 win->wname = wstrdup(name);
131 /* add to the window list of the screen (application) */
132 win->nextPtr = screen->windowList;
133 screen->windowList = win;
135 WMCreateEventHandler(win->view, ExposureMask | StructureNotifyMask
136 | ClientMessageMask | FocusChangeMask, handleEvents, win);
138 W_ResizeView(win->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
140 WMAddNotificationObserver(realizeObserver, win, WMViewRealizedNotification, win->view);
142 win->flags.style = style;
144 win->level = WMNormalWindowLevel;
146 /* kluge. Find a better solution */
147 W_SetFocusOfTopLevel(win->view, win->view);
149 return win;
152 static void setWindowTitle(WMWindow * win, const char *title)
154 WMScreen *scr = win->view->screen;
155 XTextProperty property;
156 int result;
158 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
159 if (result == XNoMemory || result == XLocaleNotSupported) {
160 wwarning(_("window title conversion error... using STRING encoding"));
161 XStoreName(scr->display, win->view->window, title);
162 } else {
163 XSetWMName(scr->display, win->view->window, &property);
164 if (property.value)
165 XFree(property.value);
168 XChangeProperty(scr->display, win->view->window,
169 scr->netwmName, scr->utf8String, 8,
170 PropModeReplace, (unsigned char *)title, strlen(title));
173 static void setMiniwindowTitle(WMWindow * win, const char *title)
175 WMScreen *scr = win->view->screen;
176 XTextProperty property;
177 int result;
179 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
180 if (result == XNoMemory || result == XLocaleNotSupported) {
181 wwarning(_("icon title conversion error... using STRING encoding"));
182 XSetIconName(scr->display, win->view->window, title);
183 } else {
184 XSetWMIconName(scr->display, win->view->window, &property);
185 if (property.value)
186 XFree(property.value);
189 XChangeProperty(scr->display, win->view->window,
190 scr->netwmIconName, scr->utf8String, 8,
191 PropModeReplace, (unsigned char *)title, strlen(title));
194 static void setMiniwindow(WMWindow *win, RImage *image)
196 WMScreen *scr = win->view->screen;
197 unsigned long *data;
198 int x, y;
199 int o;
201 if (!image)
202 return;
204 data = wmalloc((image->width * image->height + 2) * sizeof(long));
206 o = 0;
207 data[o++] = image->width;
208 data[o++] = image->height;
210 for (y = 0; y < image->height; y++) {
211 for (x = 0; x < image->width; x++) {
212 unsigned long pixel;
213 int offs = (x + y * image->width);
215 if (image->format == RRGBFormat) {
216 pixel = ((unsigned long) image->data[offs * 3 ]) << 16;
217 pixel |= ((unsigned long) image->data[offs * 3 + 1]) << 8;
218 pixel |= ((unsigned long) image->data[offs * 3 + 2]);
219 } else {
220 pixel = ((unsigned long) image->data[offs * 4 ]) << 16;
221 pixel |= ((unsigned long) image->data[offs * 4 + 1]) << 8;
222 pixel |= ((unsigned long) image->data[offs * 4 + 2]);
223 pixel |= ((unsigned long) image->data[offs * 4 + 3]) << 24;
226 data[o++] = pixel;
230 XChangeProperty(scr->display, win->view->window, scr->netwmIcon,
231 XA_CARDINAL, 32, PropModeReplace,
232 (unsigned char *)data, (image->width * image->height + 2));
234 wfree(data);
237 void WMSetWindowTitle(WMWindow * win, const char *title)
239 wassertr(title != NULL);
241 if (win->title != NULL)
242 wfree(win->title);
244 win->title = wstrdup(title);
246 if (win->view->flags.realized) {
247 setWindowTitle(win, title);
251 void WMSetWindowCloseAction(WMWindow * win, WMAction * action, void *clientData)
253 Atom *atoms = NULL;
254 Atom *newAtoms;
255 int count;
256 WMScreen *scr = win->view->screen;
258 if (win->view->flags.realized) {
259 if (action && !win->closeAction) {
260 if (!XGetWMProtocols(scr->display, win->view->window, &atoms, &count)) {
261 count = 0;
263 newAtoms = wmalloc((count + 1) * sizeof(Atom));
264 if (count > 0)
265 memcpy(newAtoms, atoms, count * sizeof(Atom));
266 newAtoms[count++] = scr->deleteWindowAtom;
267 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
268 if (atoms)
269 XFree(atoms);
270 wfree(newAtoms);
271 } else if (!action && win->closeAction) {
272 int i, ncount;
274 if (XGetWMProtocols(scr->display, win->view->window, &atoms, &count) && count > 0) {
275 newAtoms = wmalloc((count - 1) * sizeof(Atom));
276 ncount = 0;
277 for (i = 0; i < count; i++) {
278 if (atoms[i] != scr->deleteWindowAtom) {
279 newAtoms[i] = atoms[i];
280 ncount++;
283 XSetWMProtocols(scr->display, win->view->window, newAtoms, ncount);
284 if (atoms)
285 XFree(atoms);
286 wfree(newAtoms);
290 win->closeAction = action;
291 win->closeData = clientData;
294 static void willResizeWindow(W_ViewDelegate * self, WMView * view, unsigned *width, unsigned *height)
296 WMWindow *win = (WMWindow *) view->self;
298 /* Parameter not used, but tell the compiler that it is ok */
299 (void) self;
301 if (win->minSize.width > 0 && win->minSize.height > 0) {
302 if (*width < win->minSize.width)
303 *width = win->minSize.width;
304 if (*height < win->minSize.height)
305 *height = win->minSize.height;
308 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
309 if (*width > win->maxSize.width)
310 *width = win->maxSize.width;
311 if (*height > win->maxSize.height)
312 *height = win->maxSize.height;
316 static void setSizeHints(WMWindow * win)
318 XSizeHints *hints;
320 hints = XAllocSizeHints();
321 if (!hints) {
322 wwarning("could not allocate memory for window size hints");
323 return;
326 hints->flags = 0;
328 if (win->flags.setPPos) {
329 hints->flags |= PPosition;
330 hints->x = win->ppos.x;
331 hints->y = win->ppos.y;
333 if (win->flags.setUPos) {
334 hints->flags |= USPosition;
335 hints->x = win->upos.x;
336 hints->y = win->upos.y;
338 if (win->minSize.width > 0 && win->minSize.height > 0) {
339 hints->flags |= PMinSize;
340 hints->min_width = win->minSize.width;
341 hints->min_height = win->minSize.height;
343 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
344 hints->flags |= PMaxSize;
345 hints->max_width = win->maxSize.width;
346 hints->max_height = win->maxSize.height;
348 if (win->baseSize.width > 0 && win->baseSize.height > 0) {
349 hints->flags |= PBaseSize;
350 hints->base_width = win->baseSize.width;
351 hints->base_height = win->baseSize.height;
353 if (win->resizeIncrement.width > 0 && win->resizeIncrement.height > 0) {
354 hints->flags |= PResizeInc;
355 hints->width_inc = win->resizeIncrement.width;
356 hints->height_inc = win->resizeIncrement.height;
358 if (win->flags.setAspect) {
359 hints->flags |= PAspect;
360 hints->min_aspect.x = win->minAspect.x;
361 hints->min_aspect.y = win->minAspect.y;
362 hints->max_aspect.x = win->maxAspect.x;
363 hints->max_aspect.y = win->maxAspect.y;
366 if (hints->flags) {
367 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
369 XFree(hints);
372 static void writeGNUstepWMAttr(WMScreen * scr, Window window, GNUstepWMAttributes * attr)
374 unsigned long data[9];
376 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
377 data[0] = attr->flags;
378 data[1] = attr->window_style;
379 data[2] = attr->window_level;
380 data[3] = 0; /* reserved */
381 /* The X protocol says XIDs are 32bit */
382 data[4] = attr->miniaturize_pixmap;
383 data[5] = attr->close_pixmap;
384 data[6] = attr->miniaturize_mask;
385 data[7] = attr->close_mask;
386 data[8] = attr->extra_flags;
387 XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
388 32, PropModeReplace, (unsigned char *)data, 9);
391 static void setWindowMakerHints(WMWindow * win)
393 GNUstepWMAttributes attribs;
394 WMScreen *scr = WMWidgetScreen(win);
396 memset(&attribs, 0, sizeof(GNUstepWMAttributes));
397 attribs.flags = GSWindowStyleAttr | GSWindowLevelAttr | GSExtraFlagsAttr;
398 attribs.window_style = win->flags.style;
399 attribs.window_level = win->level;
400 if (win->flags.documentEdited)
401 attribs.extra_flags = GSDocumentEditedFlag;
402 else
403 attribs.extra_flags = 0;
405 writeGNUstepWMAttr(scr, win->view->window, &attribs);
408 static void realizeWindow(WMWindow * win)
410 XWMHints *hints;
411 XClassHint *classHint;
412 WMScreen *scr = win->view->screen;
413 Atom atoms[4];
414 int count;
416 classHint = XAllocClassHint();
417 classHint->res_name = win->wname;
418 classHint->res_class = WMGetApplicationName();
419 XSetClassHint(scr->display, win->view->window, classHint);
420 XFree(classHint);
422 hints = XAllocWMHints();
423 hints->flags = 0;
424 if (!scr->aflags.simpleApplication) {
425 hints->flags |= WindowGroupHint;
426 hints->window_group = scr->groupLeader;
428 if (win->miniImage) {
429 hints->flags |= IconPixmapHint;
430 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
431 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
432 if (hints->icon_mask != None) {
433 hints->flags |= IconMaskHint;
436 if (hints->flags != 0)
437 XSetWMHints(scr->display, win->view->window, hints);
438 XFree(hints);
440 count = 0;
441 if (win->closeAction) {
442 atoms[count++] = scr->deleteWindowAtom;
445 if (count > 0)
446 XSetWMProtocols(scr->display, win->view->window, atoms, count);
448 if (win->title || win->miniTitle)
449 XmbSetWMProperties(scr->display, win->view->window, win->title,
450 win->miniTitle, NULL, 0, NULL, NULL, NULL);
452 setWindowMakerHints(win);
454 setSizeHints(win);
456 if (win->owner) {
457 XSetTransientForHint(scr->display, win->view->window, win->owner->view->window);
460 if (win->title)
461 setWindowTitle(win, win->title);
464 void WMSetWindowAspectRatio(WMWindow * win, int minX, int minY, int maxX, int maxY)
466 win->flags.setAspect = 1;
467 win->minAspect.x = minX;
468 win->minAspect.y = minY;
469 win->maxAspect.x = maxX;
470 win->maxAspect.y = maxY;
471 if (win->view->flags.realized)
472 setSizeHints(win);
475 void WMSetWindowInitialPosition(WMWindow * win, int x, int y)
477 win->flags.setPPos = 1;
478 win->ppos.x = x;
479 win->ppos.y = y;
480 if (win->view->flags.realized)
481 setSizeHints(win);
482 WMMoveWidget(win, x, y);
485 void WMSetWindowUserPosition(WMWindow * win, int x, int y)
487 win->flags.setUPos = 1;
488 win->upos.x = x;
489 win->upos.y = y;
490 if (win->view->flags.realized)
491 setSizeHints(win);
492 WMMoveWidget(win, x, y);
495 void WMSetWindowMinSize(WMWindow * win, unsigned width, unsigned height)
497 win->minSize.width = width;
498 win->minSize.height = height;
499 if (win->view->flags.realized)
500 setSizeHints(win);
503 void WMSetWindowMaxSize(WMWindow * win, unsigned width, unsigned height)
505 win->maxSize.width = width;
506 win->maxSize.height = height;
507 if (win->view->flags.realized)
508 setSizeHints(win);
511 void WMSetWindowBaseSize(WMWindow * win, unsigned width, unsigned height)
513 /* TODO: validate sizes */
514 win->baseSize.width = width;
515 win->baseSize.height = height;
516 if (win->view->flags.realized)
517 setSizeHints(win);
520 void WMSetWindowResizeIncrements(WMWindow * win, unsigned wIncr, unsigned hIncr)
522 win->resizeIncrement.width = wIncr;
523 win->resizeIncrement.height = hIncr;
524 if (win->view->flags.realized)
525 setSizeHints(win);
528 void WMSetWindowLevel(WMWindow * win, int level)
530 win->level = level;
531 if (win->view->flags.realized)
532 setWindowMakerHints(win);
535 void WMSetWindowDocumentEdited(WMWindow * win, Bool flag)
537 flag = ((flag == 0) ? 0 : 1);
538 if (win->flags.documentEdited != flag) {
539 win->flags.documentEdited = flag;
540 if (win->view->flags.realized)
541 setWindowMakerHints(win);
545 void WMSetWindowMiniwindowImage(WMWindow * win, RImage * image)
547 if (win->view->flags.realized)
548 setMiniwindow(win, image);
551 void WMSetWindowMiniwindowPixmap(WMWindow * win, WMPixmap * pixmap)
553 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
554 if (win->miniImage)
555 WMReleasePixmap(win->miniImage);
557 if (pixmap)
558 win->miniImage = WMRetainPixmap(pixmap);
559 else
560 win->miniImage = NULL;
562 if (win->view->flags.realized) {
563 XWMHints *hints;
565 hints = XGetWMHints(win->view->screen->display, win->view->window);
566 if (!hints) {
567 hints = XAllocWMHints();
568 if (!hints) {
569 wwarning("could not allocate memory for WM hints");
570 return;
572 hints->flags = 0;
574 if (pixmap) {
575 hints->flags |= IconPixmapHint;
576 hints->icon_pixmap = WMGetPixmapXID(pixmap);
577 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
578 if (hints->icon_mask != None) {
579 hints->flags |= IconMaskHint;
582 XSetWMHints(win->view->screen->display, win->view->window, hints);
583 XFree(hints);
588 void WMSetWindowMiniwindowTitle(WMWindow * win, const char *title)
590 if (win && ((win->miniTitle && !title) || (!win->miniTitle && title)
591 || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0))) {
592 if (win->miniTitle)
593 wfree(win->miniTitle);
595 if (title)
596 win->miniTitle = wstrdup(title);
597 else
598 win->miniTitle = NULL;
600 if (win->view->flags.realized) {
601 setMiniwindowTitle(win, title);
606 void WMCloseWindow(WMWindow * win)
608 WMUnmapWidget(win);
609 /* withdraw the window */
610 if (win->view->flags.realized)
611 XWithdrawWindow(win->view->screen->display, win->view->window, win->view->screen->screen);
614 static void handleEvents(XEvent * event, void *clientData)
616 _Window *win = (_Window *) clientData;
617 W_View *view = win->view;
619 switch (event->type) {
620 case ClientMessage:
621 if (event->xclient.message_type == win->view->screen->protocolsAtom
622 && event->xclient.format == 32
623 && event->xclient.data.l[0] == win->view->screen->deleteWindowAtom) {
625 if (win->closeAction) {
626 (*win->closeAction) (win, win->closeData);
629 break;
631 * was causing windows to ignore commands like closeWindow
632 * after the windows is iconized/restored or a workspace change
633 * if this is really needed, put the MapNotify portion too and
634 * fix the restack bug in wmaker
635 case UnmapNotify:
636 WMUnmapWidget(win);
637 break;
639 case MapNotify:
640 WMMapWidget(win);
641 break;
644 case DestroyNotify:
645 destroyWindow(win);
646 break;
648 case ConfigureNotify:
649 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
651 view->size.width = event->xconfigure.width;
652 view->size.height = event->xconfigure.height;
654 if (view->flags.notifySizeChanged) {
655 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
658 if (event->xconfigure.x != view->pos.x || event->xconfigure.y != view->pos.y) {
660 if (event->xconfigure.send_event) {
661 view->pos.x = event->xconfigure.x;
662 view->pos.y = event->xconfigure.y;
663 } else {
664 Window foo;
666 XTranslateCoordinates(view->screen->display,
667 view->window, view->screen->rootWin,
668 event->xconfigure.x, event->xconfigure.y,
669 &view->pos.x, &view->pos.y, &foo);
672 break;
676 static void destroyWindow(_Window * win)
678 WMScreen *scr = win->view->screen;
680 WMRemoveNotificationObserver(win);
682 if (scr->windowList == win) {
683 scr->windowList = scr->windowList->nextPtr;
684 } else {
685 WMWindow *ptr;
686 ptr = scr->windowList;
688 if (ptr) {
689 while (ptr->nextPtr) {
690 if (ptr->nextPtr == win) {
691 ptr->nextPtr = ptr->nextPtr->nextPtr;
692 break;
694 ptr = ptr->nextPtr;
699 if (win->title) {
700 wfree(win->title);
703 if (win->miniTitle) {
704 wfree(win->miniTitle);
707 if (win->miniImage) {
708 WMReleasePixmap(win->miniImage);
711 if (win->wname)
712 wfree(win->wname);
714 wfree(win);