Updating to version 0.20.2
[wmaker-crm.git] / src / framewin.c
blobad5bc1fae4f81de3a1ec09143c6a7bc4e950062f
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include <wraster.h>
32 #include "WindowMaker.h"
33 #include "GNUstep.h"
34 #include "texture.h"
35 #include "screen.h"
36 #include "wcore.h"
37 #include "framewin.h"
38 #include "stacking.h"
39 #include "funcs.h"
41 #define DBLCLICK_TIME wPreferences.dblclick_time
43 extern WPreferences wPreferences;
45 static void handleExpose(WObjDescriptor *desc, XEvent *event);
46 static void handleButtonExpose(WObjDescriptor *desc, XEvent *event);
48 static void buttonMouseDown(WObjDescriptor *desc, XEvent *event);
49 static void titlebarMouseDown(WObjDescriptor *desc, XEvent *event);
50 static void resizebarMouseDown(WObjDescriptor *desc, XEvent *event);
52 static void checkTitleSize(WFrameWindow *fwin);
55 static void paintButton(WCoreWindow *button, WTexture *texture,
56 unsigned long color, WPixmap *image, int pushed);
58 static void updateTitlebar(WFrameWindow *fwin);
61 WFrameWindow*
62 wFrameWindowCreate(WScreen *scr, int wlevel, int x, int y,
63 int width, int height, int flags,
64 WTexture **title_texture, WTexture **resize_texture,
65 unsigned long *color, GC *gc, WFont **font)
67 WFrameWindow *fwin;
69 fwin = wmalloc(sizeof(WFrameWindow));
70 memset(fwin, 0, sizeof(WFrameWindow));
72 fwin->screen_ptr = scr;
73 fwin->window_level = wlevel;
75 fwin->flags.single_texture = (flags & WFF_SINGLE_STATE) ? 1 : 0;
77 fwin->title_texture = title_texture;
78 fwin->resizebar_texture = resize_texture;
79 fwin->title_pixel = color;
80 fwin->title_gc = gc;
81 fwin->font = font;
83 fwin->core = wCoreCreateTopLevel(scr, x, y, width, height,
84 FRAME_BORDER_WIDTH);
85 if (wPreferences.use_saveunders) {
86 unsigned long vmask;
87 XSetWindowAttributes attribs;
89 vmask = CWSaveUnder;
90 attribs.save_under = True;
91 XChangeWindowAttributes(dpy, fwin->core->window, vmask, &attribs);
94 /* setup stacking information */
95 fwin->core->stacking = wmalloc(sizeof(WStacking));
96 fwin->core->stacking->above = NULL;
97 fwin->core->stacking->under = NULL;
98 fwin->core->stacking->child_of = NULL;
99 fwin->core->stacking->window_level = wlevel;
101 AddToStackList(fwin->core);
103 wFrameWindowUpdateBorders(fwin, flags);
105 return fwin;
110 void
111 wFrameWindowUpdateBorders(WFrameWindow *fwin, int flags)
113 int theight;
114 int bsize;
115 int width, height;
116 int i;
117 WScreen *scr = fwin->screen_ptr;
119 width = fwin->core->width;
120 height = fwin->core->height - fwin->top_width - fwin->bottom_width;
122 if (flags & WFF_TITLEBAR)
123 theight = (*fwin->font)->height + TITLEBAR_EXTRA_HEIGHT;
124 else
125 theight = 0;
127 if (wPreferences.new_style) {
128 bsize = theight;
129 } else {
130 bsize = theight - 7;
133 if (fwin->titlebar) {
134 /* if we had a titlebar and is requesting for one,
135 * check if the size has changed and resize it */
136 if (flags & WFF_TITLEBAR) {
137 fwin->top_width = theight;
139 fwin->flags.need_texture_remake = 1;
141 if (wPreferences.new_style) {
142 if (fwin->left_button) {
143 wCoreConfigure(fwin->left_button, 0, 0, bsize, bsize);
146 if (fwin->right_button) {
147 wCoreConfigure(fwin->right_button, width-bsize+1,
148 0, bsize, bsize);
150 } else { /* !new_style */
151 if (fwin->left_button) {
152 wCoreConfigure(fwin->left_button, 3, (theight-bsize)/2,
153 bsize, bsize);
156 if (fwin->right_button) {
157 wCoreConfigure(fwin->right_button, width-bsize-3,
158 (theight-bsize)/2, bsize, bsize);
161 updateTitlebar(fwin);
162 } else {
163 /* we had a titlebar, but now we don't need it anymore */
164 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
165 FREE_PIXMAP(fwin->title_back[i]);
166 if (wPreferences.new_style) {
167 FREE_PIXMAP(fwin->lbutton_back[i]);
168 FREE_PIXMAP(fwin->rbutton_back[i]);
171 if (fwin->left_button)
172 wCoreDestroy(fwin->left_button);
173 fwin->left_button = NULL;
175 if (fwin->right_button)
176 wCoreDestroy(fwin->right_button);
177 fwin->right_button = NULL;
179 wCoreDestroy(fwin->titlebar);
180 fwin->titlebar = NULL;
182 fwin->top_width = 0;
184 } else {
185 /* if we didn't have a titlebar and are being requested for
186 * one, create it */
187 if (flags & WFF_TITLEBAR) {
188 fwin->top_width = theight;
190 fwin->flags.titlebar = 1;
191 fwin->titlebar = wCoreCreate(fwin->core, 0, 0, width+1, theight);
193 if (flags & WFF_LEFT_BUTTON) {
194 fwin->flags.left_button = 1;
195 if (wPreferences.new_style) {
196 fwin->left_button = wCoreCreate(fwin->core, 0, 0,
197 bsize, bsize);
198 if (width < theight*4) {
199 fwin->flags.lbutton_dont_fit = 1;
200 } else {
201 XMapRaised(dpy, fwin->left_button->window);
203 } else {
204 fwin->left_button =
205 wCoreCreate(fwin->titlebar, 3, (theight-bsize)/2,
206 bsize, bsize);
208 XSetWindowBackground(dpy, fwin->left_button->window,
209 scr->widget_texture->normal.pixel);
211 if (width < theight*3) {
212 fwin->flags.lbutton_dont_fit = 1;
213 } else {
214 XMapRaised(dpy, fwin->left_button->window);
220 if (flags & WFF_RIGHT_BUTTON) {
221 fwin->flags.right_button = 1;
222 if (wPreferences.new_style) {
223 fwin->right_button =
224 wCoreCreate(fwin->core, width-bsize+1, 0,
225 bsize, bsize);
226 } else {
227 fwin->right_button =
228 wCoreCreate(fwin->titlebar, width-bsize-3,
229 (theight-bsize)/2, bsize, bsize);
230 XSetWindowBackground(dpy, fwin->right_button->window,
231 scr->widget_texture->normal.pixel);
234 if (width < theight*2) {
235 fwin->flags.rbutton_dont_fit = 1;
236 } else {
237 XMapRaised(dpy, fwin->right_button->window);
241 if (wPreferences.new_style)
242 updateTitlebar(fwin);
244 XMapRaised(dpy, fwin->titlebar->window);
246 fwin->flags.need_texture_remake = 1;
249 checkTitleSize(fwin);
251 if (flags & WFF_RESIZEBAR) {
252 fwin->bottom_width = RESIZEBAR_HEIGHT;
253 } else {
254 fwin->bottom_width = 0;
257 if (flags & WFF_RESIZEBAR) {
258 if (!fwin->resizebar) {
259 fwin->flags.resizebar = 1;
260 fwin->resizebar = wCoreCreate(fwin->core, 0,
261 height + fwin->top_width,
262 width, RESIZEBAR_HEIGHT);
263 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
264 if (width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
265 fwin->resizebar_corner_width = (width - RESIZEBAR_MIN_WIDTH)/2;
266 if (fwin->resizebar_corner_width < 0)
267 fwin->resizebar_corner_width = 0;
270 XMapWindow(dpy, fwin->resizebar->window);
271 XLowerWindow(dpy, fwin->resizebar->window);
273 fwin->flags.need_texture_remake = 1;
274 } else {
275 if (height+fwin->top_width+fwin->bottom_width != fwin->core->height) {
276 wCoreConfigure(fwin->resizebar, 0, height + fwin->top_width,
277 width, RESIZEBAR_HEIGHT);
280 } else {
281 if (fwin->resizebar) {
282 fwin->bottom_width = 0;
283 wCoreDestroy(fwin->resizebar);
284 fwin->resizebar = NULL;
288 if (height + fwin->top_width + fwin->bottom_width != fwin->core->height) {
289 wFrameWindowResize(fwin, width,
290 height + fwin->top_width + fwin->bottom_width);
293 /* setup object descriptors */
295 if (fwin->titlebar) {
296 fwin->titlebar->descriptor.handle_expose = handleExpose;
297 fwin->titlebar->descriptor.parent = fwin;
298 fwin->titlebar->descriptor.parent_type = WCLASS_FRAME;
299 fwin->titlebar->descriptor.handle_mousedown = titlebarMouseDown;
302 if (fwin->resizebar) {
303 fwin->resizebar->descriptor.handle_expose = handleExpose;
304 fwin->resizebar->descriptor.parent = fwin;
305 fwin->resizebar->descriptor.parent_type = WCLASS_FRAME;
306 fwin->resizebar->descriptor.handle_mousedown = resizebarMouseDown;
309 if (fwin->left_button) {
310 fwin->left_button->descriptor.handle_expose = handleButtonExpose;
311 fwin->left_button->descriptor.parent = fwin;
312 fwin->left_button->descriptor.parent_type = WCLASS_FRAME;
313 fwin->left_button->descriptor.handle_mousedown = buttonMouseDown;
316 if (fwin->right_button) {
317 fwin->right_button->descriptor.parent = fwin;
318 fwin->right_button->descriptor.parent_type = WCLASS_FRAME;
319 fwin->right_button->descriptor.handle_expose = handleButtonExpose;
320 fwin->right_button->descriptor.handle_mousedown = buttonMouseDown;
323 checkTitleSize(fwin);
328 void
329 wFrameWindowDestroy(WFrameWindow *fwin)
331 int i;
333 if (fwin->left_button)
334 wCoreDestroy(fwin->left_button);
336 if (fwin->right_button)
337 wCoreDestroy(fwin->right_button);
339 if (fwin->resizebar)
340 wCoreDestroy(fwin->resizebar);
342 if (fwin->titlebar)
343 wCoreDestroy(fwin->titlebar);
345 RemoveFromStackList(fwin->core);
347 wCoreDestroy(fwin->core);
349 if (fwin->title)
350 free(fwin->title);
352 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
353 FREE_PIXMAP(fwin->title_back[i]);
354 if (wPreferences.new_style) {
355 FREE_PIXMAP(fwin->lbutton_back[i]);
356 FREE_PIXMAP(fwin->rbutton_back[i]);
360 free(fwin);
364 void
365 wFrameWindowChangeState(WFrameWindow *fwin, int state)
367 if (fwin->flags.state==state)
368 return;
370 fwin->flags.state = state;
371 fwin->flags.need_texture_change = 1;
373 wFrameWindowPaint(fwin);
377 static void
378 updateTitlebar(WFrameWindow *fwin)
380 int x, w;
381 int theight;
383 theight = (*fwin->font)->height + TITLEBAR_EXTRA_HEIGHT;
385 x = 0;
386 w = fwin->core->width + 1;
388 if (wPreferences.new_style) {
389 if (fwin->flags.hide_left_button || !fwin->left_button
390 || fwin->flags.lbutton_dont_fit) {
391 x = 0;
392 } else {
393 x = fwin->left_button->width;
394 w -= fwin->left_button->width;
398 if (wPreferences.new_style) {
399 if (!fwin->flags.hide_right_button && fwin->right_button
400 && !fwin->flags.rbutton_dont_fit) {
401 w -= fwin->right_button->width;
405 if (wPreferences.new_style || fwin->titlebar->width!=w)
406 fwin->flags.need_texture_remake = 1;
408 wCoreConfigure(fwin->titlebar, x, 0, w, theight);
412 void
413 wFrameWindowHideButton(WFrameWindow *fwin, int flags)
415 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button) {
416 XUnmapWindow(dpy, fwin->right_button->window);
417 fwin->flags.hide_right_button = 1;
420 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button) {
421 XUnmapWindow(dpy, fwin->left_button->window);
422 fwin->flags.hide_left_button = 1;
425 if (fwin->titlebar) {
426 if (wPreferences.new_style) {
427 updateTitlebar(fwin);
428 } else {
429 XClearWindow(dpy, fwin->titlebar->window);
430 wFrameWindowPaint(fwin);
432 checkTitleSize(fwin);
437 void
438 wFrameWindowShowButton(WFrameWindow *fwin, int flags)
440 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button
441 && fwin->flags.hide_right_button) {
443 if (!fwin->flags.rbutton_dont_fit)
444 XMapWindow(dpy, fwin->right_button->window);
446 fwin->flags.hide_right_button = 0;
449 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button
450 && fwin->flags.hide_left_button) {
452 if (!fwin->flags.lbutton_dont_fit)
453 XMapWindow(dpy, fwin->left_button->window);
455 fwin->flags.hide_left_button = 0;
459 if (fwin->titlebar) {
460 if (wPreferences.new_style) {
461 updateTitlebar(fwin);
462 } else {
463 XClearWindow(dpy, fwin->titlebar->window);
464 wFrameWindowPaint(fwin);
466 checkTitleSize(fwin);
471 static void
472 renderTexture(WScreen *scr, WTexture *texture, int width, int height,
473 int bwidth, int bheight, int left, int right,
474 Pixmap *title, Pixmap *lbutton, Pixmap *rbutton)
476 RImage *img;
477 RImage *limg, *rimg, *mimg;
478 RColor color1, color2;
479 int i, x, w;
481 *title = None;
482 *lbutton = None;
483 *rbutton = None;
485 switch (texture->any.type) {
486 case WTEX_DGRADIENT:
487 case WTEX_VGRADIENT:
488 case WTEX_HGRADIENT:
489 case WTEX_MHGRADIENT:
490 case WTEX_MVGRADIENT:
491 case WTEX_MDGRADIENT:
492 if (texture->any.type==WTEX_DGRADIENT
493 || texture->any.type==WTEX_MDGRADIENT)
494 i = RGRD_DIAGONAL;
495 else if (texture->any.type==WTEX_HGRADIENT
496 || texture->any.type==WTEX_MHGRADIENT)
497 i = RGRD_HORIZONTAL;
498 else
499 i = RGRD_VERTICAL;
501 if (texture->any.type==WTEX_MHGRADIENT
502 || texture->any.type==WTEX_MDGRADIENT
503 || texture->any.type==WTEX_MVGRADIENT)
504 img = RRenderMultiGradient(width, height,
505 &(texture->mgradient.colors[1]), i);
506 else {
507 color1.red = texture->gradient.color1.red >> 8;
508 color1.green = texture->gradient.color1.green >> 8;
509 color1.blue = texture->gradient.color1.blue >> 8;
510 color2.red = texture->gradient.color2.red >> 8;
511 color2.green = texture->gradient.color2.green >> 8;
512 color2.blue = texture->gradient.color2.blue >> 8;
513 img = RRenderGradient(width, height, &color1, &color2, i);
515 break;
517 case WTEX_PIXMAP:
518 img = wTextureRenderImage(texture, width, height, WREL_FLAT);
519 break;
521 default:
522 img = NULL;
525 if (!img) {
526 wwarning(_("could not render gradient: %s"), RMessageForError(RErrorCode));
527 return;
530 if (wPreferences.new_style) {
531 if (left) {
532 limg = RGetSubImage(img, 0, 0, bwidth, bheight);
533 } else
534 limg = NULL;
536 x = 0;
537 w = img->width;
539 if (limg) {
540 RBevelImage(limg, RBEV_RAISED2);
541 if (!RConvertImage(scr->rcontext, limg, lbutton)) {
542 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
544 x += limg->width;
545 w -= limg->width;
546 RDestroyImage(limg);
549 if (right) {
550 rimg = RGetSubImage(img, width - bwidth, 0, bwidth, bheight);
551 } else
552 rimg = NULL;
554 if (rimg) {
555 RBevelImage(rimg, RBEV_RAISED2);
556 if (!RConvertImage(scr->rcontext, rimg, rbutton)) {
557 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
559 w -= rimg->width;
560 RDestroyImage(rimg);
563 if (w!=width) {
564 mimg = RGetSubImage(img, x, 0, w, img->height);
565 RBevelImage(mimg, RBEV_RAISED2);
567 if (!RConvertImage(scr->rcontext, mimg, title)) {
568 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
570 RDestroyImage(mimg);
571 } else {
572 RBevelImage(img, RBEV_RAISED2);
574 if (!RConvertImage(scr->rcontext, img, title)) {
575 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
578 } else {
579 RBevelImage(img, RBEV_RAISED2);
581 if (!RConvertImage(scr->rcontext, img, title)) {
582 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
586 RDestroyImage(img);
590 static void
591 updateTexture(WFrameWindow *fwin)
593 int i;
594 unsigned long pixel;
596 i = fwin->flags.state;
597 if (fwin->titlebar) {
598 if (fwin->title_texture[i]->any.type!=WTEX_SOLID) {
599 XSetWindowBackgroundPixmap(dpy, fwin->titlebar->window,
600 fwin->title_back[i]);
601 if (wPreferences.new_style) {
602 if (fwin->left_button && fwin->lbutton_back[i])
603 XSetWindowBackgroundPixmap(dpy, fwin->left_button->window,
604 fwin->lbutton_back[i]);
606 if (fwin->right_button && fwin->rbutton_back[i])
607 XSetWindowBackgroundPixmap(dpy, fwin->right_button->window,
608 fwin->rbutton_back[i]);
610 } else {
611 pixel = fwin->title_texture[i]->solid.normal.pixel;
612 XSetWindowBackground(dpy, fwin->titlebar->window, pixel);
613 if (wPreferences.new_style) {
614 if (fwin->left_button)
615 XSetWindowBackground(dpy, fwin->left_button->window,
616 pixel);
617 if (fwin->right_button)
618 XSetWindowBackground(dpy, fwin->right_button->window,
619 pixel);
622 XClearWindow(dpy, fwin->titlebar->window);
624 if (fwin->left_button) {
625 XClearWindow(dpy, fwin->left_button->window);
626 handleButtonExpose(&fwin->left_button->descriptor, NULL);
628 if (fwin->right_button) {
629 XClearWindow(dpy, fwin->right_button->window);
630 handleButtonExpose(&fwin->right_button->descriptor, NULL);
634 if (fwin->resizebar) {
635 XSetWindowBackground(dpy, fwin->resizebar->window,
636 fwin->resizebar_texture[0]->solid.normal.pixel);
637 XClearWindow(dpy, fwin->resizebar->window);
643 static void
644 remakeTexture(WFrameWindow *fwin, int state)
646 Pixmap pmap, lpmap, rpmap;
648 if (fwin->title_texture[state] && fwin->titlebar) {
649 FREE_PIXMAP(fwin->title_back[state]);
650 if (wPreferences.new_style) {
651 FREE_PIXMAP(fwin->lbutton_back[state]);
652 FREE_PIXMAP(fwin->rbutton_back[state]);
655 if (fwin->title_texture[state]->any.type!=WTEX_SOLID) {
656 int left, right;
657 int width;
659 /* eventually surrounded by if new_style */
660 left = fwin->left_button && !fwin->flags.hide_left_button
661 && !fwin->flags.lbutton_dont_fit;
662 right = fwin->right_button && !fwin->flags.hide_right_button
663 && !fwin->flags.rbutton_dont_fit;
665 width = fwin->core->width+1;
667 renderTexture(fwin->screen_ptr, fwin->title_texture[state],
668 width, fwin->titlebar->height,
669 fwin->titlebar->height, fwin->titlebar->height,
670 left, right, &pmap, &lpmap, &rpmap);
672 fwin->title_back[state] = pmap;
673 if (wPreferences.new_style) {
674 fwin->lbutton_back[state] = lpmap;
675 fwin->rbutton_back[state] = rpmap;
682 void
683 wFrameWindowPaint(WFrameWindow *fwin)
686 if (fwin->flags.is_client_window_frame)
687 fwin->flags.justification = wPreferences.title_justification;
689 if (fwin->flags.need_texture_remake) {
690 int i;
692 fwin->flags.need_texture_remake = 0;
693 fwin->flags.need_texture_change = 0;
695 if (fwin->flags.single_texture) {
696 remakeTexture(fwin, 0);
697 updateTexture(fwin);
698 } else {
699 /* first render the texture for the current state... */
700 remakeTexture(fwin, fwin->flags.state);
701 /* ... and paint it */
702 updateTexture(fwin);
704 for (i=0; i < 3; i++) {
705 if (i!=fwin->flags.state)
706 remakeTexture(fwin, i);
711 if (fwin->flags.need_texture_change) {
712 fwin->flags.need_texture_change = 0;
714 updateTexture(fwin);
717 if (fwin->titlebar && !fwin->flags.repaint_only_resizebar
718 && fwin->title_texture[fwin->flags.state]->any.type==WTEX_SOLID) {
719 wDrawBevel(fwin->titlebar->window, fwin->titlebar->width,
720 fwin->titlebar->height,
721 (WTexSolid*)fwin->title_texture[fwin->flags.state],
722 WREL_RAISED);
725 if (fwin->resizebar
726 && !fwin->flags.repaint_only_titlebar) {
727 Window win;
728 int w, h;
729 int cw;
730 GC light_gc, dim_gc;
731 WTexSolid *texture = (WTexSolid*)fwin->resizebar_texture[0];
733 w = fwin->resizebar->width;
734 h = fwin->resizebar->height;
735 cw = fwin->resizebar_corner_width;
736 light_gc = texture->light_gc;
737 dim_gc = texture->dim_gc;
738 win = fwin->resizebar->window;
740 XDrawLine(dpy, win, dim_gc, 0, 0, w, 0);
741 XDrawLine(dpy, win, light_gc, 0, 1, w, 1);
743 XDrawLine(dpy, win, dim_gc, cw, 2, cw, h);
744 XDrawLine(dpy, win, light_gc, cw+1, 2, cw+1, h);
746 XDrawLine(dpy, win, dim_gc, w-cw-2, 2, w-cw-2, h);
747 XDrawLine(dpy, win, light_gc, w-cw-1, 2, w-cw-1, h);
749 #ifdef SHADOW_RESIZEBAR
750 XDrawLine(dpy, win, light_gc, 0, 1, 0, h-1);
751 XDrawLine(dpy, win, dim_gc, w-1, 2, w-1, h-1);
752 XDrawLine(dpy, win, dim_gc, 1, h-1, cw, h-1);
753 XDrawLine(dpy, win, dim_gc, cw+2, h-1, w-cw-2, h-1);
754 XDrawLine(dpy, win, dim_gc, w-cw, h-1, w-1, h-1);
755 #endif /* SHADOW_RESIZEBAR */
759 if (fwin->title && fwin->titlebar
760 && !fwin->flags.repaint_only_resizebar) {
761 int x, w;
762 int lofs = 6, rofs = 6;
763 int titlelen;
764 char *title;
765 int allButtons = 1;
768 if (!wPreferences.new_style) {
769 if (fwin->left_button && !fwin->flags.hide_left_button
770 && !fwin->flags.lbutton_dont_fit)
771 lofs += fwin->left_button->width + 3;
772 else
773 allButtons = 0;
775 if (fwin->right_button && !fwin->flags.hide_right_button
776 && !fwin->flags.rbutton_dont_fit)
777 rofs += fwin->right_button->width + 3;
778 else
779 allButtons = 0;
781 title = ShrinkString(*fwin->font, fwin->title,
782 fwin->titlebar->width - lofs - rofs);
783 titlelen = strlen(title);
784 w = wTextWidth((*fwin->font)->font, title, titlelen);
786 switch (fwin->flags.justification) {
787 case WTJ_LEFT:
788 x = lofs;
789 break;
791 case WTJ_RIGHT:
792 x = fwin->titlebar->width - w - rofs;
793 break;
795 default:
796 if (!allButtons)
797 x = lofs + (fwin->titlebar->width - w - lofs - rofs) / 2;
798 else
799 x = (fwin->titlebar->width - w) / 2;
800 break;
803 XSetForeground(dpy, *fwin->title_gc,
804 fwin->title_pixel[fwin->flags.state]);
806 wDrawString(fwin->titlebar->window, *fwin->font,
807 *fwin->title_gc, x,
808 (*fwin->font)->y + TITLEBAR_EXTRA_HEIGHT/2, title,
809 titlelen);
811 free(title);
816 void
817 wFrameWindowResize(WFrameWindow *fwin, int width, int height)
819 int k = (wPreferences.new_style ? 4 : 3);
820 int resizedHorizontally = 0;
822 XResizeWindow(dpy, fwin->core->window, width, height);
824 if (fwin->core->height != height && fwin->resizebar)
825 XMoveWindow(dpy, fwin->resizebar->window, 0,
826 height - fwin->resizebar->height);
828 if (fwin->core->width != width) {
829 fwin->flags.need_texture_remake = 1;
830 resizedHorizontally = 1;
833 fwin->core->width = width;
834 fwin->core->height = height;
836 if (fwin->titlebar && resizedHorizontally) {
837 /* Check if the titlebar is wide enough to hold the buttons.
838 * Temporarily remove them if can't
840 if (fwin->left_button) {
841 if (width < fwin->top_width*k && !fwin->flags.lbutton_dont_fit) {
843 if (!fwin->flags.hide_left_button) {
844 XUnmapWindow(dpy, fwin->left_button->window);
846 fwin->flags.lbutton_dont_fit = 1;
847 } else if (width >= fwin->top_width*k && fwin->flags.lbutton_dont_fit) {
849 if (!fwin->flags.hide_left_button) {
850 XMapWindow(dpy, fwin->left_button->window);
852 fwin->flags.lbutton_dont_fit = 0;
856 if (fwin->right_button) {
857 if (width < fwin->top_width*2 && !fwin->flags.rbutton_dont_fit) {
859 if (!fwin->flags.hide_right_button) {
860 XUnmapWindow(dpy, fwin->right_button->window);
862 fwin->flags.rbutton_dont_fit = 1;
863 } else if (width >= fwin->top_width*2 && fwin->flags.rbutton_dont_fit) {
865 if (!fwin->flags.hide_right_button) {
866 XMapWindow(dpy, fwin->right_button->window);
868 fwin->flags.rbutton_dont_fit = 0;
872 if (wPreferences.new_style) {
873 if (fwin->right_button)
874 XMoveWindow(dpy, fwin->right_button->window,
875 width - fwin->right_button->width + 1, 0);
876 } else {
877 if (fwin->right_button)
878 XMoveWindow(dpy, fwin->right_button->window,
879 width - fwin->right_button->width - 3,
880 (fwin->titlebar->height - fwin->right_button->height)/2);
882 updateTitlebar(fwin);
883 checkTitleSize(fwin);
886 if (fwin->resizebar) {
887 wCoreConfigure(fwin->resizebar, 0,
888 fwin->core->height - fwin->resizebar->height,
889 fwin->core->width, fwin->resizebar->height);
891 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
892 if (fwin->core->width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
893 fwin->resizebar_corner_width = fwin->core->width/2;
899 void
900 wFrameWindowResizeInternal(WFrameWindow *fwin, int iwidth, int iheight)
902 wFrameWindowResize(fwin, iwidth,
903 iheight + fwin->top_width + fwin->bottom_width);
908 int
909 wFrameWindowChangeTitle(WFrameWindow *fwin, char *new_title)
911 /* check if the title is the same as before */
912 if (fwin->title) {
913 if (new_title && (strcmp(fwin->title, new_title) == 0)) {
914 return 0;
916 } else {
917 if (!new_title)
918 return 0;
921 if (fwin->title)
922 free(fwin->title);
924 fwin->title = wstrdup(new_title);
926 if (fwin->titlebar) {
927 XClearWindow(dpy, fwin->titlebar->window);
929 wFrameWindowPaint(fwin);
931 checkTitleSize(fwin);
933 return 1;
937 /*********************************************************************/
939 static void
940 handleExpose(WObjDescriptor *desc, XEvent *event)
942 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
945 if (fwin->titlebar && fwin->titlebar->window == event->xexpose.window)
946 fwin->flags.repaint_only_titlebar = 1;
947 if (fwin->resizebar && fwin->resizebar->window == event->xexpose.window)
948 fwin->flags.repaint_only_resizebar = 1;
949 wFrameWindowPaint(fwin);
950 fwin->flags.repaint_only_titlebar = 0;
951 fwin->flags.repaint_only_resizebar = 0;
955 static void
956 checkTitleSize(WFrameWindow *fwin)
958 int width;
960 if (!fwin->title) {
961 fwin->flags.incomplete_title = 0;
962 return;
965 if (!fwin->titlebar) {
966 fwin->flags.incomplete_title = 1;
967 return;
968 } else {
969 width = fwin->titlebar->width - 6 - 6;
972 if (!wPreferences.new_style) {
973 if (fwin->left_button && !fwin->flags.hide_left_button
974 && !fwin->flags.lbutton_dont_fit)
975 width -= fwin->left_button->width + 3;
977 if (fwin->right_button && !fwin->flags.hide_right_button
978 && !fwin->flags.rbutton_dont_fit)
979 width -= fwin->right_button->width + 3;
981 if (wTextWidth((*fwin->font)->font, fwin->title,
982 strlen(fwin->title)) > width) {
983 fwin->flags.incomplete_title = 1;
984 } else {
985 fwin->flags.incomplete_title = 0;
989 static void
990 paintButton(WCoreWindow *button, WTexture *texture, unsigned long color,
991 WPixmap *image, int pushed)
993 WScreen *scr = button->screen_ptr;
994 GC copy_gc = scr->copy_gc;
995 int x=0, y=0, d=0;
996 int left=0, width=0;
998 /* setup stuff according to the state */
999 if (pushed) {
1000 if (image) {
1001 if (image->width>=image->height*2) {
1002 /* the image contains 2 pictures: the second is for the
1003 * pushed state */
1004 width = image->width/2;
1005 left = image->width/2;
1006 } else {
1007 width = image->width;
1010 XSetClipMask(dpy, copy_gc, None);
1011 XSetForeground(dpy, copy_gc, scr->white_pixel);
1012 d=1;
1013 if (wPreferences.new_style) {
1014 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1015 button->width-1, button->height-1);
1016 XSetForeground(dpy, copy_gc, scr->black_pixel);
1017 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1018 button->width-1, button->height-1);
1019 } else {
1020 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1021 button->width, button->height);
1022 XSetForeground(dpy, copy_gc, scr->black_pixel);
1023 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1024 button->width, button->height);
1026 } else {
1027 XClearWindow(dpy, button->window);
1029 if (image) {
1030 if (image->width>=image->height*2)
1031 width = image->width/2;
1032 else
1033 width = image->width;
1035 d=0;
1037 if (wPreferences.new_style) {
1038 if (texture->any.type==WTEX_SOLID || pushed) {
1039 wDrawBevel(button->window, button->width, button->height,
1040 (WTexSolid*)texture, WREL_RAISED);
1042 } else {
1043 wDrawBevel(button->window, button->width, button->height,
1044 scr->widget_texture, WREL_RAISED);
1048 if (image) {
1049 /* display image */
1050 XSetClipMask(dpy, copy_gc, image->mask);
1051 x = (button->width - width)/2 + d;
1052 y = (button->height - image->height)/2 + d;
1053 XSetClipOrigin(dpy, copy_gc, x-left, y);
1054 if (!wPreferences.new_style) {
1055 XSetForeground(dpy, copy_gc, scr->black_pixel);
1056 if (!pushed) {
1057 if (image->depth==1)
1058 XCopyPlane(dpy, image->image, button->window, copy_gc,
1059 left, 0, width, image->height, x, y, 1);
1060 else
1061 XCopyArea(dpy, image->image, button->window, copy_gc,
1062 left, 0, width, image->height, x, y);
1063 } else {
1064 XSetForeground(dpy, copy_gc, scr->dark_pixel);
1065 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1066 button->width, button->height);
1068 } else {
1069 if (pushed) {
1070 XSetForeground(dpy, copy_gc, scr->black_pixel);
1071 } else {
1072 XSetForeground(dpy, copy_gc, color);
1073 XSetBackground(dpy, copy_gc, texture->any.color.pixel);
1075 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1076 button->width, button->height);
1082 static void
1083 handleButtonExpose(WObjDescriptor *desc, XEvent *event)
1085 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
1086 WCoreWindow *button = (WCoreWindow*)desc->self;
1088 if (button == fwin->left_button) {
1089 paintButton(button, fwin->title_texture[fwin->flags.state],
1090 fwin->title_pixel[fwin->flags.state],
1091 fwin->lbutton_image, False);
1092 } else {
1093 paintButton(button, fwin->title_texture[fwin->flags.state],
1094 fwin->title_pixel[fwin->flags.state],
1095 fwin->rbutton_image, False);
1100 static void
1101 titlebarMouseDown(WObjDescriptor *desc, XEvent *event)
1103 WFrameWindow *fwin = desc->parent;
1104 WCoreWindow *titlebar = desc->self;
1106 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1107 if (fwin->on_dblclick_titlebar)
1108 (*fwin->on_dblclick_titlebar)(titlebar, fwin->child, event);
1109 } else {
1110 if (fwin->on_mousedown_titlebar)
1111 (*fwin->on_mousedown_titlebar)(titlebar, fwin->child, event);
1116 static void
1117 resizebarMouseDown(WObjDescriptor *desc, XEvent *event)
1119 WFrameWindow *fwin = desc->parent;
1120 WCoreWindow *resizebar = desc->self;
1122 if (fwin->on_mousedown_resizebar)
1123 (*fwin->on_mousedown_resizebar)(resizebar, fwin->child, event);
1127 static void
1128 buttonMouseDown(WObjDescriptor *desc, XEvent *event)
1130 WFrameWindow *fwin = desc->parent;
1131 WCoreWindow *button = desc->self;
1132 WPixmap *image;
1133 XEvent ev;
1134 int done=0, execute=1;
1135 WTexture *texture;
1136 unsigned long pixel;
1137 int clickButton = event->xbutton.button;
1139 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1140 if (button == fwin->right_button && fwin->on_dblclick_right) {
1141 (*fwin->on_dblclick_right)(button, fwin->child, event);
1143 return;
1146 if (button == fwin->left_button) {
1147 image = fwin->lbutton_image;
1148 } else {
1149 image = fwin->rbutton_image;
1152 pixel = fwin->title_pixel[fwin->flags.state];
1153 texture = fwin->title_texture[fwin->flags.state];
1154 paintButton(button, texture, pixel, image, True);
1156 while (!done) {
1157 WMMaskEvent(dpy, LeaveWindowMask|EnterWindowMask|ButtonReleaseMask
1158 |ButtonPressMask|ExposureMask, &ev);
1159 switch (ev.type) {
1160 case LeaveNotify:
1161 execute = 0;
1162 paintButton(button, texture, pixel, image, False);
1163 break;
1165 case EnterNotify:
1166 execute = 1;
1167 paintButton(button, texture, pixel, image, True);
1168 break;
1170 case ButtonPress:
1171 break;
1173 case ButtonRelease:
1174 if (ev.xbutton.button == clickButton)
1175 done = 1;
1176 break;
1178 default:
1179 WMHandleEvent(&ev);
1182 paintButton(button, texture, pixel, image, False);
1184 if (execute) {
1185 if (button == fwin->left_button) {
1186 if (fwin->on_click_left)
1187 (*fwin->on_click_left)(button, fwin->child, &ev);
1188 } else if (button == fwin->right_button) {
1189 if (fwin->on_click_right)
1190 (*fwin->on_click_right)(button, fwin->child, &ev);