1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from constant import EDGE_DICT
24 from draw import draw_window_shadow, draw_window_frame
25 from skin_config import skin_config
26 from theme import ui_theme
27 import cairo
28 import gobject
29 import gtk
30 from utils import (cairo_state, propagate_expose, set_cursor,
31 resize_window, get_event_root_coords,
32 enable_shadow, alpha_color_hex_to_cairo,
33 is_double_click, move_window)
34
36 """
37 The Window class is a subclass of gtk.Window. It adds some features that deepin-ui have to gtk.Window.
38
39 @undocumented: get_cursor_type
40 @undocumented: expose_window_background
41 @undocumented: expose_window_shadow
42 @undocumented: expose_window_frame
43 @undocumented: shape_window_frame
44 @undocumented: motion_notify
45 @undocumented: double_click_window
46 @undocumented: monitor_window_state
47 """
48 - def __init__(self,
49 enable_resize=False,
50 shadow_radius=6,
51 window_type=gtk.WINDOW_TOPLEVEL,
52 shadow_visible=True):
53 """
54 Initialise the Window class.
55
56 @param enable_resize: If True, the window will be set resizable. By default, it's False.
57 @param shadow_radius: The radius of the shadow. By default, it's 6.
58 @param window_type: A flag of type gtk.WindowType, which indicates the type of the window. By default, it's gtk.WINDOW_TOPLEVEL.
59 @param shadow_visible: If True, the shadow is visible. By default, it's True, just disable when your program not allow manipulate colormap, such as mplayer.
60 """
61
62 gtk.Window.__init__(self, window_type)
63 skin_config.wrap_skin_window(self)
64 self.set_decorated(False)
65 self.set_colormap(gtk.gdk.Screen().get_rgba_colormap())
66 self.add_events(gtk.gdk.ALL_EVENTS_MASK)
67 self.window_shadow = gtk.Alignment()
68 self.window_frame = gtk.VBox()
69 self.shadow_radius = shadow_radius
70 self.frame_radius = 2
71 self.shadow_is_visible = True
72 self.cursor_type = None
73 self.enable_resize = enable_resize
74 self.shadow_visible = shadow_visible
75
76
77 if enable_shadow(self) and self.shadow_visible:
78 self.shadow_padding = self.shadow_radius - self.frame_radius
79 self.window_frame.connect("size-allocate", self.shape_window_frame)
80 self.window_shadow.connect("expose-event", self.expose_window_shadow)
81 else:
82
83 self.shadow_padding = 0
84 self.connect("size-allocate", self.shape_window_frame)
85
86
87 self.window_shadow.set(0.0, 0.0, 1.0, 1.0)
88 self.window_shadow.set_padding(self.shadow_padding, self.shadow_padding, self.shadow_padding, self.shadow_padding)
89
90
91 self.add(self.window_shadow)
92 self.window_shadow.add(self.window_frame)
93
94
95 self.connect_after("expose-event", self.expose_window_background)
96 self.connect_after("size-allocate", lambda w, e: self.queue_draw())
97 self.connect("motion-notify-event", self.motion_notify)
98 self.connect("button-press-event", self.resize_window)
99 self.connect("window-state-event", self.monitor_window_state)
100 self.window_frame.connect("expose-event", self.expose_window_frame)
101
103 """
104 Show the window.
105 """
106 self.show_all()
107
109 """
110 Internal function to expose the window background.
111
112 @param widget: A window of type Gtk.Widget.
113 @param event: The expose event of type gtk.gdk.Event.
114 @return: Always return True.
115 """
116
117 cr = widget.window.cairo_create()
118 rect = widget.allocation
119
120
121 cr.set_source_rgba(0.0, 0.0, 0.0, 0.0)
122 cr.set_operator(cairo.OPERATOR_SOURCE)
123 cr.paint()
124
125
126 if self.shadow_is_visible:
127 x = rect.x + self.shadow_padding
128 y = rect.y + self.shadow_padding
129 w = rect.width - self.shadow_padding * 2
130 h = rect.height - self.shadow_padding * 2
131 else:
132 x, y, w, h = rect.x, rect.y, rect.width, rect.height
133
134
135 with cairo_state(cr):
136 cr.rectangle(x + 2, y, w - 4, 1)
137 cr.rectangle(x + 1, y + 1, w - 2, 1)
138 cr.rectangle(x, y + 2, w, h - 4)
139 cr.rectangle(x + 2, y + h - 1, w - 4, 1)
140 cr.rectangle(x + 1, y + h - 2, w - 2, 1)
141
142 cr.clip()
143
144 skin_config.render_background(cr, self, x, y)
145
146
147 self.draw_mask(cr, x, y, w, h)
148
149
150 with cairo_state(cr):
151 cr.set_source_rgba(*alpha_color_hex_to_cairo(ui_theme.get_alpha_color("window_shadow_corner").get_color_info()))
152
153 cr.rectangle(x, y + 1, 1, 1)
154 cr.rectangle(x + 1, y, 1, 1)
155
156 cr.rectangle(x + w - 1, y + 1, 1, 1)
157 cr.rectangle(x + w - 2, y, 1, 1)
158
159 cr.rectangle(x, y + h - 2, 1, 1)
160 cr.rectangle(x + 1, y + h - 1, 1, 1)
161
162 cr.rectangle(x + w - 1, y + h - 2, 1, 1)
163 cr.rectangle(x + w - 2, y + h - 1, 1, 1)
164
165 cr.fill()
166
167
168 with cairo_state(cr):
169 cr.rectangle(x, y + 1, 1, 1)
170 cr.rectangle(x + 1, y, 1, 1)
171
172 cr.rectangle(x + w - 1, y + 1, 1, 1)
173 cr.rectangle(x + w - 2, y, 1, 1)
174
175 cr.rectangle(x, y + h - 2, 1, 1)
176 cr.rectangle(x + 1, y + h - 1, 1, 1)
177
178 cr.rectangle(x + w - 1, y + h - 2, 1, 1)
179 cr.rectangle(x + w - 2, y + h - 1, 1, 1)
180
181 cr.clip()
182
183 skin_config.render_background(cr, self, x, y)
184
185
186 propagate_expose(widget, event)
187
188 return True
189
191 '''
192 Draw mask interface, you should implement this function own.
193
194 @param cr: Cairo context.
195 @param x: X coordinate of draw area.
196 @param y: Y coordinate of draw area.
197 @param w: Width of draw area.
198 @param h: Height of draw area.
199 '''
200 pass
201
203 """
204 Interh function to expose the window shadow.
205
206 @param widget: the window of gtk.Widget.
207 @param event: The expose event of type gtk.gdk.Event.
208 """
209 if self.shadow_is_visible:
210
211 cr = widget.window.cairo_create()
212 rect = widget.allocation
213 x, y, w, h = rect.x, rect.y, rect.width, rect.height
214
215
216 draw_window_shadow(cr, x, y, w, h, self.shadow_radius, self.shadow_padding, ui_theme.get_shadow_color("window_shadow"))
217
219 """
220 Internal function to expose the window frame.
221
222 @param widget: the window of gtk.Widget.
223 @param event: The expose event of type gtk.gdk.Event.
224 """
225
226 cr = widget.window.cairo_create()
227 rect = widget.allocation
228 x, y, w, h = rect.x, rect.y, rect.width, rect.height
229
230 draw_window_frame(cr, x, y, w, h,
231 ui_theme.get_alpha_color("window_frame_outside_1"),
232 ui_theme.get_alpha_color("window_frame_outside_2"),
233 ui_theme.get_alpha_color("window_frame_outside_3"),
234 ui_theme.get_alpha_color("window_frame_inside_1"),
235 ui_theme.get_alpha_color("window_frame_inside_2"),
236 )
237
239 """
240 Internal function to draw nonrectangular window frame.
241
242 @param widget: A widget of type gtk.Widget.
243 @param rect: The bounding region of the window.
244 """
245 if widget.window != None and widget.get_has_window() and rect.width > 0 and rect.height > 0:
246
247 x, y, w, h = rect.x, rect.y, rect.width, rect.height
248 bitmap = gtk.gdk.Pixmap(None, w, h, 1)
249 cr = bitmap.cairo_create()
250
251
252 cr.set_source_rgb(0.0, 0.0, 0.0)
253 cr.set_operator(cairo.OPERATOR_CLEAR)
254 cr.paint()
255
256
257 cr.set_source_rgb(1.0, 1.0, 1.0)
258 cr.set_operator(cairo.OPERATOR_OVER)
259
260 cr.rectangle(x + 1, y, w - 2, 1)
261 cr.rectangle(x, y + 1, w, h - 2)
262 cr.rectangle(x + 1, y + h - 1, w - 2, 1)
263
264 cr.fill()
265
266
267 widget.shape_combine_mask(bitmap, 0, 0)
268
270 """
271 Hide the window shadow.
272 """
273 self.shadow_is_visible = False
274 self.window_shadow.set_padding(0, 0, 0, 0)
275
277 """
278 Show the window shadow.
279 """
280 self.shadow_is_visible = True
281 self.window_shadow.set_padding(self.shadow_padding, self.shadow_padding, self.shadow_padding, self.shadow_padding)
282
284 """
285 Minimize the window. Make it iconified.
286 """
287 self.iconify()
288
290 """
291 Toggle the window size between maximized size and normal size.
292 """
293 window_state = self.window.get_state()
294 if window_state == gtk.gdk.WINDOW_STATE_MAXIMIZED:
295 self.unmaximize()
296 else:
297 self.maximize()
298
300 """
301 Toggle the window between fullscreen mode and normal size.
302 """
303 window_state = self.window.get_state()
304 if window_state == gtk.gdk.WINDOW_STATE_FULLSCREEN:
305 self.unfullscreen()
306 else:
307 self.fullscreen()
308
310 """
311 Close the window. Send the destroy signal to the program.
312
313 @return: Always return False.
314 """
315
316
317 self.hide_all()
318
319 self.emit("destroy")
320
321 return False
322
324 """
325 Internal callback for `motion-notify` signal.
326
327 @param widget: A widget of gtk.Widget.
328 @param event: The motion-notify-event of type gtk.gdk.Event
329 """
330 if self.enable_resize and self.shadow_is_visible:
331 cursor_type = self.get_cursor_type(event)
332 if cursor_type != None:
333 set_cursor(self, self.cursor_type)
334 elif self.cursor_type != None:
335 set_cursor(self, None)
336
337 self.cursor_type = cursor_type
338
340 """
341 Resize the window.
342
343 @param widget: The window of type gtk.Widget.
344 @param event: A signal of type gtk.gdk.Event.
345 """
346 if self.enable_resize:
347 edge = self.get_edge()
348 if edge != None:
349 resize_window(widget, event, self, edge)
350
352 """
353 An interface which indicates whether the window could be maximized, you should implement this function you own.
354
355 @return: Always return False.
356 """
357 return False
358
360 """
361 Internal function to monitor window state,
362
363 add shadow when window at maximized or fullscreen status. Otherwise hide shadow.
364
365 @param widget: The window of type gtk.Widget.
366 @param event: The event of gtk.gdk.Event.
367 """
368 window_state = self.window.get_state()
369 if window_state in [gtk.gdk.WINDOW_STATE_MAXIMIZED, gtk.gdk.WINDOW_STATE_FULLSCREEN]:
370 self.hide_shadow()
371
372 if self.is_disable_window_maximized():
373 self.unmaximize()
374 else:
375 self.show_shadow()
376
378 """
379 Add move event callback.
380
381 @param widget: A widget of type gtk.Widget.
382 """
383 widget.connect("button-press-event", lambda w, e: move_window(w, e, self))
384
386 """
387 Add toggle event callback.
388
389 @param widget: A widget of type gtk.Widget.
390 """
391 widget.connect("button-press-event", self.double_click_window)
392
394 """
395 Double click event handler of the window. It will maximize the window.
396
397 @param widget: A widget of type gtk.Widget.
398 @param event: A event of type gtk.gdk.Event.
399 @return: Always return False.
400 """
401 if is_double_click(event):
402 self.toggle_max_window()
403
404 return False
405
407 """
408 Get the edge which the cursor is on, according to the cursor type.
409
410 @return: If there is a corresponding cursor type, an instance of gtk.gdk.WindowEdge is returned, else None is returned.
411 """
412 if EDGE_DICT.has_key(self.cursor_type):
413 return EDGE_DICT[self.cursor_type]
414 else:
415 return None
416
418 """
419 Get the cursor position.
420
421 @param event: An event of type gtk.gdk.Event.
422 @return: If the cursor is on the frame of the window, return the cursor position. Otherwise return None.
423 """
424
425 (ex, ey) = get_event_root_coords(event)
426
427
428 rect = self.get_allocation()
429 (wx, wy) = self.get_position()
430 ww = rect.width
431 wh = rect.height
432
433
434 if wx <= ex <= wx + self.shadow_padding:
435 if wy <= ey <= wy + self.shadow_padding * 2:
436 return gtk.gdk.TOP_LEFT_CORNER
437 elif wy + wh - (self.shadow_padding * 2) <= ey <= wy + wh:
438 return gtk.gdk.BOTTOM_LEFT_CORNER
439 elif wy + self.shadow_padding < ey < wy + wh - self.shadow_padding:
440 return gtk.gdk.LEFT_SIDE
441 else:
442 return None
443 elif wx + ww - self.shadow_padding <= ex <= wx + ww:
444 if wy <= ey <= wy + self.shadow_padding * 2:
445 return gtk.gdk.TOP_RIGHT_CORNER
446 elif wy + wh - (self.shadow_padding * 2) <= ey <= wy + wh:
447 return gtk.gdk.BOTTOM_RIGHT_CORNER
448 elif wy + self.shadow_padding < ey < wy + wh - self.shadow_padding:
449 return gtk.gdk.RIGHT_SIDE
450 else:
451 return None
452 elif wx + self.shadow_padding < ex < wx + ww - self.shadow_padding:
453 if wy <= ey <= wy + self.shadow_padding:
454 return gtk.gdk.TOP_SIDE
455 elif wy + wh - self.shadow_padding <= ey <= wy + wh:
456 return gtk.gdk.BOTTOM_SIDE
457 else:
458 return None
459 else:
460 return None
461
463 """
464 Get the shadow size.
465
466 @return: return the shadow size or (0, 0)
467 """
468 if enable_shadow(self) and self.shadow_visible:
469 window_state = self.window.get_state()
470 if window_state in [gtk.gdk.WINDOW_STATE_MAXIMIZED, gtk.gdk.WINDOW_STATE_FULLSCREEN]:
471 return (0, 0)
472 else:
473 return (self.shadow_padding, self.shadow_padding)
474 else:
475 return (0, 0)
476
477 gobject.type_register(Window)
478
479 if __name__ == "__main__":
480 import pseudo_skin
481
482 window = Window()
483 window.connect("destroy", lambda w: gtk.main_quit())
484 window.set_size_request(500, 500)
485
486 window.show_all()
487
488 gtk.main()
489