Update for 0.51.0
[wmaker-crm.git] / src / framewin.c
blobd3eee0edfad0d44ba709c77ce09c44ad6e98248e
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;
74 fwin->flags.single_texture = (flags & WFF_SINGLE_STATE) ? 1 : 0;
76 fwin->title_texture = title_texture;
77 fwin->resizebar_texture = resize_texture;
78 fwin->title_pixel = color;
79 fwin->title_gc = gc;
80 fwin->font = font;
82 fwin->core = wCoreCreateTopLevel(scr, x, y, width, height,
83 FRAME_BORDER_WIDTH);
84 if (wPreferences.use_saveunders) {
85 unsigned long vmask;
86 XSetWindowAttributes attribs;
88 vmask = CWSaveUnder;
89 attribs.save_under = True;
90 XChangeWindowAttributes(dpy, fwin->core->window, vmask, &attribs);
93 /* setup stacking information */
94 fwin->core->stacking = wmalloc(sizeof(WStacking));
95 fwin->core->stacking->above = NULL;
96 fwin->core->stacking->under = NULL;
97 fwin->core->stacking->child_of = NULL;
98 fwin->core->stacking->window_level = wlevel;
100 AddToStackList(fwin->core);
102 wFrameWindowUpdateBorders(fwin, flags);
104 return fwin;
109 void
110 wFrameWindowUpdateBorders(WFrameWindow *fwin, int flags)
112 int theight;
113 int bsize;
114 int width, height;
115 int i;
116 WScreen *scr = fwin->screen_ptr;
118 width = fwin->core->width;
119 height = fwin->core->height - fwin->top_width - fwin->bottom_width;
121 if (flags & WFF_TITLEBAR)
122 theight = (*fwin->font)->height + TITLEBAR_EXTRA_HEIGHT;
123 else
124 theight = 0;
126 if (wPreferences.new_style) {
127 bsize = theight;
128 } else {
129 bsize = theight - 7;
132 if (fwin->titlebar) {
133 /* if we had a titlebar and is requesting for one,
134 * check if the size has changed and resize it */
135 if (flags & WFF_TITLEBAR) {
136 fwin->top_width = theight;
138 fwin->flags.need_texture_remake = 1;
140 if (wPreferences.new_style) {
141 if (fwin->left_button) {
142 wCoreConfigure(fwin->left_button, 0, 0, bsize, bsize);
145 if (fwin->right_button) {
146 wCoreConfigure(fwin->right_button, width-bsize+1,
147 0, bsize, bsize);
149 } else { /* !new_style */
150 if (fwin->left_button) {
151 wCoreConfigure(fwin->left_button, 3, (theight-bsize)/2,
152 bsize, bsize);
155 if (fwin->right_button) {
156 wCoreConfigure(fwin->right_button, width-bsize-3,
157 (theight-bsize)/2, bsize, bsize);
160 updateTitlebar(fwin);
161 } else {
162 /* we had a titlebar, but now we don't need it anymore */
163 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
164 FREE_PIXMAP(fwin->title_back[i]);
165 if (wPreferences.new_style) {
166 FREE_PIXMAP(fwin->lbutton_back[i]);
167 FREE_PIXMAP(fwin->rbutton_back[i]);
170 if (fwin->left_button)
171 wCoreDestroy(fwin->left_button);
172 fwin->left_button = NULL;
174 if (fwin->right_button)
175 wCoreDestroy(fwin->right_button);
176 fwin->right_button = NULL;
178 wCoreDestroy(fwin->titlebar);
179 fwin->titlebar = NULL;
181 fwin->top_width = 0;
183 } else {
184 /* if we didn't have a titlebar and are being requested for
185 * one, create it */
186 if (flags & WFF_TITLEBAR) {
187 fwin->top_width = theight;
189 fwin->flags.titlebar = 1;
190 fwin->titlebar = wCoreCreate(fwin->core, 0, 0, width+1, theight);
192 if (flags & WFF_LEFT_BUTTON) {
193 fwin->flags.left_button = 1;
194 if (wPreferences.new_style) {
195 fwin->left_button = wCoreCreate(fwin->core, 0, 0,
196 bsize, bsize);
197 if (width < theight*4) {
198 fwin->flags.lbutton_dont_fit = 1;
199 } else {
200 XMapRaised(dpy, fwin->left_button->window);
202 } else {
203 fwin->left_button =
204 wCoreCreate(fwin->titlebar, 3, (theight-bsize)/2,
205 bsize, bsize);
207 XSetWindowBackground(dpy, fwin->left_button->window,
208 scr->widget_texture->normal.pixel);
210 if (width < theight*3) {
211 fwin->flags.lbutton_dont_fit = 1;
212 } else {
213 XMapRaised(dpy, fwin->left_button->window);
219 if (flags & WFF_RIGHT_BUTTON) {
220 fwin->flags.right_button = 1;
221 if (wPreferences.new_style) {
222 fwin->right_button =
223 wCoreCreate(fwin->core, width-bsize+1, 0,
224 bsize, bsize);
225 } else {
226 fwin->right_button =
227 wCoreCreate(fwin->titlebar, width-bsize-3,
228 (theight-bsize)/2, bsize, bsize);
229 XSetWindowBackground(dpy, fwin->right_button->window,
230 scr->widget_texture->normal.pixel);
233 if (width < theight*2) {
234 fwin->flags.rbutton_dont_fit = 1;
235 } else {
236 XMapRaised(dpy, fwin->right_button->window);
240 if (wPreferences.new_style)
241 updateTitlebar(fwin);
243 XMapRaised(dpy, fwin->titlebar->window);
245 fwin->flags.need_texture_remake = 1;
248 checkTitleSize(fwin);
250 if (flags & WFF_RESIZEBAR) {
251 fwin->bottom_width = RESIZEBAR_HEIGHT;
252 } else {
253 fwin->bottom_width = 0;
256 if (flags & WFF_RESIZEBAR) {
257 if (!fwin->resizebar) {
258 fwin->flags.resizebar = 1;
259 fwin->resizebar = wCoreCreate(fwin->core, 0,
260 height + fwin->top_width,
261 width, RESIZEBAR_HEIGHT);
262 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
263 if (width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
264 fwin->resizebar_corner_width = (width - RESIZEBAR_MIN_WIDTH)/2;
265 if (fwin->resizebar_corner_width < 0)
266 fwin->resizebar_corner_width = 0;
269 XMapWindow(dpy, fwin->resizebar->window);
270 XLowerWindow(dpy, fwin->resizebar->window);
272 fwin->flags.need_texture_remake = 1;
273 } else {
274 if (height+fwin->top_width+fwin->bottom_width != fwin->core->height) {
275 wCoreConfigure(fwin->resizebar, 0, height + fwin->top_width,
276 width, RESIZEBAR_HEIGHT);
279 } else {
280 if (fwin->resizebar) {
281 fwin->bottom_width = 0;
282 wCoreDestroy(fwin->resizebar);
283 fwin->resizebar = NULL;
287 if (height + fwin->top_width + fwin->bottom_width != fwin->core->height) {
288 wFrameWindowResize(fwin, width,
289 height + fwin->top_width + fwin->bottom_width);
292 /* setup object descriptors */
294 if (fwin->titlebar) {
295 fwin->titlebar->descriptor.handle_expose = handleExpose;
296 fwin->titlebar->descriptor.parent = fwin;
297 fwin->titlebar->descriptor.parent_type = WCLASS_FRAME;
298 fwin->titlebar->descriptor.handle_mousedown = titlebarMouseDown;
301 if (fwin->resizebar) {
302 fwin->resizebar->descriptor.handle_expose = handleExpose;
303 fwin->resizebar->descriptor.parent = fwin;
304 fwin->resizebar->descriptor.parent_type = WCLASS_FRAME;
305 fwin->resizebar->descriptor.handle_mousedown = resizebarMouseDown;
308 if (fwin->left_button) {
309 fwin->left_button->descriptor.handle_expose = handleButtonExpose;
310 fwin->left_button->descriptor.parent = fwin;
311 fwin->left_button->descriptor.parent_type = WCLASS_FRAME;
312 fwin->left_button->descriptor.handle_mousedown = buttonMouseDown;
315 if (fwin->right_button) {
316 fwin->right_button->descriptor.parent = fwin;
317 fwin->right_button->descriptor.parent_type = WCLASS_FRAME;
318 fwin->right_button->descriptor.handle_expose = handleButtonExpose;
319 fwin->right_button->descriptor.handle_mousedown = buttonMouseDown;
322 checkTitleSize(fwin);
327 void
328 wFrameWindowDestroy(WFrameWindow *fwin)
330 int i;
332 if (fwin->left_button)
333 wCoreDestroy(fwin->left_button);
335 if (fwin->right_button)
336 wCoreDestroy(fwin->right_button);
338 if (fwin->resizebar)
339 wCoreDestroy(fwin->resizebar);
341 if (fwin->titlebar)
342 wCoreDestroy(fwin->titlebar);
344 RemoveFromStackList(fwin->core);
346 wCoreDestroy(fwin->core);
348 if (fwin->title)
349 free(fwin->title);
351 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
352 FREE_PIXMAP(fwin->title_back[i]);
353 if (wPreferences.new_style) {
354 FREE_PIXMAP(fwin->lbutton_back[i]);
355 FREE_PIXMAP(fwin->rbutton_back[i]);
359 free(fwin);
363 void
364 wFrameWindowChangeState(WFrameWindow *fwin, int state)
366 if (fwin->flags.state==state)
367 return;
369 fwin->flags.state = state;
370 fwin->flags.need_texture_change = 1;
372 wFrameWindowPaint(fwin);
376 static void
377 updateTitlebar(WFrameWindow *fwin)
379 int x, w;
380 int theight;
382 theight = (*fwin->font)->height + TITLEBAR_EXTRA_HEIGHT;
384 x = 0;
385 w = fwin->core->width + 1;
387 if (wPreferences.new_style) {
388 if (fwin->flags.hide_left_button || !fwin->left_button
389 || fwin->flags.lbutton_dont_fit) {
390 x = 0;
391 } else {
392 x = fwin->left_button->width;
393 w -= fwin->left_button->width;
397 if (wPreferences.new_style) {
398 if (!fwin->flags.hide_right_button && fwin->right_button
399 && !fwin->flags.rbutton_dont_fit) {
400 w -= fwin->right_button->width;
404 if (wPreferences.new_style || fwin->titlebar->width!=w)
405 fwin->flags.need_texture_remake = 1;
407 wCoreConfigure(fwin->titlebar, x, 0, w, theight);
411 void
412 wFrameWindowHideButton(WFrameWindow *fwin, int flags)
414 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button) {
415 XUnmapWindow(dpy, fwin->right_button->window);
416 fwin->flags.hide_right_button = 1;
419 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button) {
420 XUnmapWindow(dpy, fwin->left_button->window);
421 fwin->flags.hide_left_button = 1;
424 if (fwin->titlebar) {
425 if (wPreferences.new_style) {
426 updateTitlebar(fwin);
427 } else {
428 XClearWindow(dpy, fwin->titlebar->window);
429 wFrameWindowPaint(fwin);
431 checkTitleSize(fwin);
436 void
437 wFrameWindowShowButton(WFrameWindow *fwin, int flags)
439 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button
440 && fwin->flags.hide_right_button) {
442 if (!fwin->flags.rbutton_dont_fit)
443 XMapWindow(dpy, fwin->right_button->window);
445 fwin->flags.hide_right_button = 0;
448 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button
449 && fwin->flags.hide_left_button) {
451 if (!fwin->flags.lbutton_dont_fit)
452 XMapWindow(dpy, fwin->left_button->window);
454 fwin->flags.hide_left_button = 0;
458 if (fwin->titlebar) {
459 if (wPreferences.new_style) {
460 updateTitlebar(fwin);
461 } else {
462 XClearWindow(dpy, fwin->titlebar->window);
463 wFrameWindowPaint(fwin);
465 checkTitleSize(fwin);
470 static void
471 renderTexture(WScreen *scr, WTexture *texture, int width, int height,
472 int bwidth, int bheight, int left, int right,
473 Pixmap *title, Pixmap *lbutton, Pixmap *rbutton)
475 RImage *img;
476 RImage *limg, *rimg, *mimg;
477 int x, w;
479 *title = None;
480 *lbutton = None;
481 *rbutton = None;
483 img = wTextureRenderImage(texture, width, height, WREL_FLAT);
484 if (!img) {
485 wwarning(_("could not render gradient: %s"), RMessageForError(RErrorCode));
486 return;
489 if (wPreferences.new_style) {
490 if (left) {
491 limg = RGetSubImage(img, 0, 0, bwidth, bheight);
492 } else
493 limg = NULL;
495 x = 0;
496 w = img->width;
498 if (limg) {
499 RBevelImage(limg, RBEV_RAISED2);
500 if (!RConvertImage(scr->rcontext, limg, lbutton)) {
501 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
503 x += limg->width;
504 w -= limg->width;
505 RDestroyImage(limg);
508 if (right) {
509 rimg = RGetSubImage(img, width - bwidth, 0, bwidth, bheight);
510 } else
511 rimg = NULL;
513 if (rimg) {
514 RBevelImage(rimg, RBEV_RAISED2);
515 if (!RConvertImage(scr->rcontext, rimg, rbutton)) {
516 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
518 w -= rimg->width;
519 RDestroyImage(rimg);
522 if (w!=width) {
523 mimg = RGetSubImage(img, x, 0, w, img->height);
524 RBevelImage(mimg, RBEV_RAISED2);
526 if (!RConvertImage(scr->rcontext, mimg, title)) {
527 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
529 RDestroyImage(mimg);
530 } else {
531 RBevelImage(img, RBEV_RAISED2);
533 if (!RConvertImage(scr->rcontext, img, title)) {
534 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
537 } else {
538 RBevelImage(img, RBEV_RAISED2);
540 if (!RConvertImage(scr->rcontext, img, title)) {
541 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
545 RDestroyImage(img);
549 static void
550 updateTexture(WFrameWindow *fwin)
552 int i;
553 unsigned long pixel;
555 i = fwin->flags.state;
556 if (fwin->titlebar) {
557 if (fwin->title_texture[i]->any.type!=WTEX_SOLID) {
558 XSetWindowBackgroundPixmap(dpy, fwin->titlebar->window,
559 fwin->title_back[i]);
560 if (wPreferences.new_style) {
561 if (fwin->left_button && fwin->lbutton_back[i])
562 XSetWindowBackgroundPixmap(dpy, fwin->left_button->window,
563 fwin->lbutton_back[i]);
565 if (fwin->right_button && fwin->rbutton_back[i])
566 XSetWindowBackgroundPixmap(dpy, fwin->right_button->window,
567 fwin->rbutton_back[i]);
569 } else {
570 pixel = fwin->title_texture[i]->solid.normal.pixel;
571 XSetWindowBackground(dpy, fwin->titlebar->window, pixel);
572 if (wPreferences.new_style) {
573 if (fwin->left_button)
574 XSetWindowBackground(dpy, fwin->left_button->window,
575 pixel);
576 if (fwin->right_button)
577 XSetWindowBackground(dpy, fwin->right_button->window,
578 pixel);
581 XClearWindow(dpy, fwin->titlebar->window);
583 if (fwin->left_button) {
584 XClearWindow(dpy, fwin->left_button->window);
585 handleButtonExpose(&fwin->left_button->descriptor, NULL);
587 if (fwin->right_button) {
588 XClearWindow(dpy, fwin->right_button->window);
589 handleButtonExpose(&fwin->right_button->descriptor, NULL);
593 if (fwin->resizebar) {
594 XSetWindowBackground(dpy, fwin->resizebar->window,
595 fwin->resizebar_texture[0]->solid.normal.pixel);
596 XClearWindow(dpy, fwin->resizebar->window);
602 static void
603 remakeTexture(WFrameWindow *fwin, int state)
605 Pixmap pmap, lpmap, rpmap;
607 if (fwin->title_texture[state] && fwin->titlebar) {
608 FREE_PIXMAP(fwin->title_back[state]);
609 if (wPreferences.new_style) {
610 FREE_PIXMAP(fwin->lbutton_back[state]);
611 FREE_PIXMAP(fwin->rbutton_back[state]);
614 if (fwin->title_texture[state]->any.type!=WTEX_SOLID) {
615 int left, right;
616 int width;
618 /* eventually surrounded by if new_style */
619 left = fwin->left_button && !fwin->flags.hide_left_button
620 && !fwin->flags.lbutton_dont_fit;
621 right = fwin->right_button && !fwin->flags.hide_right_button
622 && !fwin->flags.rbutton_dont_fit;
624 width = fwin->core->width+1;
626 renderTexture(fwin->screen_ptr, fwin->title_texture[state],
627 width, fwin->titlebar->height,
628 fwin->titlebar->height, fwin->titlebar->height,
629 left, right, &pmap, &lpmap, &rpmap);
631 fwin->title_back[state] = pmap;
632 if (wPreferences.new_style) {
633 fwin->lbutton_back[state] = lpmap;
634 fwin->rbutton_back[state] = rpmap;
641 void
642 wFrameWindowPaint(WFrameWindow *fwin)
645 if (fwin->flags.is_client_window_frame)
646 fwin->flags.justification = wPreferences.title_justification;
648 if (fwin->flags.need_texture_remake) {
649 int i;
651 fwin->flags.need_texture_remake = 0;
652 fwin->flags.need_texture_change = 0;
654 if (fwin->flags.single_texture) {
655 remakeTexture(fwin, 0);
656 updateTexture(fwin);
657 } else {
658 /* first render the texture for the current state... */
659 remakeTexture(fwin, fwin->flags.state);
660 /* ... and paint it */
661 updateTexture(fwin);
663 for (i=0; i < 3; i++) {
664 if (i!=fwin->flags.state)
665 remakeTexture(fwin, i);
670 if (fwin->flags.need_texture_change) {
671 fwin->flags.need_texture_change = 0;
673 updateTexture(fwin);
676 if (fwin->titlebar && !fwin->flags.repaint_only_resizebar
677 && fwin->title_texture[fwin->flags.state]->any.type==WTEX_SOLID) {
678 wDrawBevel(fwin->titlebar->window, fwin->titlebar->width,
679 fwin->titlebar->height,
680 (WTexSolid*)fwin->title_texture[fwin->flags.state],
681 WREL_RAISED);
684 if (fwin->resizebar && !fwin->flags.repaint_only_titlebar) {
685 Window win;
686 int w, h;
687 int cw;
688 GC light_gc, dim_gc;
689 WTexSolid *texture = (WTexSolid*)fwin->resizebar_texture[0];
691 w = fwin->resizebar->width;
692 h = fwin->resizebar->height;
693 cw = fwin->resizebar_corner_width;
694 light_gc = texture->light_gc;
695 dim_gc = texture->dim_gc;
696 win = fwin->resizebar->window;
698 XDrawLine(dpy, win, dim_gc, 0, 0, w, 0);
699 XDrawLine(dpy, win, light_gc, 0, 1, w, 1);
701 XDrawLine(dpy, win, dim_gc, cw, 2, cw, h);
702 XDrawLine(dpy, win, light_gc, cw+1, 2, cw+1, h);
704 XDrawLine(dpy, win, dim_gc, w-cw-2, 2, w-cw-2, h);
705 XDrawLine(dpy, win, light_gc, w-cw-1, 2, w-cw-1, h);
707 #ifdef SHADOW_RESIZEBAR
708 XDrawLine(dpy, win, light_gc, 0, 1, 0, h-1);
709 XDrawLine(dpy, win, dim_gc, w-1, 2, w-1, h-1);
710 XDrawLine(dpy, win, dim_gc, 1, h-1, cw, h-1);
711 XDrawLine(dpy, win, dim_gc, cw+2, h-1, w-cw-2, h-1);
712 XDrawLine(dpy, win, dim_gc, w-cw, h-1, w-1, h-1);
713 #endif /* SHADOW_RESIZEBAR */
717 if (fwin->title && fwin->titlebar && !fwin->flags.repaint_only_resizebar) {
718 int x, w;
719 int lofs = 6, rofs = 6;
720 int titlelen;
721 char *title;
722 int allButtons = 1;
725 if (!wPreferences.new_style) {
726 if (fwin->left_button && !fwin->flags.hide_left_button
727 && !fwin->flags.lbutton_dont_fit)
728 lofs += fwin->left_button->width + 3;
729 else
730 allButtons = 0;
732 if (fwin->right_button && !fwin->flags.hide_right_button
733 && !fwin->flags.rbutton_dont_fit)
734 rofs += fwin->right_button->width + 3;
735 else
736 allButtons = 0;
738 title = ShrinkString(*fwin->font, fwin->title,
739 fwin->titlebar->width - lofs - rofs);
740 titlelen = strlen(title);
741 w = wTextWidth((*fwin->font)->font, title, titlelen);
743 switch (fwin->flags.justification) {
744 case WTJ_LEFT:
745 x = lofs;
746 break;
748 case WTJ_RIGHT:
749 x = fwin->titlebar->width - w - rofs;
750 break;
752 default:
753 if (!allButtons)
754 x = lofs + (fwin->titlebar->width - w - lofs - rofs) / 2;
755 else
756 x = (fwin->titlebar->width - w) / 2;
757 break;
760 XSetForeground(dpy, *fwin->title_gc,
761 fwin->title_pixel[fwin->flags.state]);
763 wDrawString(fwin->titlebar->window, *fwin->font,
764 *fwin->title_gc, x,
765 (*fwin->font)->y + TITLEBAR_EXTRA_HEIGHT/2, title,
766 titlelen);
768 #ifdef TITLE_TEXT_SHADOW
769 if(wPreferences.title_shadow){
770 int shadowx,shadowy;
771 XSetForeground(dpy, *fwin->title_gc,
772 fwin->title_pixel[fwin->flags.state+3]);
773 for(shadowx=0;shadowx<TITLE_TEXT_SHADOW_WIDTH;shadowx++)
774 for(shadowy=0;shadowy<TITLE_TEXT_SHADOW_HEIGHT;shadowy++)
775 wDrawString(fwin->titlebar->window, *fwin->font,
776 *fwin->title_gc,
777 x + shadowx + TITLE_TEXT_SHADOW_X_OFFSET,
778 (*fwin->font)->y + TITLEBAR_EXTRA_HEIGHT/2
779 + shadowy + TITLE_TEXT_SHADOW_Y_OFFSET, title,
780 titlelen);
782 #endif /* TITLE_TEXT_SHADOW */
784 free(title);
789 static void
790 reconfigure(WFrameWindow *fwin, int x, int y, int width, int height,
791 Bool dontMove)
793 int k = (wPreferences.new_style ? 4 : 3);
794 int resizedHorizontally = 0;
796 if (dontMove)
797 XResizeWindow(dpy, fwin->core->window, width, height);
798 else
799 XMoveResizeWindow(dpy, fwin->core->window, x, y, width, height);
802 if (fwin->core->height != height && fwin->resizebar)
803 XMoveWindow(dpy, fwin->resizebar->window, 0,
804 height - fwin->resizebar->height);
806 if (fwin->core->width != width) {
807 fwin->flags.need_texture_remake = 1;
808 resizedHorizontally = 1;
811 fwin->core->width = width;
812 fwin->core->height = height;
814 if (fwin->titlebar && resizedHorizontally) {
815 /* Check if the titlebar is wide enough to hold the buttons.
816 * Temporarily remove them if can't
818 if (fwin->left_button) {
819 if (width < fwin->top_width*k && !fwin->flags.lbutton_dont_fit) {
821 if (!fwin->flags.hide_left_button) {
822 XUnmapWindow(dpy, fwin->left_button->window);
824 fwin->flags.lbutton_dont_fit = 1;
825 } else if (width >= fwin->top_width*k && fwin->flags.lbutton_dont_fit) {
827 if (!fwin->flags.hide_left_button) {
828 XMapWindow(dpy, fwin->left_button->window);
830 fwin->flags.lbutton_dont_fit = 0;
834 if (fwin->right_button) {
835 if (width < fwin->top_width*2 && !fwin->flags.rbutton_dont_fit) {
837 if (!fwin->flags.hide_right_button) {
838 XUnmapWindow(dpy, fwin->right_button->window);
840 fwin->flags.rbutton_dont_fit = 1;
841 } else if (width >= fwin->top_width*2 && fwin->flags.rbutton_dont_fit) {
843 if (!fwin->flags.hide_right_button) {
844 XMapWindow(dpy, fwin->right_button->window);
846 fwin->flags.rbutton_dont_fit = 0;
850 if (wPreferences.new_style) {
851 if (fwin->right_button)
852 XMoveWindow(dpy, fwin->right_button->window,
853 width - fwin->right_button->width + 1, 0);
854 } else {
855 if (fwin->right_button)
856 XMoveWindow(dpy, fwin->right_button->window,
857 width - fwin->right_button->width - 3,
858 (fwin->titlebar->height - fwin->right_button->height)/2);
860 updateTitlebar(fwin);
861 checkTitleSize(fwin);
864 if (fwin->resizebar) {
865 wCoreConfigure(fwin->resizebar, 0,
866 fwin->core->height - fwin->resizebar->height,
867 fwin->core->width, fwin->resizebar->height);
869 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
870 if (fwin->core->width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
871 fwin->resizebar_corner_width = fwin->core->width/2;
876 void
877 wFrameWindowConfigure(WFrameWindow *fwin, int x, int y, int width, int height)
879 reconfigure(fwin, x, y, width, height, False);
882 void
883 wFrameWindowResize(WFrameWindow *fwin, int width, int height)
885 reconfigure(fwin, 0, 0, width, height, True);
890 int
891 wFrameWindowChangeTitle(WFrameWindow *fwin, char *new_title)
893 /* check if the title is the same as before */
894 if (fwin->title) {
895 if (new_title && (strcmp(fwin->title, new_title) == 0)) {
896 return 0;
898 } else {
899 if (!new_title)
900 return 0;
903 if (fwin->title)
904 free(fwin->title);
906 fwin->title = wstrdup(new_title);
908 if (fwin->titlebar) {
909 XClearWindow(dpy, fwin->titlebar->window);
911 wFrameWindowPaint(fwin);
913 checkTitleSize(fwin);
915 return 1;
919 #ifdef OLWM_HINTS
920 void
921 wFrameWindowUpdatePushButton(WFrameWindow *fwin, Bool pushed)
923 fwin->flags.right_button_pushed_in = pushed;
925 paintButton(fwin->right_button, fwin->title_texture[fwin->flags.state],
926 fwin->title_pixel[fwin->flags.state],
927 fwin->rbutton_image, pushed);
929 #endif /* OLWM_HINTS */
933 /*********************************************************************/
935 static void
936 handleExpose(WObjDescriptor *desc, XEvent *event)
938 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
941 if (fwin->titlebar && fwin->titlebar->window == event->xexpose.window)
942 fwin->flags.repaint_only_titlebar = 1;
943 if (fwin->resizebar && fwin->resizebar->window == event->xexpose.window)
944 fwin->flags.repaint_only_resizebar = 1;
945 wFrameWindowPaint(fwin);
946 fwin->flags.repaint_only_titlebar = 0;
947 fwin->flags.repaint_only_resizebar = 0;
951 static void
952 checkTitleSize(WFrameWindow *fwin)
954 int width;
956 if (!fwin->title) {
957 fwin->flags.incomplete_title = 0;
958 return;
961 if (!fwin->titlebar) {
962 fwin->flags.incomplete_title = 1;
963 return;
964 } else {
965 width = fwin->titlebar->width - 6 - 6;
968 if (!wPreferences.new_style) {
969 if (fwin->left_button && !fwin->flags.hide_left_button
970 && !fwin->flags.lbutton_dont_fit)
971 width -= fwin->left_button->width + 3;
973 if (fwin->right_button && !fwin->flags.hide_right_button
974 && !fwin->flags.rbutton_dont_fit)
975 width -= fwin->right_button->width + 3;
977 if (wTextWidth((*fwin->font)->font, fwin->title,
978 strlen(fwin->title)) > width) {
979 fwin->flags.incomplete_title = 1;
980 } else {
981 fwin->flags.incomplete_title = 0;
986 static void
987 paintButton(WCoreWindow *button, WTexture *texture, unsigned long color,
988 WPixmap *image, int pushed)
990 WScreen *scr = button->screen_ptr;
991 GC copy_gc = scr->copy_gc;
992 int x=0, y=0, d=0;
993 int left=0, width=0;
995 /* setup stuff according to the state */
996 if (pushed) {
997 if (image) {
998 if (image->width>=image->height*2) {
999 /* the image contains 2 pictures: the second is for the
1000 * pushed state */
1001 width = image->width/2;
1002 left = image->width/2;
1003 } else {
1004 width = image->width;
1007 XSetClipMask(dpy, copy_gc, None);
1008 XSetForeground(dpy, copy_gc, scr->white_pixel);
1009 d=1;
1010 if (wPreferences.new_style) {
1011 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1012 button->width-1, button->height-1);
1013 XSetForeground(dpy, copy_gc, scr->black_pixel);
1014 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1015 button->width-1, button->height-1);
1016 } else {
1017 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1018 button->width, button->height);
1019 XSetForeground(dpy, copy_gc, scr->black_pixel);
1020 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1021 button->width, button->height);
1023 } else {
1024 XClearWindow(dpy, button->window);
1026 if (image) {
1027 if (image->width>=image->height*2)
1028 width = image->width/2;
1029 else
1030 width = image->width;
1032 d=0;
1034 if (wPreferences.new_style) {
1035 if (texture->any.type==WTEX_SOLID || pushed) {
1036 wDrawBevel(button->window, button->width, button->height,
1037 (WTexSolid*)texture, WREL_RAISED);
1039 } else {
1040 wDrawBevel(button->window, button->width, button->height,
1041 scr->widget_texture, WREL_RAISED);
1045 if (image) {
1046 /* display image */
1047 XSetClipMask(dpy, copy_gc, image->mask);
1048 x = (button->width - width)/2 + d;
1049 y = (button->height - image->height)/2 + d;
1050 XSetClipOrigin(dpy, copy_gc, x-left, y);
1051 if (!wPreferences.new_style) {
1052 XSetForeground(dpy, copy_gc, scr->black_pixel);
1053 if (!pushed) {
1054 if (image->depth==1)
1055 XCopyPlane(dpy, image->image, button->window, copy_gc,
1056 left, 0, width, image->height, x, y, 1);
1057 else
1058 XCopyArea(dpy, image->image, button->window, copy_gc,
1059 left, 0, width, image->height, x, y);
1060 } else {
1061 XSetForeground(dpy, copy_gc, scr->dark_pixel);
1062 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1063 button->width, button->height);
1065 } else {
1066 if (pushed) {
1067 XSetForeground(dpy, copy_gc, scr->black_pixel);
1068 } else {
1069 XSetForeground(dpy, copy_gc, color);
1070 XSetBackground(dpy, copy_gc, texture->any.color.pixel);
1072 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1073 button->width, button->height);
1079 static void
1080 handleButtonExpose(WObjDescriptor *desc, XEvent *event)
1082 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
1083 WCoreWindow *button = (WCoreWindow*)desc->self;
1085 if (button == fwin->left_button) {
1086 paintButton(button, fwin->title_texture[fwin->flags.state],
1087 fwin->title_pixel[fwin->flags.state],
1088 fwin->lbutton_image, False);
1089 } else {
1090 Bool pushed = False;
1092 #ifdef OLWM_HINTS
1093 if (fwin->flags.right_button_pushed_in)
1094 pushed = True;
1095 #endif
1096 /* emulate the olwm pushpin in the "out" state */
1097 paintButton(button, fwin->title_texture[fwin->flags.state],
1098 fwin->title_pixel[fwin->flags.state],
1099 fwin->rbutton_image, pushed);
1104 static void
1105 titlebarMouseDown(WObjDescriptor *desc, XEvent *event)
1107 WFrameWindow *fwin = desc->parent;
1108 WCoreWindow *titlebar = desc->self;
1110 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1111 if (fwin->on_dblclick_titlebar)
1112 (*fwin->on_dblclick_titlebar)(titlebar, fwin->child, event);
1113 } else {
1114 if (fwin->on_mousedown_titlebar)
1115 (*fwin->on_mousedown_titlebar)(titlebar, fwin->child, event);
1120 static void
1121 resizebarMouseDown(WObjDescriptor *desc, XEvent *event)
1123 WFrameWindow *fwin = desc->parent;
1124 WCoreWindow *resizebar = desc->self;
1126 if (fwin->on_mousedown_resizebar)
1127 (*fwin->on_mousedown_resizebar)(resizebar, fwin->child, event);
1131 static void
1132 buttonMouseDown(WObjDescriptor *desc, XEvent *event)
1134 WFrameWindow *fwin = desc->parent;
1135 WCoreWindow *button = desc->self;
1136 WPixmap *image;
1137 XEvent ev;
1138 int done=0, execute=1;
1139 WTexture *texture;
1140 unsigned long pixel;
1141 int clickButton = event->xbutton.button;
1143 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1144 if (button == fwin->right_button && fwin->on_dblclick_right) {
1145 (*fwin->on_dblclick_right)(button, fwin->child, event);
1147 return;
1150 if (button == fwin->left_button) {
1151 image = fwin->lbutton_image;
1152 } else {
1153 image = fwin->rbutton_image;
1156 pixel = fwin->title_pixel[fwin->flags.state];
1157 texture = fwin->title_texture[fwin->flags.state];
1158 paintButton(button, texture, pixel, image, True);
1160 while (!done) {
1161 WMMaskEvent(dpy, LeaveWindowMask|EnterWindowMask|ButtonReleaseMask
1162 |ButtonPressMask|ExposureMask, &ev);
1163 switch (ev.type) {
1164 case LeaveNotify:
1165 execute = 0;
1166 paintButton(button, texture, pixel, image, False);
1167 break;
1169 case EnterNotify:
1170 execute = 1;
1171 paintButton(button, texture, pixel, image, True);
1172 break;
1174 case ButtonPress:
1175 break;
1177 case ButtonRelease:
1178 if (ev.xbutton.button == clickButton)
1179 done = 1;
1180 break;
1182 default:
1183 WMHandleEvent(&ev);
1186 paintButton(button, texture, pixel, image, False);
1188 if (execute) {
1189 if (button == fwin->left_button) {
1190 if (fwin->on_click_left)
1191 (*fwin->on_click_left)(button, fwin->child, &ev);
1192 } else if (button == fwin->right_button) {
1193 if (fwin->on_click_right)
1194 (*fwin->on_click_right)(button, fwin->child, &ev);