2
// -------------------------------------------
4
// $Date: 2003/06/23 14:47:22 $
5
// $Revision: 1.1.1.1 $
6
// $Source: /cvsroot/miwm/miwm/miwm/disp.cc,v $
7
// $Id: disp.cc,v 1.1.1.1 2003/06/23 14:47:22 bwise837 Exp $
8
// $RCSfile: disp.cc,v $
9
// -------------------------------------------
10
// Copyright by Ben Paul Wise.
11
// -------------------------------------------
12
// This program is free software; you can redistribute it and/or modify
13
// it under the terms of the GNU General Public License as published by
14
// the Free Software Foundation; either version 2 of the License, or
15
// (at your option) any later version.
17
// This program is distributed in the hope that it will be useful,
18
// but WITHOUT ANY WARRANTY; without even the implied warranty of
19
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
// GNU General Public License for more details.
22
// You should have received a copy of the GNU General Public License
23
// along with this program; if not, write to the Free Software
24
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
// -------------------------------------------
29
#include <X11/Xutil.h>
31
#include <X11/Xresource.h>
32
#include <X11/Xatom.h>
41
// Dispatcher for main event loop.
43
typedef struct Disp Disp;
46
void (*handler)(XEvent *);
49
void logXEvents (XEvent *ev);
51
// comment these out to limit functionality
52
void buttonpress(XEvent *);
53
void buttonrelease(XEvent *);
54
void motionnotify(XEvent *);
56
void expose(XEvent *);
57
void maprequest(XEvent *);
58
void configurereq(XEvent *);
60
void destroy(XEvent *);
61
void clientmessage(XEvent *);
62
void colormap(XEvent *);
63
void property(XEvent *);
64
void reparent(XEvent *);
66
void expose(XEvent *);
69
void keypress(XEvent *);
70
void keyrelease(XEvent *);
72
// void motionnotifyMoving(XEvent*);
73
// void motionnotifyResizing(XEvent*);
74
void reshaping_motionnotify(XEvent*);
79
{MapRequest, maprequest},
80
{ConfigureRequest, configurereq},
82
{DestroyNotify, destroy},
83
{ClientMessage, clientmessage},
84
{ColormapNotify, colormap},
85
{PropertyNotify, property},
86
{ReparentNotify, reparent},
89
// comment these out to limit functionality
90
{MotionNotify, motionnotify},
91
{ButtonPress, buttonpress},
92
{ButtonRelease, buttonrelease},
96
{CirculateRequest, 0},
103
{SelectionNotify, 0},
104
{SelectionRequest, 0},
113
#ifdef MIWM_TRACE_ALL_X_EVENTS
118
for (p = disps; p < disps + sizeof disps / sizeof disps[0]; p++) {
119
if (p->type == ev->type) {
121
p->handler(ev); // purify says this is a leak?!
127
fprintf(stderr, "%s: unknown event %d\n", argv0, ev->type);
131
logXEvents (XEvent *ev) {
136
cout << "ButtonPress"; break;
138
cout << "ButtonRelease"; break;
140
cout << "MapRequest"; break;
141
case ConfigureRequest:
142
cout << "ConfigureRequest"; break;
144
cout << "UnmapNotify"; break;
146
cout << "DestroyNotify"; break;
148
cout << "ClientMessage"; break;
150
cout << "ColormapNotify"; break;
152
cout << "PropertyNotify"; break;
154
cout << "ReparentNotify"; break;
156
cout << "EnterNotify"; break;
158
cout << "LeaveNotify"; break;
160
// too frequent to post, usually!
161
cout << "Expose"; break;
163
// too frequent to post, usually!
164
cout << "MotionNotify"; break;
166
case CirculateRequest:
167
cout << "CirculateRequest"; break;
168
case ConfigureNotify:
169
cout << "ConfigureNotify"; break;
171
cout << "CreateNotify"; break;
173
cout << "GravityNotify"; break;
175
cout << "MapNotify"; break;
177
cout << "MappingNotify"; break;
179
cout << "SelectionClear"; break;
180
case SelectionNotify:
181
cout << "SelectionNotify"; break;
182
case SelectionRequest:
183
cout << "SelectionRequest"; break;
185
cout << "unknown event type " << ev->type;
187
cout << ">\n" << flush;
194
Window w; // Window the expose event is for.
196
if (ev->xexpose.count != 0) return;
198
w = ev->xexpose.window;
200
// We don't draw on the root window (yet)
201
if (w == root) return;
203
// Decide what needs redrawing: window frame or menu?
205
switch (theWM->mode) {
208
theWM->menu->expose();
212
theWM->positionExpose();
225
// cout << "Exposing Client " << c->clientID << endl << flush;
226
// XSync(dpy, False);
228
theWM->drawClientBorder(c, c == current);
235
WindowManager::titleHeightc(Client *c)
237
if (c->accepts_focus && c->name)
238
return titleHeight();
249
keyrelease(XEvent *) {
253
// -------------------------------------------
254
// these are the big three: press button, move, release
255
// -------------------------------------------
257
// this should be a dispatch table on (location, button, modifiers)
258
// pointing at fn(Client*, XEvent*)
260
buttonpress(XEvent *ev) {
262
XButtonEvent *e = &ev->xbutton;
265
if (theWM->mode != wmReady) return;
267
c = getClient(e->window);
269
// =================================================
270
// FRAME button presses
271
// =================================================
273
if (c && (e->window == c->parent)) { // click on frame around a client.
274
// cout << "Frame button press"<<endl;
278
case Button3: // hide client
279
if (e->state & ControlMask) {
280
if (theWM->mouseInDeadlyBox(current)) {
281
theWM->mode = wmKilling;
282
theWM->startKillingClient(e, c);
284
else { // raise client ops menu
285
theWM->mode = wmMenuing;
286
theWM->setClientOpsMenu();
287
theWM->menu->startMenuing(e);
295
case Button2: // start moving client on screen or between WS
296
if (e->state & ControlMask) {
298
theWM->mode = wmMenuing;
300
if (e->state & ShiftMask) {
301
// follow client to new WS
302
theWM->followClientToWS = 1;
304
theWM->whichMenu = sendCtoWSMenu;
305
theWM->menu->startMenuing(e);
308
theWM->mode = wmMoving;
309
theWM->startMovingClient(ev, c);
314
if (e->state & ControlMask)
315
theWM->backClient(c);
317
theWM->mode = wmResizing;
318
theWM->startResizingClient(e, c);
325
} // end of clicks on border
327
// =================================================
328
// ROOT button presses
329
// =================================================
330
if (e->window == root) {
331
// cout << "Root button press"<<endl;
332
// XChangeActivePointerGrab(dpy,
333
// theWM->moving_event_mask,
334
// root_cursor, CurrentTime);
338
// cout << "Trying to raise topclient = " << theWM->workSpace->topClient << endl << flush;
339
// if (theWM->workSpace->topClient != NULL) {
340
// cout << " named " << choose_label(theWM->workSpace->topClient) << endl;
341
// theWM->raiseClient(theWM->workSpace->topClient );
342
// theWM->focusOn(theWM->workSpace->topClient);
344
// raise command menu
345
theWM->mode = wmMenuing;
346
theWM->setShellCmdMenu();
347
theWM->menu->startMenuing(e);
351
// if ctrl-Button2, skip
352
if (e->state & ControlMask) {
353
if (e->state & ShiftMask)
360
else { // raise WS menu
361
theWM->mode = wmMenuing;
363
theWM->whichMenu = changeWSMenu;
364
theWM->menu->startMenuing(e);
369
if (e->state & ControlMask) {
370
theWM->mode = wmMenuing;
371
theWM->setWMOpsMenu();
372
theWM->menu->startMenuing(e);
375
// raise hidden client menu
376
theWM->mode = wmMenuing;
377
theWM->setHiddenClientMenu();
378
theWM->menu->startMenuing(e);
385
} // end of root button clicks
390
motionnotify(XEvent *ev) {
391
switch (theWM->mode) {
394
theWM->motionNotifyResizing();
398
theWM->motionNotifyKilling();
402
// cout << "Moving" << endl << flush;
403
theWM->motionNotifyMoving();
407
theWM->menu->motionNotify(ev);
421
buttonrelease(XEvent *ev) {
422
// cout << "Button release"<<endl;
423
switch (theWM->mode) {
426
// cout << "Stop menuing" << endl << flush;
428
theWM->menu->buttonRelease();
432
theWM->buttonReleaseResizing();
436
theWM->buttonReleaseMoving();
440
theWM->buttonReleaseKilling();
447
theWM->mode = wmReady;
451
// -------------------------------------------
454
void maprequest(XEvent *ev) {
456
XMapRequestEvent *e = &ev->xmaprequest;
458
c = getClient(e->window);
460
if (c == 0 || c->window != e->window) {
461
cout << "Adding client in maprequest" << endl << flush;
462
c = addClient(e->window);
471
if (c->parent == root) {
472
theWM->manageClient(c);
475
XReparentWindow(dpy, c->window, c->parent, border, border);
476
XAddToSaveSet(dpy, c->window);
479
XMapRaised(dpy, c->parent);
480
XMapWindow(dpy, c->window);
482
setClientState(c, NormalState);
491
XUnmapEvent *e = &ev->xunmap;
493
c = getClient(e->window);
496
// In the description of the ReparentWindow request we read: "If the window
497
// is mapped, an UnmapWindow request is performed automatically first". This
498
// might seem stupid, but it's the way it is. While a reparenting is pending
499
// we ignore UnmapWindow requests.
501
if (c->internal_state == IPendingReparenting) {
502
c->internal_state = INormal;
506
if (c->state == IconicState) {
508
//Is this a hidden window disappearing? If not, then we
509
//are not interested because it's an unmap request caused
510
//by our hiding a window.
513
unhidec(c, 0); // It's a hidden window disappearing.
515
// This is a plain unmap, so withdraw the window.
519
c->internal_state = INormal;
523
configurereq(XEvent *ev)
527
XConfigureRequestEvent *e = &ev->xconfigurerequest;
529
c = getClient(e->window);
531
// ICCCM section 4.1.5 says that the x and y coordinates here
532
//will have been "adjusted for the border width".
533
// NOTE: this may not be the only place to bear this in mind.
534
if (e->value_mask & CWBorderWidth) {
535
e->x -= e->border_width;
536
e->y -= e->border_width;
538
// The ICCCM also says that clients should always set the
539
//border width in a configure request. As usual, many don't.
544
if (e->value_mask & CWX)
546
if (e->value_mask & CWY)
548
if (e->value_mask & CWWidth)
549
c->size.width = e->width + 2 * border;
550
if (e->value_mask & CWHeight)
551
c->size.height = e->height + 2 * border;
552
if (e->value_mask & CWBorderWidth)
553
c->border = e->border_width;
555
if (c->parent != root && c->window == e->window) {
558
wc.width = c->size.width;
559
wc.height = c->size.height;
561
wc.y -= titleHeight();
562
wc.height += titleHeight();
565
wc.sibling = e->above;
566
wc.stack_mode = e->detail;
567
XConfigureWindow(dpy, e->parent, e->value_mask, &wc);
568
sendConfigureNotify(c);
571
if (c && (c->internal_state == INormal)) {
579
wc.height = e->height;
581
wc.sibling = e->above;
582
wc.stack_mode = e->detail;
583
e->value_mask |= CWBorderWidth;
586
wc.y += titleHeight();
588
XConfigureWindow(dpy, e->window, e->value_mask, &wc);
595
Window w = ev->xdestroywindow.window;
605
clientmessage(XEvent *ev)
608
XClientMessageEvent *e = &ev->xclient;
610
if (e->message_type == wm_change_state) {
611
c = getClient(e->window);
613
if (e->format == 32 && e->data.l[0] == IconicState && normal(c))
623
// XColormapEvent *e = &ev->xcolormap;
625
// I commented this out as the 'new' keyword appeared to be confusing g++
627
// c = getClient(e->window);
629
// c->cmap = e->colormap;
633
// Client_ColorMap(ev);
639
property(XEvent * ev) {
641
XPropertyEvent * e = &ev->xproperty;
643
c = getClient(e->window);
650
setactive(c, c == current, 0L);
652
case XA_WM_TRANSIENT_FOR:
655
case XA_WM_NORMAL_HINTS:
659
if (e->atom == wm_colormaps) {
671
XReparentEvent *e = &ev->xreparent;
673
if (e->event != root || e->override_redirect || e->parent == root)
676
c = getClient(e->window);
677
if (c != 0 && (c->parent == root || withdrawn(c)))
683
// do nothing for now
690
if (wmReady ==theWM->mode) {
692
// it is possible for a client to die when you are
693
// doing a menu operation (send to WS, toggle sticky, etc.)
694
// in that case, we do NOT want to apply the operation
695
// to the next client, so I allow change of focus
696
// only if we are in wmReady mode.
697
c = getClient(ev->xcrossing.window);
701
// if (c != current && !c->hidden) {
702
// // Take focus away from current holder.
704
// setactive(current, 0, 0L);
706
// // Give focus to new holder.
708
// setactive(current, 1, ev->xcrossing.time);
711
// cout << "Entering Client " << c->clientID << endl << flush;
712
if (1 == theWM->insideClientP(c))
719
WindowManager::focusOn(Client* c) {
720
if (c == NULL) { // de focus
722
setactive(current,0,0L);
727
if (c != current && !c->hidden) {
728
// Take focus away from current holder.
730
setactive(current, 0, 0L);
732
if (1 == raiseOnFocusP)
735
// Give focus to new holder.
737
setactive(current, 1, CurrentTime);
742
// motionnotifyMoving(XEvent*ev) {
743
// // reshaping_motionnotify(ev);
745
// // XChangeActivePointerGrab(dpy, theWM->moving_event_mask,
746
// // root_cursor, CurrentTime);
748
// cout << "motionnotifyMoving"<<endl << flush;
755
// theWM->drawClientOutline(current); // erase old one
769
// reshaping_motionnotify(XEvent*) // parameter ev was unused
771
// int nx; /* New x. */
772
// int ny; /* New y. */
773
// int ox; /* Original x. */
774
// int oy; /* Original y. */
775
// int ndx; /* New width. */
776
// int ndy; /* New height. */
777
// int odx; /* Original width. */
778
// int ody; /* Original height. */
783
// if ((theWM->mode != wmResizing) || (mode != wmMoving))
786
// yTitleAdjust = (current->accepts_focus && current->name) ? titleHeight() : 0;
788
// getMouse(&pointer_x, &pointer_y);
790
// if (interacting_edge != ENone) {
791
// nx = ox = current->size.x;
792
// ny = oy = current->size.y;
793
// ndx = odx = current->size.width;
794
// ndy = ody = current->size.height;
796
// Client_SizeFeedback();
799
// switch (interacting_edge) {
803
// ndy += (current->size.y - pointer_y);
808
// case EBottomRight:
809
// ndy = pointer_y - current->size.y;
815
// switch (interacting_edge) {
818
// case EBottomRight:
819
// ndx = pointer_x - current->size.x;
824
// ndx += (current->size.x - pointer_x);
830
// adjustClientBorder(current, interacting_edge, &nx, &ny, &ndx, &ndy);
831
// XMoveResizeWindow(dpy, current->parent,
832
// current->size.x, current->size.y - yTitleAdjust,
833
// current->size.width, current->size.height + yTitleAdjust);
834
// if (current->size.width == odx && current->size.height == ody) {
835
// if (current->size.x != ox || current->size.y != oy)
836
// sendConfigureNotify(current);
838
// XMoveResizeWindow(dpy, current->window, border, border + yTitleAdjust,
839
// current->size.width - 2 * border, current->size.height - 2 * border);
840
// } // edge of reshaping section, edge != ENone
842
// { // bodily move the client
843
// nx = pointer_x + start_x;
844
// ny = pointer_y + start_y;
846
// adjustClientBorder(current, interacting_edge, &nx, &ny, 0, 0);
847
// XMoveWindow(dpy, current->parent,
848
// current->size.x, current->size.y - yTitleAdjust);
849
// sendConfigureNotify(current);
854
// -------------------------------------------
856
// -------------------------------------------