JWM Source Documentation
popup.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "popup.h"
12 #include "main.h"
13 #include "color.h"
14 #include "font.h"
15 #include "screen.h"
16 #include "cursor.h"
17 #include "timing.h"
18 #include "misc.h"
19 #include "settings.h"
20 #include "event.h"
21 #include "hint.h"
22 
23 typedef struct PopupType {
24  int x, y; /* The coordinates of the upper-left corner of the popup. */
25  int mx, my; /* The mouse position when the popup was created. */
26  Window mw;
27  int width, height;
28  char *text; /* The raw popup text. */
29  char *lines; /* Popup text split into NUL-separated lines. */
30  int lineCount; /* The number of lines. */
31  Window window;
32  Pixmap pmap;
33 } PopupType;
34 
36 
37 static void MeasurePopupText();
38 static void SignalPopup(const TimeType *now, int x, int y, Window w,
39  void *data);
40 
42 void StartupPopup(void)
43 {
44  popup.text = NULL;
45  popup.window = None;
46  RegisterCallback(100, SignalPopup, NULL);
47 }
48 
50 void ShutdownPopup(void)
51 {
53  if(popup.text) {
54  Release(popup.text);
55  Release(popup.lines);
56  popup.text = NULL;
57  }
58  if(popup.window != None) {
60  JXFreePixmap(display, popup.pmap);
61  popup.window = None;
62  }
63 }
64 
67 {
68  const int textHeight = GetStringHeight(FONT_POPUP) + 1;
69  char *ptr;
70 
71  popup.lines = CopyString(popup.text);
72  ptr = popup.lines;
73 
74  popup.width = 0;
75  popup.height = 1;
76  popup.lineCount = 0;
77  for(;;) {
78  char *end = strchr(ptr, '\n');
79  int currentWidth;
80  if(end) {
81  *end = 0;
82  }
83  currentWidth = GetStringWidth(FONT_POPUP, ptr) + 9;
84  popup.width = Max(popup.width, currentWidth);
85  popup.height += textHeight;
86  popup.lineCount += 1;
87  if(end) {
88  ptr = end + 1;
89  } else {
90  break;
91  }
92  }
93 }
94 
96 void ShowPopup(int x, int y, const char *text,
97  const PopupMaskType context)
98 {
99  const ScreenType *sp;
100  char *ptr;
101  int textHeight;
102  int i;
103 
104  if(!(settings.popupMask & context)) {
105  return;
106  }
107 
108  if(popup.text) {
109  if(x == popup.x && y == popup.y && !strcmp(popup.text, text)) {
110  /* This popup is already shown. */
111  return;
112  }
113  Release(popup.text);
114  Release(popup.lines);
115  popup.text = NULL;
116  }
117 
118  if(text[0] == 0) {
119  return;
120  }
121 
122  GetMousePosition(&popup.mx, &popup.my, &popup.mw);
123  popup.text = CopyString(text);
124 
126  sp = GetCurrentScreen(x, y);
127  if(popup.width > sp->width) {
128  popup.width = sp->width;
129  }
130 
131  popup.x = x;
132  if(y + 2 * popup.height + 2 >= sp->height) {
133  popup.y = y - popup.height - 2;
134  } else {
135  popup.y = y + GetStringHeight(FONT_POPUP) + 2;
136  }
137 
138  if(popup.width + popup.x > sp->x + sp->width) {
139  popup.x = sp->x + sp->width - popup.width - 2;
140  }
141  if(popup.height + popup.y > sp->y + sp->height) {
142  popup.y = sp->y + sp->height - popup.height - 2;
143  }
144  if(popup.x < 2) {
145  popup.x = 2;
146  }
147  if(popup.y < 2) {
148  popup.y = 2;
149  }
150 
151  if(popup.window == None) {
152 
153  XSetWindowAttributes attr;
154  unsigned long attrMask = 0;
155 
156  attrMask |= CWEventMask;
157  attr.event_mask = ExposureMask
158  | PointerMotionMask | PointerMotionHintMask;
159 
160  attrMask |= CWSaveUnder;
161  attr.save_under = True;
162 
163  attrMask |= CWDontPropagate;
164  attr.do_not_propagate_mask = PointerMotionMask
165  | ButtonPressMask
166  | ButtonReleaseMask;
167 
168  popup.window = JXCreateWindow(display, rootWindow, popup.x, popup.y,
169  popup.width, popup.height, 0,
170  CopyFromParent, InputOutput,
171  CopyFromParent, attrMask, &attr);
174  JXMapRaised(display, popup.window);
175 
176  } else {
177 
178  JXMoveResizeWindow(display, popup.window, popup.x, popup.y,
179  popup.width, popup.height);
180  JXFreePixmap(display, popup.pmap);
181 
182  }
183 
184  popup.pmap = JXCreatePixmap(display, popup.window,
185  popup.width, popup.height,
186  rootDepth);
187 
189  JXFillRectangle(display, popup.pmap, rootGC, 0, 0,
190  popup.width - 1, popup.height - 1);
192  JXDrawRectangle(display, popup.pmap, rootGC, 0, 0,
193  popup.width - 1, popup.height - 1);
194  ptr = popup.lines;
195  textHeight = GetStringHeight(FONT_POPUP) + 1;
196  for(i = 0; i < popup.lineCount; i++) {
198  textHeight * i + 1, popup.width, ptr);
199  ptr += strlen(ptr) + 1;
200  }
201  JXCopyArea(display, popup.pmap, popup.window, rootGC,
202  0, 0, popup.width, popup.height, 0, 0);
203 
204 }
205 
207 void SignalPopup(const TimeType *now, int x, int y, Window w, void *data)
208 {
209  if(popup.window != None) {
210  if(popup.mw != w ||
211  abs(popup.mx - x) > 0 || abs(popup.my - y) > 0) {
213  JXFreePixmap(display, popup.pmap);
214  popup.window = None;
215  }
216  }
217 }
218 
220 char ProcessPopupEvent(const XEvent *event)
221 {
222  if(popup.window != None && event->xany.window == popup.window) {
223  if(event->type == Expose && event->xexpose.count == 0) {
224  JXCopyArea(display, popup.pmap, popup.window, rootGC,
225  0, 0, popup.width, popup.height, 0, 0);
226  } else if(event->type == MotionNotify) {
228  JXFreePixmap(display, popup.pmap);
229  popup.window = None;
230  }
231  return 1;
232  }
233  return 0;
234 }

joewing.net / Projects / JWM