Initial revision
[wmaker-crm.git] / src / framewin.c
blob59704dce265c198f4d6ab970597dcec1c28ef763
1 /*
2 * WindowMaker 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"), RErrorString);
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"), RErrorString);
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"), RErrorString);
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"), RErrorString);
570 RDestroyImage(mimg);
571 } else {
572 RBevelImage(img, RBEV_RAISED2);
574 if (!RConvertImage(scr->rcontext, img, title)) {
575 wwarning(_("error rendering image:%s"), RErrorString);
578 } else {
579 RBevelImage(img, RBEV_RAISED2);
581 if (!RConvertImage(scr->rcontext, img, title)) {
582 wwarning(_("error rendering image:%s"), RErrorString);
586 RDestroyImage(img);
590 void
591 wFrameWindowPaint(WFrameWindow *fwin)
594 if (fwin->flags.is_client_window_frame)
595 fwin->flags.justification = wPreferences.title_justification;
597 if (fwin->flags.need_texture_remake) {
598 int i;
599 Pixmap pmap, lpmap, rpmap;
601 fwin->flags.need_texture_remake = 0;
603 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
604 if (fwin->title_texture[i] && fwin->titlebar) {
605 FREE_PIXMAP(fwin->title_back[i]);
606 if (wPreferences.new_style) {
607 FREE_PIXMAP(fwin->lbutton_back[i]);
608 FREE_PIXMAP(fwin->rbutton_back[i]);
611 if (fwin->title_texture[i]->any.type!=WTEX_SOLID) {
612 int left, right;
613 int width;
615 /* eventually surrounded by if new_style */
616 left = fwin->left_button && !fwin->flags.hide_left_button
617 && !fwin->flags.lbutton_dont_fit;
618 right = fwin->right_button && !fwin->flags.hide_right_button
619 && !fwin->flags.rbutton_dont_fit;
621 width = fwin->core->width+1;
623 renderTexture(fwin->screen_ptr, fwin->title_texture[i],
624 width, fwin->titlebar->height,
625 fwin->titlebar->height, fwin->titlebar->height,
626 left, right, &pmap, &lpmap, &rpmap);
628 fwin->title_back[i] = pmap;
629 if (wPreferences.new_style) {
630 fwin->lbutton_back[i] = lpmap;
631 fwin->rbutton_back[i] = rpmap;
637 fwin->flags.need_texture_change = 1;
640 if (fwin->flags.need_texture_change) {
641 int i;
642 unsigned long pixel;
644 fwin->flags.need_texture_change = 0;
646 i = fwin->flags.state;
647 if (fwin->titlebar) {
648 if (fwin->title_texture[i]->any.type!=WTEX_SOLID) {
649 XSetWindowBackgroundPixmap(dpy, fwin->titlebar->window,
650 fwin->title_back[i]);
651 if (wPreferences.new_style) {
652 if (fwin->left_button && fwin->lbutton_back[i])
653 XSetWindowBackgroundPixmap(dpy,
654 fwin->left_button->window,
655 fwin->lbutton_back[i]);
657 if (fwin->right_button && fwin->rbutton_back[i])
658 XSetWindowBackgroundPixmap(dpy,
659 fwin->right_button->window,
660 fwin->rbutton_back[i]);
662 } else {
663 pixel = fwin->title_texture[i]->solid.normal.pixel;
664 XSetWindowBackground(dpy, fwin->titlebar->window, pixel);
665 if (wPreferences.new_style) {
666 if (fwin->left_button)
667 XSetWindowBackground(dpy, fwin->left_button->window,
668 pixel);
669 if (fwin->right_button)
670 XSetWindowBackground(dpy, fwin->right_button->window,
671 pixel);
674 XClearWindow(dpy, fwin->titlebar->window);
676 if (fwin->left_button) {
677 XClearWindow(dpy, fwin->left_button->window);
678 handleButtonExpose(&fwin->left_button->descriptor, NULL);
680 if (fwin->right_button) {
681 XClearWindow(dpy, fwin->right_button->window);
682 handleButtonExpose(&fwin->right_button->descriptor, NULL);
686 if (fwin->resizebar) {
687 XSetWindowBackground(dpy, fwin->resizebar->window,
688 fwin->resizebar_texture[0]->solid.normal.pixel);
689 XClearWindow(dpy, fwin->resizebar->window);
693 if (fwin->titlebar && !fwin->flags.repaint_only_resizebar
694 && fwin->title_texture[fwin->flags.state]->any.type==WTEX_SOLID) {
695 wDrawBevel(fwin->titlebar,
696 (WTexSolid*)fwin->title_texture[fwin->flags.state],
697 WREL_RAISED);
700 if (fwin->resizebar
701 && !fwin->flags.repaint_only_titlebar) {
702 Window win;
703 int w, h;
704 int cw;
705 GC light_gc, dim_gc;
706 WTexSolid *texture = (WTexSolid*)fwin->resizebar_texture[0];
708 w = fwin->resizebar->width;
709 h = fwin->resizebar->height;
710 cw = fwin->resizebar_corner_width;
711 light_gc = texture->light_gc;
712 dim_gc = texture->dim_gc;
713 win = fwin->resizebar->window;
715 XDrawLine(dpy, win, dim_gc, 0, 0, w, 0);
716 XDrawLine(dpy, win, light_gc, 0, 1, w, 1);
718 XDrawLine(dpy, win, dim_gc, cw, 2, cw, h);
719 XDrawLine(dpy, win, light_gc, cw+1, 2, cw+1, h);
721 XDrawLine(dpy, win, dim_gc, w-cw-2, 2, w-cw-2, h);
722 XDrawLine(dpy, win, light_gc, w-cw-1, 2, w-cw-1, h);
724 #ifdef SHADOW_RESIZEBAR
725 XDrawLine(dpy, win, light_gc, 0, 1, 0, h-1);
726 XDrawLine(dpy, win, dim_gc, w-1, 2, w-1, h-1);
727 XDrawLine(dpy, win, dim_gc, 1, h-1, cw, h-1);
728 XDrawLine(dpy, win, dim_gc, cw+2, h-1, w-cw-2, h-1);
729 XDrawLine(dpy, win, dim_gc, w-cw, h-1, w-1, h-1);
730 #endif /* SHADOW_RESIZEBAR */
734 if (fwin->title && fwin->titlebar
735 && !fwin->flags.repaint_only_resizebar) {
736 int x, w;
737 int lofs = 6, rofs = 6;
738 int titlelen;
739 char *title;
740 int allButtons = 1;
743 if (!wPreferences.new_style) {
744 if (fwin->left_button && !fwin->flags.hide_left_button
745 && !fwin->flags.lbutton_dont_fit)
746 lofs += fwin->left_button->width + 3;
747 else
748 allButtons = 0;
750 if (fwin->right_button && !fwin->flags.hide_right_button
751 && !fwin->flags.rbutton_dont_fit)
752 rofs += fwin->right_button->width + 3;
753 else
754 allButtons = 0;
756 title = ShrinkString(*fwin->font, fwin->title,
757 fwin->titlebar->width - lofs - rofs);
758 titlelen = strlen(title);
759 w = wTextWidth((*fwin->font)->font, title, titlelen);
761 switch (fwin->flags.justification) {
762 case WTJ_LEFT:
763 x = lofs;
764 break;
766 case WTJ_RIGHT:
767 x = fwin->titlebar->width - w - rofs;
768 break;
770 default:
771 if (!allButtons)
772 x = lofs + (fwin->titlebar->width - w - lofs - rofs) / 2;
773 else
774 x = (fwin->titlebar->width - w) / 2;
775 break;
778 XSetForeground(dpy, *fwin->title_gc,
779 fwin->title_pixel[fwin->flags.state]);
781 wDrawString(fwin->titlebar->window, *fwin->font,
782 *fwin->title_gc, x,
783 (*fwin->font)->y + TITLEBAR_EXTRA_HEIGHT/2, title,
784 titlelen);
786 free(title);
791 void
792 wFrameWindowResize(WFrameWindow *fwin, int width, int height)
794 int k = (wPreferences.new_style ? 4 : 3);
795 int resizedHorizontally = 0;
797 XResizeWindow(dpy, fwin->core->window, width, height);
799 if (fwin->core->height != height && fwin->resizebar)
800 XMoveWindow(dpy, fwin->resizebar->window, 0,
801 height - fwin->resizebar->height);
803 if (fwin->core->width != width) {
804 fwin->flags.need_texture_remake = 1;
805 resizedHorizontally = 1;
808 fwin->core->width = width;
809 fwin->core->height = height;
811 if (fwin->titlebar && resizedHorizontally) {
812 /* Check if the titlebar is wide enough to hold the buttons.
813 * Temporarily remove them if can't
815 if (fwin->left_button) {
816 if (width < fwin->top_width*k && !fwin->flags.lbutton_dont_fit) {
818 if (!fwin->flags.hide_left_button) {
819 XUnmapWindow(dpy, fwin->left_button->window);
821 fwin->flags.lbutton_dont_fit = 1;
822 } else if (width >= fwin->top_width*k && fwin->flags.lbutton_dont_fit) {
824 if (!fwin->flags.hide_left_button) {
825 XMapWindow(dpy, fwin->left_button->window);
827 fwin->flags.lbutton_dont_fit = 0;
831 if (fwin->right_button) {
832 if (width < fwin->top_width*2 && !fwin->flags.rbutton_dont_fit) {
834 if (!fwin->flags.hide_right_button) {
835 XUnmapWindow(dpy, fwin->right_button->window);
837 fwin->flags.rbutton_dont_fit = 1;
838 } else if (width >= fwin->top_width*2 && fwin->flags.rbutton_dont_fit) {
840 if (!fwin->flags.hide_right_button) {
841 XMapWindow(dpy, fwin->right_button->window);
843 fwin->flags.rbutton_dont_fit = 0;
847 if (wPreferences.new_style) {
848 if (fwin->right_button)
849 XMoveWindow(dpy, fwin->right_button->window,
850 width - fwin->right_button->width + 1, 0);
851 } else {
852 if (fwin->right_button)
853 XMoveWindow(dpy, fwin->right_button->window,
854 width - fwin->right_button->width - 3,
855 (fwin->titlebar->height - fwin->right_button->height)/2);
857 updateTitlebar(fwin);
858 checkTitleSize(fwin);
861 if (fwin->resizebar) {
862 wCoreConfigure(fwin->resizebar, 0,
863 fwin->core->height - fwin->resizebar->height,
864 fwin->core->width, fwin->resizebar->height);
866 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
867 if (fwin->core->width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
868 fwin->resizebar_corner_width = fwin->core->width/2;
874 void
875 wFrameWindowResizeInternal(WFrameWindow *fwin, int iwidth, int iheight)
877 wFrameWindowResize(fwin, iwidth,
878 iheight + fwin->top_width + fwin->bottom_width);
883 int
884 wFrameWindowChangeTitle(WFrameWindow *fwin, char *new_title)
886 /* check if the title is the same as before */
887 if (fwin->title) {
888 if (new_title && (strcmp(fwin->title, new_title) == 0)) {
889 return 0;
891 } else {
892 if (!new_title)
893 return 0;
896 if (fwin->title)
897 free(fwin->title);
899 fwin->title = wstrdup(new_title);
901 if (fwin->titlebar) {
902 XClearWindow(dpy, fwin->titlebar->window);
904 wFrameWindowPaint(fwin);
906 checkTitleSize(fwin);
908 return 1;
912 /*********************************************************************/
914 static void
915 handleExpose(WObjDescriptor *desc, XEvent *event)
917 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
920 if (fwin->titlebar && fwin->titlebar->window == event->xexpose.window)
921 fwin->flags.repaint_only_titlebar = 1;
922 if (fwin->resizebar && fwin->resizebar->window == event->xexpose.window)
923 fwin->flags.repaint_only_resizebar = 1;
924 wFrameWindowPaint(fwin);
925 fwin->flags.repaint_only_titlebar = 0;
926 fwin->flags.repaint_only_resizebar = 0;
930 static void
931 checkTitleSize(WFrameWindow *fwin)
933 int width;
935 if (!fwin->title) {
936 fwin->flags.incomplete_title = 0;
937 return;
940 if (!fwin->titlebar) {
941 fwin->flags.incomplete_title = 1;
942 return;
943 } else {
944 width = fwin->titlebar->width - 6 - 6;
947 if (!wPreferences.new_style) {
948 if (fwin->left_button && !fwin->flags.hide_left_button
949 && !fwin->flags.lbutton_dont_fit)
950 width -= fwin->left_button->width + 3;
952 if (fwin->right_button && !fwin->flags.hide_right_button
953 && !fwin->flags.rbutton_dont_fit)
954 width -= fwin->right_button->width + 3;
956 if (wTextWidth((*fwin->font)->font, fwin->title,
957 strlen(fwin->title)) > width) {
958 fwin->flags.incomplete_title = 1;
959 } else {
960 fwin->flags.incomplete_title = 0;
964 static void
965 paintButton(WCoreWindow *button, WTexture *texture, unsigned long color,
966 WPixmap *image, int pushed)
968 WScreen *scr = button->screen_ptr;
969 GC copy_gc = scr->copy_gc;
970 int x=0, y=0, d=0;
971 int left=0, width=0;
973 /* setup stuff according to the state */
974 if (pushed) {
975 if (image) {
976 if (image->width>=image->height*2) {
977 /* the image contains 2 pictures: the second is for the
978 * pushed state */
979 width = image->width/2;
980 left = image->width/2;
981 } else {
982 width = image->width;
985 XSetClipMask(dpy, copy_gc, None);
986 XSetForeground(dpy, copy_gc, scr->white_pixel);
987 d=1;
988 if (wPreferences.new_style) {
989 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
990 button->width-1, button->height-1);
991 XSetForeground(dpy, copy_gc, scr->black_pixel);
992 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
993 button->width-1, button->height-1);
994 } else {
995 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
996 button->width, button->height);
997 XSetForeground(dpy, copy_gc, scr->black_pixel);
998 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
999 button->width, button->height);
1001 } else {
1002 XClearWindow(dpy, button->window);
1004 if (image) {
1005 if (image->width>=image->height*2)
1006 width = image->width/2;
1007 else
1008 width = image->width;
1010 d=0;
1012 if (wPreferences.new_style) {
1013 if (texture->any.type==WTEX_SOLID || pushed) {
1014 wDrawBevel(button, (WTexSolid*)texture, WREL_RAISED);
1016 } else {
1017 wDrawBevel(button, scr->widget_texture, WREL_RAISED);
1021 if (image) {
1022 /* display image */
1023 XSetClipMask(dpy, copy_gc, image->mask);
1024 x = (button->width - width)/2 + d;
1025 y = (button->height - image->height)/2 + d;
1026 XSetClipOrigin(dpy, copy_gc, x-left, y);
1027 if (!wPreferences.new_style) {
1028 XSetForeground(dpy, copy_gc, scr->black_pixel);
1029 if (!pushed) {
1030 if (image->depth==1)
1031 XCopyPlane(dpy, image->image, button->window, copy_gc,
1032 left, 0, width, image->height, x, y, 1);
1033 else
1034 XCopyArea(dpy, image->image, button->window, copy_gc,
1035 left, 0, width, image->height, x, y);
1036 } else {
1037 XSetForeground(dpy, copy_gc, scr->dark_pixel);
1038 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1039 button->width, button->height);
1041 } else {
1042 if (pushed) {
1043 XSetForeground(dpy, copy_gc, scr->black_pixel);
1044 } else {
1045 XSetForeground(dpy, copy_gc, color);
1046 XSetBackground(dpy, copy_gc, texture->any.color.pixel);
1048 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1049 button->width, button->height);
1055 static void
1056 handleButtonExpose(WObjDescriptor *desc, XEvent *event)
1058 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
1059 WCoreWindow *button = (WCoreWindow*)desc->self;
1061 if (button == fwin->left_button) {
1062 paintButton(button, fwin->title_texture[fwin->flags.state],
1063 fwin->title_pixel[fwin->flags.state],
1064 fwin->lbutton_image, False);
1065 } else {
1066 paintButton(button, fwin->title_texture[fwin->flags.state],
1067 fwin->title_pixel[fwin->flags.state],
1068 fwin->rbutton_image, False);
1073 static void
1074 titlebarMouseDown(WObjDescriptor *desc, XEvent *event)
1076 WFrameWindow *fwin = desc->parent;
1077 WCoreWindow *titlebar = desc->self;
1079 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1080 if (fwin->on_dblclick_titlebar)
1081 (*fwin->on_dblclick_titlebar)(titlebar, fwin->child, event);
1082 } else {
1083 if (fwin->on_mousedown_titlebar)
1084 (*fwin->on_mousedown_titlebar)(titlebar, fwin->child, event);
1089 static void
1090 resizebarMouseDown(WObjDescriptor *desc, XEvent *event)
1092 WFrameWindow *fwin = desc->parent;
1093 WCoreWindow *resizebar = desc->self;
1095 if (fwin->on_mousedown_resizebar)
1096 (*fwin->on_mousedown_resizebar)(resizebar, fwin->child, event);
1100 static void
1101 buttonMouseDown(WObjDescriptor *desc, XEvent *event)
1103 WFrameWindow *fwin = desc->parent;
1104 WCoreWindow *button = desc->self;
1105 WPixmap *image;
1106 XEvent ev;
1107 int done=0, execute=1;
1108 WTexture *texture;
1109 unsigned long pixel;
1110 int clickButton = event->xbutton.button;
1112 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1113 if (button == fwin->right_button && fwin->on_dblclick_right) {
1114 (*fwin->on_dblclick_right)(button, fwin->child, event);
1116 return;
1119 if (button == fwin->left_button) {
1120 image = fwin->lbutton_image;
1121 } else {
1122 image = fwin->rbutton_image;
1125 pixel = fwin->title_pixel[fwin->flags.state];
1126 texture = fwin->title_texture[fwin->flags.state];
1127 paintButton(button, texture, pixel, image, True);
1129 while (!done) {
1130 WMMaskEvent(dpy, LeaveWindowMask|EnterWindowMask|ButtonReleaseMask
1131 |ButtonPressMask|ExposureMask, &ev);
1132 switch (ev.type) {
1133 case LeaveNotify:
1134 execute = 0;
1135 paintButton(button, texture, pixel, image, False);
1136 break;
1138 case EnterNotify:
1139 execute = 1;
1140 paintButton(button, texture, pixel, image, True);
1141 break;
1143 case ButtonPress:
1144 break;
1146 case ButtonRelease:
1147 if (ev.xbutton.button == clickButton)
1148 done = 1;
1149 break;
1151 default:
1152 WMHandleEvent(&ev);
1155 paintButton(button, texture, pixel, image, False);
1157 if (execute) {
1158 if (button == fwin->left_button) {
1159 if (fwin->on_click_left)
1160 (*fwin->on_click_left)(button, fwin->child, &ev);
1161 } else if (button == fwin->right_button) {
1162 if (fwin->on_click_right)
1163 (*fwin->on_click_right)(button, fwin->child, &ev);